selftests/bpf: Fix erroneous bitmask operation
[platform/kernel/linux-rpi.git] / tools / testing / selftests / bpf / progs / bind4_prog.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <string.h>
4
5 #include <linux/stddef.h>
6 #include <linux/bpf.h>
7 #include <linux/in.h>
8 #include <linux/in6.h>
9 #include <linux/if.h>
10 #include <errno.h>
11
12 #include <bpf/bpf_helpers.h>
13 #include <bpf/bpf_endian.h>
14
15 #define SERV4_IP                0xc0a801feU /* 192.168.1.254 */
16 #define SERV4_PORT              4040
17 #define SERV4_REWRITE_IP        0x7f000001U /* 127.0.0.1 */
18 #define SERV4_REWRITE_PORT      4444
19
20 #ifndef IFNAMSIZ
21 #define IFNAMSIZ 16
22 #endif
23
24 static __inline int bind_to_device(struct bpf_sock_addr *ctx)
25 {
26         char veth1[IFNAMSIZ] = "test_sock_addr1";
27         char veth2[IFNAMSIZ] = "test_sock_addr2";
28         char missing[IFNAMSIZ] = "nonexistent_dev";
29         char del_bind[IFNAMSIZ] = "";
30         int veth1_idx, veth2_idx;
31
32         if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
33                            &veth1, sizeof(veth1)))
34                 return 1;
35         if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
36                            &veth1_idx, sizeof(veth1_idx)) || !veth1_idx)
37                 return 1;
38         if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
39                            &veth2, sizeof(veth2)))
40                 return 1;
41         if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
42                            &veth2_idx, sizeof(veth2_idx)) || !veth2_idx ||
43             veth1_idx == veth2_idx)
44                 return 1;
45         if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
46                            &missing, sizeof(missing)) != -ENODEV)
47                 return 1;
48         if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
49                            &veth1_idx, sizeof(veth1_idx)))
50                 return 1;
51         if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
52                            &del_bind, sizeof(del_bind)))
53                 return 1;
54
55         return 0;
56 }
57
58 static __inline int bind_reuseport(struct bpf_sock_addr *ctx)
59 {
60         int val = 1;
61
62         if (bpf_setsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
63                            &val, sizeof(val)))
64                 return 1;
65         if (bpf_getsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
66                            &val, sizeof(val)) || !val)
67                 return 1;
68         val = 0;
69         if (bpf_setsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
70                            &val, sizeof(val)))
71                 return 1;
72         if (bpf_getsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
73                            &val, sizeof(val)) || val)
74                 return 1;
75
76         return 0;
77 }
78
79 static __inline int misc_opts(struct bpf_sock_addr *ctx, int opt)
80 {
81         int old, tmp, new = 0xeb9f;
82
83         /* Socket in test case has guarantee that old never equals to new. */
84         if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)) ||
85             old == new)
86                 return 1;
87         if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &new, sizeof(new)))
88                 return 1;
89         if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &tmp, sizeof(tmp)) ||
90             tmp != new)
91                 return 1;
92         if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)))
93                 return 1;
94
95         return 0;
96 }
97
98 SEC("cgroup/bind4")
99 int bind_v4_prog(struct bpf_sock_addr *ctx)
100 {
101         struct bpf_sock *sk;
102         __u32 user_ip4;
103         __u16 user_port;
104
105         sk = ctx->sk;
106         if (!sk)
107                 return 0;
108
109         if (sk->family != AF_INET)
110                 return 0;
111
112         if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
113                 return 0;
114
115         if (ctx->user_ip4 != bpf_htonl(SERV4_IP) ||
116             ctx->user_port != bpf_htons(SERV4_PORT))
117                 return 0;
118
119         // u8 narrow loads:
120         user_ip4 = 0;
121         user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[0] << 0;
122         user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[1] << 8;
123         user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[2] << 16;
124         user_ip4 |= ((volatile __u8 *)&ctx->user_ip4)[3] << 24;
125         if (ctx->user_ip4 != user_ip4)
126                 return 0;
127
128         user_port = 0;
129         user_port |= ((volatile __u8 *)&ctx->user_port)[0] << 0;
130         user_port |= ((volatile __u8 *)&ctx->user_port)[1] << 8;
131         if (ctx->user_port != user_port)
132                 return 0;
133
134         // u16 narrow loads:
135         user_ip4 = 0;
136         user_ip4 |= ((volatile __u16 *)&ctx->user_ip4)[0] << 0;
137         user_ip4 |= ((volatile __u16 *)&ctx->user_ip4)[1] << 16;
138         if (ctx->user_ip4 != user_ip4)
139                 return 0;
140
141         /* Bind to device and unbind it. */
142         if (bind_to_device(ctx))
143                 return 0;
144
145         /* Test for misc socket options. */
146         if (misc_opts(ctx, SO_MARK) || misc_opts(ctx, SO_PRIORITY))
147                 return 0;
148
149         /* Set reuseport and unset */
150         if (bind_reuseport(ctx))
151                 return 0;
152
153         ctx->user_ip4 = bpf_htonl(SERV4_REWRITE_IP);
154         ctx->user_port = bpf_htons(SERV4_REWRITE_PORT);
155
156         return 1;
157 }
158
159 char _license[] SEC("license") = "GPL";