| // SPDX-License-Identifier: GPL-2.0 |
| |
| #include "vmlinux.h" |
| #include "bpf_tracing_net.h" |
| #include <bpf/bpf_helpers.h> |
| #include <bpf/bpf_tracing.h> |
| |
| char _license[] SEC("license") = "GPL"; |
| |
| extern bool CONFIG_SECURITY_SELINUX __kconfig __weak; |
| extern bool CONFIG_SECURITY_SMACK __kconfig __weak; |
| extern bool CONFIG_SECURITY_APPARMOR __kconfig __weak; |
| |
| #ifndef AF_PACKET |
| #define AF_PACKET 17 |
| #endif |
| |
| #ifndef AF_UNIX |
| #define AF_UNIX 1 |
| #endif |
| |
| #ifndef EPERM |
| #define EPERM 1 |
| #endif |
| |
| struct { |
| __uint(type, BPF_MAP_TYPE_CGROUP_STORAGE); |
| __type(key, __u64); |
| __type(value, __u64); |
| } cgroup_storage SEC(".maps"); |
| |
| int called_socket_post_create; |
| int called_socket_post_create2; |
| int called_socket_bind; |
| int called_socket_bind2; |
| int called_socket_alloc; |
| int called_socket_clone; |
| |
| static __always_inline int test_local_storage(void) |
| { |
| __u64 *val; |
| |
| val = bpf_get_local_storage(&cgroup_storage, 0); |
| if (!val) |
| return 0; |
| *val += 1; |
| |
| return 1; |
| } |
| |
| static __always_inline int real_create(struct socket *sock, int family, |
| int protocol) |
| { |
| struct sock *sk; |
| int prio = 123; |
| |
| /* Reject non-tx-only AF_PACKET. */ |
| if (family == AF_PACKET && protocol != 0) |
| return 0; /* EPERM */ |
| |
| sk = sock->sk; |
| if (!sk) |
| return 1; |
| |
| /* The rest of the sockets get default policy. */ |
| if (bpf_setsockopt(sk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio))) |
| return 0; /* EPERM */ |
| |
| /* Make sure bpf_getsockopt is allowed and works. */ |
| prio = 0; |
| if (bpf_getsockopt(sk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio))) |
| return 0; /* EPERM */ |
| if (prio != 123) |
| return 0; /* EPERM */ |
| |
| /* Can access cgroup local storage. */ |
| if (!test_local_storage()) |
| return 0; /* EPERM */ |
| |
| return 1; |
| } |
| |
| /* __cgroup_bpf_run_lsm_socket */ |
| SEC("lsm_cgroup/socket_post_create") |
| int BPF_PROG(socket_post_create, struct socket *sock, int family, |
| int type, int protocol, int kern) |
| { |
| called_socket_post_create++; |
| return real_create(sock, family, protocol); |
| } |
| |
| /* __cgroup_bpf_run_lsm_socket */ |
| SEC("lsm_cgroup/socket_post_create") |
| int BPF_PROG(socket_post_create2, struct socket *sock, int family, |
| int type, int protocol, int kern) |
| { |
| called_socket_post_create2++; |
| return real_create(sock, family, protocol); |
| } |
| |
| static __always_inline int real_bind(struct socket *sock, |
| struct sockaddr *address, |
| int addrlen) |
| { |
| struct sockaddr_ll sa = {}; |
| |
| if (sock->sk->__sk_common.skc_family != AF_PACKET) |
| return 1; |
| |
| if (sock->sk->sk_kern_sock) |
| return 1; |
| |
| bpf_probe_read_kernel(&sa, sizeof(sa), address); |
| if (sa.sll_protocol) |
| return 0; /* EPERM */ |
| |
| /* Can access cgroup local storage. */ |
| if (!test_local_storage()) |
| return 0; /* EPERM */ |
| |
| return 1; |
| } |
| |
| /* __cgroup_bpf_run_lsm_socket */ |
| SEC("lsm_cgroup/socket_bind") |
| int BPF_PROG(socket_bind, struct socket *sock, struct sockaddr *address, |
| int addrlen) |
| { |
| called_socket_bind++; |
| return real_bind(sock, address, addrlen); |
| } |
| |
| /* __cgroup_bpf_run_lsm_socket */ |
| SEC("lsm_cgroup/socket_bind") |
| int BPF_PROG(socket_bind2, struct socket *sock, struct sockaddr *address, |
| int addrlen) |
| { |
| called_socket_bind2++; |
| return real_bind(sock, address, addrlen); |
| } |
| |
| /* __cgroup_bpf_run_lsm_current (via bpf_lsm_current_hooks) */ |
| SEC("lsm_cgroup/sk_alloc_security") |
| int BPF_PROG(socket_alloc, struct sock *sk, int family, gfp_t priority) |
| { |
| called_socket_alloc++; |
| /* if already have non-bpf lsms installed, EPERM will cause memory leak of non-bpf lsms */ |
| if (CONFIG_SECURITY_SELINUX || CONFIG_SECURITY_SMACK || CONFIG_SECURITY_APPARMOR) |
| return 1; |
| |
| if (family == AF_UNIX) |
| return 0; /* EPERM */ |
| |
| /* Can access cgroup local storage. */ |
| if (!test_local_storage()) |
| return 0; /* EPERM */ |
| |
| return 1; |
| } |
| |
| /* __cgroup_bpf_run_lsm_sock */ |
| SEC("lsm_cgroup/inet_csk_clone") |
| int BPF_PROG(socket_clone, struct sock *newsk, const struct request_sock *req) |
| { |
| int prio = 234; |
| |
| if (!newsk) |
| return 1; |
| |
| /* Accepted request sockets get a different priority. */ |
| if (bpf_setsockopt(newsk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio))) |
| return 1; |
| |
| /* Make sure bpf_getsockopt is allowed and works. */ |
| prio = 0; |
| if (bpf_getsockopt(newsk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio))) |
| return 1; |
| if (prio != 234) |
| return 1; |
| |
| /* Can access cgroup local storage. */ |
| if (!test_local_storage()) |
| return 1; |
| |
| called_socket_clone++; |
| |
| return 1; |
| } |