bpf: Add sockptr support for getsockopt
authorBreno Leitao <leitao@debian.org>
Mon, 16 Oct 2023 13:47:39 +0000 (06:47 -0700)
committerJens Axboe <axboe@kernel.dk>
Thu, 19 Oct 2023 20:05:28 +0000 (14:05 -0600)
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>
include/linux/bpf-cgroup.h
kernel/bpf/cgroup.c
net/socket.c

index 8506690dbb9ca401bb8e6c59bb6732c23bb1c4a5..f5b4fb6ed8c67e75510215db88ff12015c416455 100644 (file)
@@ -139,9 +139,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 5b2741aa0d9bb8e01d630ca548eb39ce10553e6a..ebc8c58f7e46589010080d99118074ae1704802f 100644 (file)
@@ -1875,8 +1875,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);
@@ -1903,8 +1903,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;
                }
@@ -1915,8 +1915,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;
                }
@@ -1930,7 +1930,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);
@@ -1942,11 +1943,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 c8b08b32f097ec5dfde66b42701be720ab05c826..82cd6890a4f0b36bd59236108bd92126725b63db 100644 (file)
@@ -2356,8 +2356,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;