]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
bpf: Add sockptr support for getsockopt
authorBreno Leitao <leitao@debian.org>
Mon, 16 Oct 2023 13:47:39 +0000 (06:47 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 12 Sep 2024 09:11:34 +0000 (11:11 +0200)
[ Upstream commit a615f67e1a426f35366b8398c11f31c148e7df48 ]

The whole network stack uses sockptr, and while it doesn't move to
something more modern, let's use sockptr in getsockptr BPF hooks, so, it
could be used by other callers.

The main motivation for this change is to use it in the io_uring
{g,s}etsockopt(), which will use a userspace pointer for *optval, but, a
kernel value for optlen.

Link: https://lore.kernel.org/all/ZSArfLaaGcfd8LH8@gmail.com/
Signed-off-by: Breno Leitao <leitao@debian.org>
Acked-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://lore.kernel.org/r/20231016134750.1381153-2-leitao@debian.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Stable-dep-of: 33f339a1ba54 ("bpf, net: Fix a potential race in do_sock_getsockopt()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/linux/bpf-cgroup.h
kernel/bpf/cgroup.c
net/socket.c

index 31561e7897157850b8bae193ac16d26d70177199..c4956a48ab3e93a0a13b0decd759db6afed9c9f7 100644 (file)
@@ -140,9 +140,10 @@ int __cgroup_bpf_run_filter_sysctl(struct ctl_table_header *head,
 int __cgroup_bpf_run_filter_setsockopt(struct sock *sock, int *level,
                                       int *optname, char __user *optval,
                                       int *optlen, char **kernel_optval);
+
 int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
-                                      int optname, char __user *optval,
-                                      int __user *optlen, int max_optlen,
+                                      int optname, sockptr_t optval,
+                                      sockptr_t optlen, int max_optlen,
                                       int retval);
 
 int __cgroup_bpf_run_filter_getsockopt_kern(struct sock *sk, int level,
index ac37bd53aee031340c601ed4a79ac635824a2a7c..caae07cc885e9c3bfe8aa068734390eebb9f61fc 100644 (file)
@@ -1889,8 +1889,8 @@ out:
 }
 
 int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
-                                      int optname, char __user *optval,
-                                      int __user *optlen, int max_optlen,
+                                      int optname, sockptr_t optval,
+                                      sockptr_t optlen, int max_optlen,
                                       int retval)
 {
        struct cgroup *cgrp = sock_cgroup_ptr(&sk->sk_cgrp_data);
@@ -1917,8 +1917,8 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
                 * one that kernel returned as well to let
                 * BPF programs inspect the value.
                 */
-
-               if (get_user(ctx.optlen, optlen)) {
+               if (copy_from_sockptr(&ctx.optlen, optlen,
+                                     sizeof(ctx.optlen))) {
                        ret = -EFAULT;
                        goto out;
                }
@@ -1929,8 +1929,8 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
                }
                orig_optlen = ctx.optlen;
 
-               if (copy_from_user(ctx.optval, optval,
-                                  min(ctx.optlen, max_optlen)) != 0) {
+               if (copy_from_sockptr(ctx.optval, optval,
+                                     min(ctx.optlen, max_optlen))) {
                        ret = -EFAULT;
                        goto out;
                }
@@ -1944,7 +1944,8 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
        if (ret < 0)
                goto out;
 
-       if (optval && (ctx.optlen > max_optlen || ctx.optlen < 0)) {
+       if (!sockptr_is_null(optval) &&
+           (ctx.optlen > max_optlen || ctx.optlen < 0)) {
                if (orig_optlen > PAGE_SIZE && ctx.optlen >= 0) {
                        pr_info_once("bpf getsockopt: ignoring program buffer with optlen=%d (max_optlen=%d)\n",
                                     ctx.optlen, max_optlen);
@@ -1956,11 +1957,12 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level,
        }
 
        if (ctx.optlen != 0) {
-               if (optval && copy_to_user(optval, ctx.optval, ctx.optlen)) {
+               if (!sockptr_is_null(optval) &&
+                   copy_to_sockptr(optval, ctx.optval, ctx.optlen)) {
                        ret = -EFAULT;
                        goto out;
                }
-               if (put_user(ctx.optlen, optlen)) {
+               if (copy_to_sockptr(optlen, &ctx.optlen, sizeof(ctx.optlen))) {
                        ret = -EFAULT;
                        goto out;
                }
index 8d83c4bb163b42d758c96e2ca91a5a3e62cfc356..b2d75d5661be49d3da1cd791fb1d4326f9ed84fb 100644 (file)
@@ -2375,8 +2375,9 @@ int __sys_getsockopt(int fd, int level, int optname, char __user *optval,
 
        if (!in_compat_syscall())
                err = BPF_CGROUP_RUN_PROG_GETSOCKOPT(sock->sk, level, optname,
-                                                    optval, optlen, max_optlen,
-                                                    err);
+                                                    USER_SOCKPTR(optval),
+                                                    USER_SOCKPTR(optlen),
+                                                    max_optlen, err);
 out_put:
        fput_light(sock->file, fput_needed);
        return err;