• Stanislav Fomichev's avatar
    bpf: implement getsockopt and setsockopt hooks · 0d01da6a
    Stanislav Fomichev authored
    Implement new BPF_PROG_TYPE_CGROUP_SOCKOPT program type and
    BPF_CGROUP_{G,S}ETSOCKOPT cgroup hooks.
    
    BPF_CGROUP_SETSOCKOPT can modify user setsockopt arguments before
    passing them down to the kernel or bypass kernel completely.
    BPF_CGROUP_GETSOCKOPT can can inspect/modify getsockopt arguments that
    kernel returns.
    Both hooks reuse existing PTR_TO_PACKET{,_END} infrastructure.
    
    The buffer memory is pre-allocated (because I don't think there is
    a precedent for working with __user memory from bpf). This might be
    slow to do for each {s,g}etsockopt call, that's why I've added
    __cgroup_bpf_prog_array_is_empty that exits early if there is nothing
    attached to a cgroup. Note, however, that there is a race between
    __cgroup_bpf_prog_array_is_empty and BPF_PROG_RUN_ARRAY where cgroup
    program layout might have changed; this should not be a problem
    because in general there is a race between multiple calls to
    {s,g}etsocktop and user adding/removing bpf progs from a cgroup.
    
    The return code of the BPF program is handled as follows:
    * 0: EPERM
    * 1: success, continue with next BPF program in the cgroup chain
    
    v9:
    * allow overwriting setsockopt arguments (Alexei Starovoitov):
      * use set_fs (same as kernel_setsockopt)
      * buffer is always kzalloc'd (no small on-stack buffer)
    
    v8:
    * use s32 for optlen (Andrii Nakryiko)
    
    v7:
    * return only 0 or 1 (Alexei Starovoitov)
    * always run all progs (Alexei Starovoitov)
    * use optval=0 as kernel bypass in setsockopt (Alexei Starovoitov)
      (decided to use optval=-1 instead, optval=0 might be a valid input)
    * call getsockopt hook after kernel handlers (Alexei Starovoitov)
    
    v6:
    * rework cgroup chaining; stop as soon as bpf program returns
      0 or 2; see patch with the documentation for the details
    * drop Andrii's and Martin's Acked-by (not sure they are comfortable
      with the new state of things)
    
    v5:
    * skip copy_to_user() and put_user() when ret == 0 (Martin Lau)
    
    v4:
    * don't export bpf_sk_fullsock helper (Martin Lau)
    * size != sizeof(__u64) for uapi pointers (Martin Lau)
    * offsetof instead of bpf_ctx_range when checking ctx access (Martin Lau)
    
    v3:
    * typos in BPF_PROG_CGROUP_SOCKOPT_RUN_ARRAY comments (Andrii Nakryiko)
    * reverse christmas tree in BPF_PROG_CGROUP_SOCKOPT_RUN_ARRAY (Andrii
      Nakryiko)
    * use __bpf_md_ptr instead of __u32 for optval{,_end} (Martin Lau)
    * use BPF_FIELD_SIZEOF() for consistency (Martin Lau)
    * new CG_SOCKOPT_ACCESS macro to wrap repeated parts
    
    v2:
    * moved bpf_sockopt_kern fields around to remove a hole (Martin Lau)
    * aligned bpf_sockopt_kern->buf to 8 bytes (Martin Lau)
    * bpf_prog_array_is_empty instead of bpf_prog_array_length (Martin Lau)
    * added [0,2] return code check to verifier (Martin Lau)
    * dropped unused buf[64] from the stack (Martin Lau)
    * use PTR_TO_SOCKET for bpf_sockopt->sk (Martin Lau)
    * dropped bpf_target_off from ctx rewrites (Martin Lau)
    * use return code for kernel bypass (Martin Lau & Andrii Nakryiko)
    
    Cc: Andrii Nakryiko <andriin@fb.com>
    Cc: Martin Lau <kafai@fb.com>
    Signed-off-by: default avatarStanislav Fomichev <sdf@google.com>
    Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
    0d01da6a
socket.c 92.7 KB