@@ -3608,7 +3608,7 @@ static int link_create(union bpf_attr *attr)
static int link_update(union bpf_attr *attr)
{
- struct bpf_prog *old_prog = NULL, *new_prog;
+ struct bpf_prog *old_prog = NULL, *new_prog = NULL;
struct bpf_link *link;
u32 flags;
int ret;
@@ -3628,31 +3628,38 @@ static int link_update(union bpf_attr *attr)
return PTR_ERR(link);
new_prog = bpf_prog_get(attr->link_update.new_prog_fd);
- if (IS_ERR(new_prog))
- return PTR_ERR(new_prog);
+ if (IS_ERR(new_prog)) {
+ ret = PTR_ERR(new_prog);
+ new_prog = NULL;
+ goto out_put;
+ }
if (flags & BPF_F_REPLACE) {
old_prog = bpf_prog_get(attr->link_update.old_prog_fd);
if (IS_ERR(old_prog)) {
ret = PTR_ERR(old_prog);
old_prog = NULL;
- goto out_put_progs;
+ goto out_put;
}
+ } else if (attr->link_update.old_prog_fd) {
+ ret = -EINVAL;
+ goto out_put;
}
#ifdef CONFIG_CGROUP_BPF
if (link->ops == &bpf_cgroup_link_lops) {
ret = cgroup_bpf_replace(link, old_prog, new_prog);
- goto out_put_progs;
+ goto out_put;
}
#endif
ret = -EINVAL;
-out_put_progs:
+out_put:
if (old_prog)
bpf_prog_put(old_prog);
- if (ret)
+ if (ret && new_prog)
bpf_prog_put(new_prog);
+ bpf_link_put(link);
return ret;
}
Fix bug of not putting bpf_link in LINK_UPDATE command. Also enforce zeroed old_prog_fd if no BPF_F_REPLACE flag is specified. Signed-off-by: Andrii Nakryiko <andriin@fb.com> --- kernel/bpf/syscall.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-)