@@ -13,6 +13,7 @@ static int getsetsockopt(void)
char cc[16]; /* TCP_CA_NAME_MAX */
} buf = {};
socklen_t optlen;
+ char *big_buf;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
@@ -78,6 +79,31 @@ static int getsetsockopt(void)
goto err;
}
+ /* IP_FREEBIND - BPF can't access optval when optlen > PAGE_SIZE */
+
+ optlen = getpagesize() * 2;
+ big_buf = calloc(1, optlen);
+ if (!big_buf) {
+ log_err("Couldn't allocate two pages");
+ goto err;
+ }
+
+ err = setsockopt(fd, SOL_IP, IP_FREEBIND, big_buf, optlen);
+ if (err != 0) {
+ log_err("Failed to call setsockopt, ret=%d", err);
+ free(big_buf);
+ goto err;
+ }
+
+ err = getsockopt(fd, SOL_IP, IP_FREEBIND, big_buf, &optlen);
+ if (err != 0) {
+ log_err("Failed to call getsockopt, ret=%d", err);
+ free(big_buf);
+ goto err;
+ }
+
+ free(big_buf);
+
/* SO_SNDBUF is overwritten */
buf.u32 = 0x01010101;
@@ -51,6 +51,16 @@ int _getsockopt(struct bpf_sockopt *ctx)
return 1;
}
+ if (ctx->level == SOL_IP && ctx->optname == IP_FREEBIND) {
+ if (optval > optval_end) {
+ /* For optval > PAGE_SIZE, the actual data
+ * is not provided.
+ */
+ return 0; /* EPERM, unexpected data size */
+ }
+ return 1;
+ }
+
if (ctx->level != SOL_CUSTOM)
return 0; /* EPERM, deny everything except custom level */
@@ -112,6 +122,16 @@ int _setsockopt(struct bpf_sockopt *ctx)
return 1;
}
+ if (ctx->level == SOL_IP && ctx->optname == IP_FREEBIND) {
+ if (optval > optval_end) {
+ /* For optval > PAGE_SIZE, the actual data
+ * is not provided.
+ */
+ return 0; /* EPERM, unexpected data size */
+ }
+ return 1;
+ }
+
if (ctx->level != SOL_CUSTOM)
return 0; /* EPERM, deny everything except custom level */
We are relying on the fact, that we can pass > sizeof(int) optvals to the SOL_IP+IP_FREEBIND option (the kernel will take first 4 bytes). In the BPF program, we return EPERM if optval is greater than optval_end (implemented via PTR_TO_PACKET/PTR_TO_PACKET_END) and rely on the verifier to enforce the fact that this data can not be touched. Signed-off-by: Stanislav Fomichev <sdf@google.com> --- .../selftests/bpf/prog_tests/sockopt_sk.c | 26 +++++++++++++++++++ .../testing/selftests/bpf/progs/sockopt_sk.c | 20 ++++++++++++++ 2 files changed, 46 insertions(+)