Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpf_{s,g}etsockopt from cgroup bind{4,6} hooks #5

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions include/linux/bpf-cgroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,11 @@ int bpf_percpu_cgroup_storage_update(struct bpf_map *map, void *key,
__ret; \
})

#define BPF_CGROUP_RUN_PROG_INET4_BIND(sk, uaddr) \
BPF_CGROUP_RUN_SA_PROG(sk, uaddr, BPF_CGROUP_INET4_BIND)
#define BPF_CGROUP_RUN_PROG_INET4_BIND_LOCK(sk, uaddr) \
BPF_CGROUP_RUN_SA_PROG_LOCK(sk, uaddr, BPF_CGROUP_INET4_BIND, NULL)

#define BPF_CGROUP_RUN_PROG_INET6_BIND(sk, uaddr) \
BPF_CGROUP_RUN_SA_PROG(sk, uaddr, BPF_CGROUP_INET6_BIND)
#define BPF_CGROUP_RUN_PROG_INET6_BIND_LOCK(sk, uaddr) \
BPF_CGROUP_RUN_SA_PROG_LOCK(sk, uaddr, BPF_CGROUP_INET6_BIND, NULL)

#define BPF_CGROUP_PRE_CONNECT_ENABLED(sk) (cgroup_bpf_enabled && \
sk->sk_prot->pre_connect)
Expand Down Expand Up @@ -434,8 +434,8 @@ static inline int bpf_percpu_cgroup_storage_update(struct bpf_map *map,
#define BPF_CGROUP_RUN_PROG_INET_EGRESS(sk,skb) ({ 0; })
#define BPF_CGROUP_RUN_PROG_INET_SOCK(sk) ({ 0; })
#define BPF_CGROUP_RUN_PROG_INET_SOCK_RELEASE(sk) ({ 0; })
#define BPF_CGROUP_RUN_PROG_INET4_BIND(sk, uaddr) ({ 0; })
#define BPF_CGROUP_RUN_PROG_INET6_BIND(sk, uaddr) ({ 0; })
#define BPF_CGROUP_RUN_PROG_INET4_BIND_LOCK(sk, uaddr) ({ 0; })
#define BPF_CGROUP_RUN_PROG_INET6_BIND_LOCK(sk, uaddr) ({ 0; })
#define BPF_CGROUP_RUN_PROG_INET4_POST_BIND(sk) ({ 0; })
#define BPF_CGROUP_RUN_PROG_INET6_POST_BIND(sk) ({ 0; })
#define BPF_CGROUP_RUN_PROG_INET4_CONNECT(sk, uaddr) ({ 0; })
Expand Down
4 changes: 4 additions & 0 deletions net/core/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -6995,6 +6995,8 @@ sock_addr_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
return &bpf_sk_storage_delete_proto;
case BPF_FUNC_setsockopt:
switch (prog->expected_attach_type) {
case BPF_CGROUP_INET4_BIND:
case BPF_CGROUP_INET6_BIND:
case BPF_CGROUP_INET4_CONNECT:
case BPF_CGROUP_INET6_CONNECT:
return &bpf_sock_addr_setsockopt_proto;
Expand All @@ -7003,6 +7005,8 @@ sock_addr_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
}
case BPF_FUNC_getsockopt:
switch (prog->expected_attach_type) {
case BPF_CGROUP_INET4_BIND:
case BPF_CGROUP_INET6_BIND:
case BPF_CGROUP_INET4_CONNECT:
case BPF_CGROUP_INET6_CONNECT:
return &bpf_sock_addr_getsockopt_proto;
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/af_inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/* BPF prog is run before any checks are done so that if the prog
* changes context in a wrong way it will be caught.
*/
err = BPF_CGROUP_RUN_PROG_INET4_BIND(sk, uaddr);
err = BPF_CGROUP_RUN_PROG_INET4_BIND_LOCK(sk, uaddr);
if (err)
return err;

Expand Down
2 changes: 1 addition & 1 deletion net/ipv6/af_inet6.c
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/* BPF prog is run before any checks are done so that if the prog
* changes context in a wrong way it will be caught.
*/
err = BPF_CGROUP_RUN_PROG_INET6_BIND(sk, uaddr);
err = BPF_CGROUP_RUN_PROG_INET6_BIND_LOCK(sk, uaddr);
if (err)
return err;

Expand Down
102 changes: 102 additions & 0 deletions tools/testing/selftests/bpf/progs/bind4_prog.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: GPL-2.0

#include <string.h>

#include <linux/stddef.h>
#include <linux/bpf.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <linux/if.h>
#include <errno.h>

#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>

#define SERV4_IP 0xc0a801feU /* 192.168.1.254 */
#define SERV4_PORT 4040
#define SERV4_REWRITE_IP 0x7f000001U /* 127.0.0.1 */
#define SERV4_REWRITE_PORT 4444

#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif

static __inline int bind_to_device(struct bpf_sock_addr *ctx)
{
char veth1[IFNAMSIZ] = "test_sock_addr1";
char veth2[IFNAMSIZ] = "test_sock_addr2";
char missing[IFNAMSIZ] = "nonexistent_dev";
char del_bind[IFNAMSIZ] = "";

if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
&veth1, sizeof(veth1)))
return 1;
if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
&veth2, sizeof(veth2)))
return 1;
if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
&missing, sizeof(missing)) != -ENODEV)
return 1;
if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
&del_bind, sizeof(del_bind)))
return 1;

return 0;
}

SEC("cgroup/bind4")
int bind_v4_prog(struct bpf_sock_addr *ctx)
{
struct bpf_sock *sk;
__u32 user_ip4;
__u16 user_port;

sk = ctx->sk;
if (!sk)
return 0;

if (sk->family != AF_INET)
return 0;

if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
return 0;

if (ctx->user_ip4 != bpf_htonl(SERV4_IP) ||
ctx->user_port != bpf_htons(SERV4_PORT))
return 0;

// u8 narrow loads:
user_ip4 = 0;
user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[0] << 0;
user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[1] << 8;
user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[2] << 16;
user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[3] << 24;
if (ctx->user_ip4 != user_ip4)
return 0;

user_port = 0;
user_port |= ((volatile __u8 *)&ctx->user_port)[0] << 0;
user_port |= ((volatile __u8 *)&ctx->user_port)[1] << 8;
if (ctx->user_port != user_port)
return 0;

// u16 narrow loads:
user_ip4 = 0;
user_ip4 |= ((volatile __u16 *)&ctx->user_ip4)[0] << 0;
user_ip4 |= ((volatile __u16 *)&ctx->user_ip4)[1] << 16;
if (ctx->user_ip4 != user_ip4)
return 0;

/* Bind to device and unbind it. */
if (bind_to_device(ctx))
return 0;

ctx->user_ip4 = bpf_htonl(SERV4_REWRITE_IP);
ctx->user_port = bpf_htons(SERV4_REWRITE_PORT);

return 1;
}

char _license[] SEC("license") = "GPL";
119 changes: 119 additions & 0 deletions tools/testing/selftests/bpf/progs/bind6_prog.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// SPDX-License-Identifier: GPL-2.0

#include <string.h>

#include <linux/stddef.h>
#include <linux/bpf.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <linux/if.h>
#include <errno.h>

#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>

#define SERV6_IP_0 0xfaceb00c /* face:b00c:1234:5678::abcd */
#define SERV6_IP_1 0x12345678
#define SERV6_IP_2 0x00000000
#define SERV6_IP_3 0x0000abcd
#define SERV6_PORT 6060
#define SERV6_REWRITE_IP_0 0x00000000
#define SERV6_REWRITE_IP_1 0x00000000
#define SERV6_REWRITE_IP_2 0x00000000
#define SERV6_REWRITE_IP_3 0x00000001
#define SERV6_REWRITE_PORT 6666

#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif

static __inline int bind_to_device(struct bpf_sock_addr *ctx)
{
char veth1[IFNAMSIZ] = "test_sock_addr1";
char veth2[IFNAMSIZ] = "test_sock_addr2";
char missing[IFNAMSIZ] = "nonexistent_dev";
char del_bind[IFNAMSIZ] = "";

if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
&veth1, sizeof(veth1)))
return 1;
if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
&veth2, sizeof(veth2)))
return 1;
if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
&missing, sizeof(missing)) != -ENODEV)
return 1;
if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
&del_bind, sizeof(del_bind)))
return 1;

return 0;
}

SEC("cgroup/bind6")
int bind_v6_prog(struct bpf_sock_addr *ctx)
{
struct bpf_sock *sk;
__u32 user_ip6;
__u16 user_port;
int i;

sk = ctx->sk;
if (!sk)
return 0;

if (sk->family != AF_INET6)
return 0;

if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
return 0;

if (ctx->user_ip6[0] != bpf_htonl(SERV6_IP_0) ||
ctx->user_ip6[1] != bpf_htonl(SERV6_IP_1) ||
ctx->user_ip6[2] != bpf_htonl(SERV6_IP_2) ||
ctx->user_ip6[3] != bpf_htonl(SERV6_IP_3) ||
ctx->user_port != bpf_htons(SERV6_PORT))
return 0;

// u8 narrow loads:
for (i = 0; i < 4; i++) {
user_ip6 = 0;
user_ip6 |= ((volatile __u8 *)&ctx->user_ip6[i])[0] << 0;
user_ip6 |= ((volatile __u8 *)&ctx->user_ip6[i])[1] << 8;
user_ip6 |= ((volatile __u8 *)&ctx->user_ip6[i])[2] << 16;
user_ip6 |= ((volatile __u8 *)&ctx->user_ip6[i])[3] << 24;
if (ctx->user_ip6[i] != user_ip6)
return 0;
}

user_port = 0;
user_port |= ((volatile __u8 *)&ctx->user_port)[0] << 0;
user_port |= ((volatile __u8 *)&ctx->user_port)[1] << 8;
if (ctx->user_port != user_port)
return 0;

// u16 narrow loads:
for (i = 0; i < 4; i++) {
user_ip6 = 0;
user_ip6 |= ((volatile __u16 *)&ctx->user_ip6[i])[0] << 0;
user_ip6 |= ((volatile __u16 *)&ctx->user_ip6[i])[1] << 16;
if (ctx->user_ip6[i] != user_ip6)
return 0;
}

/* Bind to device and unbind it. */
if (bind_to_device(ctx))
return 0;

ctx->user_ip6[0] = bpf_htonl(SERV6_REWRITE_IP_0);
ctx->user_ip6[1] = bpf_htonl(SERV6_REWRITE_IP_1);
ctx->user_ip6[2] = bpf_htonl(SERV6_REWRITE_IP_2);
ctx->user_ip6[3] = bpf_htonl(SERV6_REWRITE_IP_3);
ctx->user_port = bpf_htons(SERV6_REWRITE_PORT);

return 1;
}

char _license[] SEC("license") = "GPL";
Loading