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@xxxxxx> --- kernel/bpf/syscall.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index d85f37239540..087cf27218c9 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -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; } -- 2.24.1