lkml.org 
[lkml]   [2023]   [Aug]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 5/8] bpf: Leverage sockptr_t in BPF getsockopt hook
    Date
    Leverage sockptr_t structure to have an argument that is either an
    userspace pointer, or, a kernel pointer.

    This makes this function flexible, so, we can mix and match user and
    kernel space pointers. 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.

    Signed-off-by: Breno Leitao <leitao@debian.org>
    ---
    include/linux/bpf-cgroup.h | 5 +++--
    kernel/bpf/cgroup.c | 20 +++++++++++---------
    net/socket.c | 5 +++--
    3 files changed, 17 insertions(+), 13 deletions(-)

    diff --git a/include/linux/bpf-cgroup.h b/include/linux/bpf-cgroup.h
    index 57e9e109257e..d16cb99fd4f1 100644
    --- a/include/linux/bpf-cgroup.h
    +++ b/include/linux/bpf-cgroup.h
    @@ -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,
    diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
    index 5b2741aa0d9b..ebc8c58f7e46 100644
    --- a/kernel/bpf/cgroup.c
    +++ b/kernel/bpf/cgroup.c
    @@ -1875,8 +1875,8 @@ int __cgroup_bpf_run_filter_setsockopt(struct sock *sk, int *level,
    }

    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;
    }
    diff --git a/net/socket.c b/net/socket.c
    index 8df54352af83..c686c6e89441 100644
    --- a/net/socket.c
    +++ b/net/socket.c
    @@ -2306,8 +2306,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;
    --
    2.34.1
    \
     
     \ /
      Last update: 2023-08-08 21:16    [W:4.777 / U:0.040 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site