Commit b0072308 authored by Tze-nan Wu's avatar Tze-nan Wu Committed by Pu Lehui
Browse files

bpf, net: Fix a potential race in do_sock_getsockopt()

mainline inclusion
from mainline-v6.11-rc7
commit 33f339a1ba54e56bba57ee9a77c71e385ab4825c
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IB2EW4

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=33f339a1ba54



--------------------------------

There's a potential race when `cgroup_bpf_enabled(CGROUP_GETSOCKOPT)` is
false during the execution of `BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN`, but
becomes true when `BPF_CGROUP_RUN_PROG_GETSOCKOPT` is called.
This inconsistency can lead to `BPF_CGROUP_RUN_PROG_GETSOCKOPT` receiving
an "-EFAULT" from `__cgroup_bpf_run_filter_getsockopt(max_optlen=0)`.
Scenario shown as below:

           `process A`                      `process B`
           -----------                      ------------
  BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN
                                            enable CGROUP_GETSOCKOPT
  BPF_CGROUP_RUN_PROG_GETSOCKOPT (-EFAULT)

To resolve this, remove the `BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN` macro and
directly uses `copy_from_sockptr` to ensure that `max_optlen` is always
set before `BPF_CGROUP_RUN_PROG_GETSOCKOPT` is invoked.

Fixes: 0d01da6a ("bpf: implement getsockopt and setsockopt hooks")
Co-developed-by: default avatarYanghui Li <yanghui.li@mediatek.com>
Signed-off-by: default avatarYanghui Li <yanghui.li@mediatek.com>
Co-developed-by: default avatarCheng-Jui Wang <cheng-jui.wang@mediatek.com>
Signed-off-by: default avatarCheng-Jui Wang <cheng-jui.wang@mediatek.com>
Signed-off-by: default avatarTze-nan Wu <Tze-nan.Wu@mediatek.com>
Acked-by: default avatarStanislav Fomichev <sdf@fomichev.me>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20240830082518.23243-1-Tze-nan.Wu@mediatek.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Conflicts:
	include/linux/bpf-cgroup.h
	net/socket.c
[The conflicts were due to not merge commit 0b05b0cd78c9]
Signed-off-by: default avatarPu Lehui <pulehui@huawei.com>
parent 9f376291
Loading
Loading
Loading
Loading
+0 −9
Original line number Diff line number Diff line
@@ -434,14 +434,6 @@ int bpf_percpu_cgroup_storage_update(struct bpf_map *map, void *key,
	__ret;								       \
})

#define BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN(optlen)			       \
({									       \
	int __ret = 0;							       \
	if (cgroup_bpf_enabled(CGROUP_GETSOCKOPT))			       \
		get_user(__ret, optlen);				       \
	__ret;								       \
})

#define BPF_CGROUP_RUN_PROG_GETSOCKOPT(sock, level, optname, optval, optlen,   \
				       max_optlen, retval)		       \
({									       \
@@ -530,7 +522,6 @@ static inline int bpf_percpu_cgroup_storage_update(struct bpf_map *map,
#define BPF_CGROUP_RUN_PROG_SOCK_OPS(sock_ops) ({ 0; })
#define BPF_CGROUP_RUN_PROG_DEVICE_CGROUP(atype, major, minor, access) ({ 0; })
#define BPF_CGROUP_RUN_PROG_SYSCTL(head,table,write,buf,count,pos) ({ 0; })
#define BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN(optlen) ({ 0; })
#define BPF_CGROUP_RUN_PROG_GETSOCKOPT(sock, level, optname, optval, \
				       optlen, max_optlen, retval) ({ retval; })
#define BPF_CGROUP_RUN_PROG_SETSOCKOPT(sock, level, optname, optval, optlen, \
+2 −2
Original line number Diff line number Diff line
@@ -2178,7 +2178,7 @@ int __sys_getsockopt(int fd, int level, int optname, char __user *optval,
{
	int err, fput_needed;
	struct socket *sock;
	int max_optlen;
	int max_optlen = 0;

	sock = sockfd_lookup_light(fd, &err, &fput_needed);
	if (!sock)
@@ -2189,7 +2189,7 @@ int __sys_getsockopt(int fd, int level, int optname, char __user *optval,
		goto out_put;

	if (!in_compat_syscall())
		max_optlen = BPF_CGROUP_GETSOCKOPT_MAX_OPTLEN(optlen);
		get_user(max_optlen, optlen);

	if (level == SOL_SOCKET)
		err = sock_getsockopt(sock, level, optname, optval, optlen);