Commit e01b4a72 authored by Stanislav Fomichev's avatar Stanislav Fomichev Committed by Martin KaFai Lau

selftests/bpf: Correctly handle optlen > 4096

Even though it's not relevant in selftests, the people
might still copy-paste from them. So let's take care
of optlen > 4096 cases explicitly.
Signed-off-by: default avatarStanislav Fomichev <sdf@google.com>
Link: https://lore.kernel.org/r/20230511170456.1759459-4-sdf@google.comSigned-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
parent 989a4a7d
...@@ -25,6 +25,8 @@ static void test_setsockopt_set(int cgroup_fd, int sock_fd) ...@@ -25,6 +25,8 @@ static void test_setsockopt_set(int cgroup_fd, int sock_fd)
if (!ASSERT_OK_PTR(obj, "skel-load")) if (!ASSERT_OK_PTR(obj, "skel-load"))
return; return;
obj->bss->page_size = sysconf(_SC_PAGESIZE);
/* Attach setsockopt that sets EUNATCH, assert that /* Attach setsockopt that sets EUNATCH, assert that
* we actually get that error when we run setsockopt() * we actually get that error when we run setsockopt()
*/ */
...@@ -59,6 +61,8 @@ static void test_setsockopt_set_and_get(int cgroup_fd, int sock_fd) ...@@ -59,6 +61,8 @@ static void test_setsockopt_set_and_get(int cgroup_fd, int sock_fd)
if (!ASSERT_OK_PTR(obj, "skel-load")) if (!ASSERT_OK_PTR(obj, "skel-load"))
return; return;
obj->bss->page_size = sysconf(_SC_PAGESIZE);
/* Attach setsockopt that sets EUNATCH, and one that gets the /* Attach setsockopt that sets EUNATCH, and one that gets the
* previously set errno. Assert that we get the same errno back. * previously set errno. Assert that we get the same errno back.
*/ */
...@@ -100,6 +104,8 @@ static void test_setsockopt_default_zero(int cgroup_fd, int sock_fd) ...@@ -100,6 +104,8 @@ static void test_setsockopt_default_zero(int cgroup_fd, int sock_fd)
if (!ASSERT_OK_PTR(obj, "skel-load")) if (!ASSERT_OK_PTR(obj, "skel-load"))
return; return;
obj->bss->page_size = sysconf(_SC_PAGESIZE);
/* Attach setsockopt that gets the previously set errno. /* Attach setsockopt that gets the previously set errno.
* Assert that, without anything setting one, we get 0. * Assert that, without anything setting one, we get 0.
*/ */
...@@ -134,6 +140,8 @@ static void test_setsockopt_default_zero_and_set(int cgroup_fd, int sock_fd) ...@@ -134,6 +140,8 @@ static void test_setsockopt_default_zero_and_set(int cgroup_fd, int sock_fd)
if (!ASSERT_OK_PTR(obj, "skel-load")) if (!ASSERT_OK_PTR(obj, "skel-load"))
return; return;
obj->bss->page_size = sysconf(_SC_PAGESIZE);
/* Attach setsockopt that gets the previously set errno, and then /* Attach setsockopt that gets the previously set errno, and then
* one that sets the errno to EUNATCH. Assert that the get does not * one that sets the errno to EUNATCH. Assert that the get does not
* see EUNATCH set later, and does not prevent EUNATCH from being set. * see EUNATCH set later, and does not prevent EUNATCH from being set.
...@@ -177,6 +185,8 @@ static void test_setsockopt_override(int cgroup_fd, int sock_fd) ...@@ -177,6 +185,8 @@ static void test_setsockopt_override(int cgroup_fd, int sock_fd)
if (!ASSERT_OK_PTR(obj, "skel-load")) if (!ASSERT_OK_PTR(obj, "skel-load"))
return; return;
obj->bss->page_size = sysconf(_SC_PAGESIZE);
/* Attach setsockopt that sets EUNATCH, then one that sets EISCONN, /* Attach setsockopt that sets EUNATCH, then one that sets EISCONN,
* and then one that gets the exported errno. Assert both the syscall * and then one that gets the exported errno. Assert both the syscall
* and the helper sees the last set errno. * and the helper sees the last set errno.
...@@ -224,6 +234,8 @@ static void test_setsockopt_legacy_eperm(int cgroup_fd, int sock_fd) ...@@ -224,6 +234,8 @@ static void test_setsockopt_legacy_eperm(int cgroup_fd, int sock_fd)
if (!ASSERT_OK_PTR(obj, "skel-load")) if (!ASSERT_OK_PTR(obj, "skel-load"))
return; return;
obj->bss->page_size = sysconf(_SC_PAGESIZE);
/* Attach setsockopt that return a reject without setting errno /* Attach setsockopt that return a reject without setting errno
* (legacy reject), and one that gets the errno. Assert that for * (legacy reject), and one that gets the errno. Assert that for
* backward compatibility the syscall result in EPERM, and this * backward compatibility the syscall result in EPERM, and this
...@@ -268,6 +280,8 @@ static void test_setsockopt_legacy_no_override(int cgroup_fd, int sock_fd) ...@@ -268,6 +280,8 @@ static void test_setsockopt_legacy_no_override(int cgroup_fd, int sock_fd)
if (!ASSERT_OK_PTR(obj, "skel-load")) if (!ASSERT_OK_PTR(obj, "skel-load"))
return; return;
obj->bss->page_size = sysconf(_SC_PAGESIZE);
/* Attach setsockopt that sets EUNATCH, then one that return a reject /* Attach setsockopt that sets EUNATCH, then one that return a reject
* without setting errno, and then one that gets the exported errno. * without setting errno, and then one that gets the exported errno.
* Assert both the syscall and the helper's errno are unaffected by * Assert both the syscall and the helper's errno are unaffected by
...@@ -319,6 +333,8 @@ static void test_getsockopt_get(int cgroup_fd, int sock_fd) ...@@ -319,6 +333,8 @@ static void test_getsockopt_get(int cgroup_fd, int sock_fd)
if (!ASSERT_OK_PTR(obj, "skel-load")) if (!ASSERT_OK_PTR(obj, "skel-load"))
return; return;
obj->bss->page_size = sysconf(_SC_PAGESIZE);
/* Attach getsockopt that gets previously set errno. Assert that the /* Attach getsockopt that gets previously set errno. Assert that the
* error from kernel is in both ctx_retval_value and retval_value. * error from kernel is in both ctx_retval_value and retval_value.
*/ */
...@@ -359,6 +375,8 @@ static void test_getsockopt_override(int cgroup_fd, int sock_fd) ...@@ -359,6 +375,8 @@ static void test_getsockopt_override(int cgroup_fd, int sock_fd)
if (!ASSERT_OK_PTR(obj, "skel-load")) if (!ASSERT_OK_PTR(obj, "skel-load"))
return; return;
obj->bss->page_size = sysconf(_SC_PAGESIZE);
/* Attach getsockopt that sets retval to -EISCONN. Assert that this /* Attach getsockopt that sets retval to -EISCONN. Assert that this
* overrides the value from kernel. * overrides the value from kernel.
*/ */
...@@ -396,6 +414,8 @@ static void test_getsockopt_retval_sync(int cgroup_fd, int sock_fd) ...@@ -396,6 +414,8 @@ static void test_getsockopt_retval_sync(int cgroup_fd, int sock_fd)
if (!ASSERT_OK_PTR(obj, "skel-load")) if (!ASSERT_OK_PTR(obj, "skel-load"))
return; return;
obj->bss->page_size = sysconf(_SC_PAGESIZE);
/* Attach getsockopt that sets retval to -EISCONN, and one that clears /* Attach getsockopt that sets retval to -EISCONN, and one that clears
* ctx retval. Assert that the clearing ctx retval is synced to helper * ctx retval. Assert that the clearing ctx retval is synced to helper
* and clears any errors both from kernel and BPF.. * and clears any errors both from kernel and BPF..
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#include <test_progs.h> #include <test_progs.h>
#include "cgroup_helpers.h" #include "cgroup_helpers.h"
#include "sockopt_inherit.skel.h"
#define SOL_CUSTOM 0xdeadbeef #define SOL_CUSTOM 0xdeadbeef
#define CUSTOM_INHERIT1 0 #define CUSTOM_INHERIT1 0
#define CUSTOM_INHERIT2 1 #define CUSTOM_INHERIT2 1
...@@ -132,58 +134,30 @@ static int start_server(void) ...@@ -132,58 +134,30 @@ static int start_server(void)
return fd; return fd;
} }
static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title,
const char *prog_name)
{
enum bpf_attach_type attach_type;
enum bpf_prog_type prog_type;
struct bpf_program *prog;
int err;
err = libbpf_prog_type_by_name(title, &prog_type, &attach_type);
if (err) {
log_err("Failed to deduct types for %s BPF program", prog_name);
return -1;
}
prog = bpf_object__find_program_by_name(obj, prog_name);
if (!prog) {
log_err("Failed to find %s BPF program", prog_name);
return -1;
}
err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd,
attach_type, 0);
if (err) {
log_err("Failed to attach %s BPF program", prog_name);
return -1;
}
return 0;
}
static void run_test(int cgroup_fd) static void run_test(int cgroup_fd)
{ {
struct bpf_link *link_getsockopt = NULL;
struct bpf_link *link_setsockopt = NULL;
int server_fd = -1, client_fd; int server_fd = -1, client_fd;
struct bpf_object *obj; struct sockopt_inherit *obj;
void *server_err; void *server_err;
pthread_t tid; pthread_t tid;
int err; int err;
obj = bpf_object__open_file("sockopt_inherit.bpf.o", NULL); obj = sockopt_inherit__open_and_load();
if (!ASSERT_OK_PTR(obj, "obj_open")) if (!ASSERT_OK_PTR(obj, "skel-load"))
return; return;
err = bpf_object__load(obj); obj->bss->page_size = sysconf(_SC_PAGESIZE);
if (!ASSERT_OK(err, "obj_load"))
goto close_bpf_object;
err = prog_attach(obj, cgroup_fd, "cgroup/getsockopt", "_getsockopt"); link_getsockopt = bpf_program__attach_cgroup(obj->progs._getsockopt,
if (!ASSERT_OK(err, "prog_attach _getsockopt")) cgroup_fd);
if (!ASSERT_OK_PTR(link_getsockopt, "cg-attach-getsockopt"))
goto close_bpf_object; goto close_bpf_object;
err = prog_attach(obj, cgroup_fd, "cgroup/setsockopt", "_setsockopt"); link_setsockopt = bpf_program__attach_cgroup(obj->progs._setsockopt,
if (!ASSERT_OK(err, "prog_attach _setsockopt")) cgroup_fd);
if (!ASSERT_OK_PTR(link_setsockopt, "cg-attach-setsockopt"))
goto close_bpf_object; goto close_bpf_object;
server_fd = start_server(); server_fd = start_server();
...@@ -217,7 +191,10 @@ static void run_test(int cgroup_fd) ...@@ -217,7 +191,10 @@ static void run_test(int cgroup_fd)
close_server_fd: close_server_fd:
close(server_fd); close(server_fd);
close_bpf_object: close_bpf_object:
bpf_object__close(obj); bpf_link__destroy(link_getsockopt);
bpf_link__destroy(link_setsockopt);
sockopt_inherit__destroy(obj);
} }
void test_sockopt_inherit(void) void test_sockopt_inherit(void)
......
...@@ -2,61 +2,13 @@ ...@@ -2,61 +2,13 @@
#include <test_progs.h> #include <test_progs.h>
#include "cgroup_helpers.h" #include "cgroup_helpers.h"
static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title, const char *name) #include "sockopt_multi.skel.h"
{
enum bpf_attach_type attach_type;
enum bpf_prog_type prog_type;
struct bpf_program *prog;
int err;
err = libbpf_prog_type_by_name(title, &prog_type, &attach_type);
if (err) {
log_err("Failed to deduct types for %s BPF program", title);
return -1;
}
prog = bpf_object__find_program_by_name(obj, name);
if (!prog) {
log_err("Failed to find %s BPF program", name);
return -1;
}
err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd,
attach_type, BPF_F_ALLOW_MULTI);
if (err) {
log_err("Failed to attach %s BPF program", name);
return -1;
}
return 0;
}
static int prog_detach(struct bpf_object *obj, int cgroup_fd, const char *title, const char *name) static int run_getsockopt_test(struct sockopt_multi *obj, int cg_parent,
{
enum bpf_attach_type attach_type;
enum bpf_prog_type prog_type;
struct bpf_program *prog;
int err;
err = libbpf_prog_type_by_name(title, &prog_type, &attach_type);
if (err)
return -1;
prog = bpf_object__find_program_by_name(obj, name);
if (!prog)
return -1;
err = bpf_prog_detach2(bpf_program__fd(prog), cgroup_fd,
attach_type);
if (err)
return -1;
return 0;
}
static int run_getsockopt_test(struct bpf_object *obj, int cg_parent,
int cg_child, int sock_fd) int cg_child, int sock_fd)
{ {
struct bpf_link *link_parent = NULL;
struct bpf_link *link_child = NULL;
socklen_t optlen; socklen_t optlen;
__u8 buf; __u8 buf;
int err; int err;
...@@ -89,8 +41,9 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, ...@@ -89,8 +41,9 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent,
* - child: 0x80 -> 0x90 * - child: 0x80 -> 0x90
*/ */
err = prog_attach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child"); link_child = bpf_program__attach_cgroup(obj->progs._getsockopt_child,
if (err) cg_child);
if (!ASSERT_OK_PTR(link_child, "cg-attach-getsockopt_child"))
goto detach; goto detach;
buf = 0x00; buf = 0x00;
...@@ -113,8 +66,9 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, ...@@ -113,8 +66,9 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent,
* - parent: 0x90 -> 0xA0 * - parent: 0x90 -> 0xA0
*/ */
err = prog_attach(obj, cg_parent, "cgroup/getsockopt", "_getsockopt_parent"); link_parent = bpf_program__attach_cgroup(obj->progs._getsockopt_parent,
if (err) cg_parent);
if (!ASSERT_OK_PTR(link_parent, "cg-attach-getsockopt_parent"))
goto detach; goto detach;
buf = 0x00; buf = 0x00;
...@@ -157,11 +111,8 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, ...@@ -157,11 +111,8 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent,
* - parent: unexpected 0x40, EPERM * - parent: unexpected 0x40, EPERM
*/ */
err = prog_detach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child"); bpf_link__destroy(link_child);
if (err) { link_child = NULL;
log_err("Failed to detach child program");
goto detach;
}
buf = 0x00; buf = 0x00;
optlen = 1; optlen = 1;
...@@ -198,15 +149,17 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, ...@@ -198,15 +149,17 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent,
} }
detach: detach:
prog_detach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child"); bpf_link__destroy(link_child);
prog_detach(obj, cg_parent, "cgroup/getsockopt", "_getsockopt_parent"); bpf_link__destroy(link_parent);
return err; return err;
} }
static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, static int run_setsockopt_test(struct sockopt_multi *obj, int cg_parent,
int cg_child, int sock_fd) int cg_child, int sock_fd)
{ {
struct bpf_link *link_parent = NULL;
struct bpf_link *link_child = NULL;
socklen_t optlen; socklen_t optlen;
__u8 buf; __u8 buf;
int err; int err;
...@@ -236,8 +189,9 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, ...@@ -236,8 +189,9 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent,
/* Attach child program and make sure it adds 0x10. */ /* Attach child program and make sure it adds 0x10. */
err = prog_attach(obj, cg_child, "cgroup/setsockopt", "_setsockopt"); link_child = bpf_program__attach_cgroup(obj->progs._setsockopt,
if (err) cg_child);
if (!ASSERT_OK_PTR(link_child, "cg-attach-setsockopt_child"))
goto detach; goto detach;
buf = 0x80; buf = 0x80;
...@@ -263,8 +217,9 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, ...@@ -263,8 +217,9 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent,
/* Attach parent program and make sure it adds another 0x10. */ /* Attach parent program and make sure it adds another 0x10. */
err = prog_attach(obj, cg_parent, "cgroup/setsockopt", "_setsockopt"); link_parent = bpf_program__attach_cgroup(obj->progs._setsockopt,
if (err) cg_parent);
if (!ASSERT_OK_PTR(link_parent, "cg-attach-setsockopt_parent"))
goto detach; goto detach;
buf = 0x80; buf = 0x80;
...@@ -289,8 +244,8 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, ...@@ -289,8 +244,8 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent,
} }
detach: detach:
prog_detach(obj, cg_child, "cgroup/setsockopt", "_setsockopt"); bpf_link__destroy(link_child);
prog_detach(obj, cg_parent, "cgroup/setsockopt", "_setsockopt"); bpf_link__destroy(link_parent);
return err; return err;
} }
...@@ -298,9 +253,8 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, ...@@ -298,9 +253,8 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent,
void test_sockopt_multi(void) void test_sockopt_multi(void)
{ {
int cg_parent = -1, cg_child = -1; int cg_parent = -1, cg_child = -1;
struct bpf_object *obj = NULL; struct sockopt_multi *obj = NULL;
int sock_fd = -1; int sock_fd = -1;
int err = -1;
cg_parent = test__join_cgroup("/parent"); cg_parent = test__join_cgroup("/parent");
if (!ASSERT_GE(cg_parent, 0, "join_cgroup /parent")) if (!ASSERT_GE(cg_parent, 0, "join_cgroup /parent"))
...@@ -310,13 +264,11 @@ void test_sockopt_multi(void) ...@@ -310,13 +264,11 @@ void test_sockopt_multi(void)
if (!ASSERT_GE(cg_child, 0, "join_cgroup /parent/child")) if (!ASSERT_GE(cg_child, 0, "join_cgroup /parent/child"))
goto out; goto out;
obj = bpf_object__open_file("sockopt_multi.bpf.o", NULL); obj = sockopt_multi__open_and_load();
if (!ASSERT_OK_PTR(obj, "obj_load")) if (!ASSERT_OK_PTR(obj, "skel-load"))
goto out; goto out;
err = bpf_object__load(obj); obj->bss->page_size = sysconf(_SC_PAGESIZE);
if (!ASSERT_OK(err, "obj_load"))
goto out;
sock_fd = socket(AF_INET, SOCK_STREAM, 0); sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (!ASSERT_GE(sock_fd, 0, "socket")) if (!ASSERT_GE(sock_fd, 0, "socket"))
...@@ -327,7 +279,7 @@ void test_sockopt_multi(void) ...@@ -327,7 +279,7 @@ void test_sockopt_multi(void)
out: out:
close(sock_fd); close(sock_fd);
bpf_object__close(obj); sockopt_multi__destroy(obj);
close(cg_child); close(cg_child);
close(cg_parent); close(cg_parent);
} }
...@@ -42,6 +42,8 @@ void test_sockopt_qos_to_cc(void) ...@@ -42,6 +42,8 @@ void test_sockopt_qos_to_cc(void)
if (!ASSERT_OK_PTR(skel, "skel")) if (!ASSERT_OK_PTR(skel, "skel"))
goto done; goto done;
skel->bss->page_size = sysconf(_SC_PAGESIZE);
sock_fd = socket(AF_INET6, SOCK_STREAM, 0); sock_fd = socket(AF_INET6, SOCK_STREAM, 0);
if (!ASSERT_GE(sock_fd, 0, "v6 socket open")) if (!ASSERT_GE(sock_fd, 0, "v6 socket open"))
goto done; goto done;
......
...@@ -12,6 +12,7 @@ __u32 invocations = 0; ...@@ -12,6 +12,7 @@ __u32 invocations = 0;
__u32 assertion_error = 0; __u32 assertion_error = 0;
__u32 retval_value = 0; __u32 retval_value = 0;
__u32 ctx_retval_value = 0; __u32 ctx_retval_value = 0;
__u32 page_size = 0;
SEC("cgroup/getsockopt") SEC("cgroup/getsockopt")
int get_retval(struct bpf_sockopt *ctx) int get_retval(struct bpf_sockopt *ctx)
...@@ -20,6 +21,10 @@ int get_retval(struct bpf_sockopt *ctx) ...@@ -20,6 +21,10 @@ int get_retval(struct bpf_sockopt *ctx)
ctx_retval_value = ctx->retval; ctx_retval_value = ctx->retval;
__sync_fetch_and_add(&invocations, 1); __sync_fetch_and_add(&invocations, 1);
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 1; return 1;
} }
...@@ -31,6 +36,10 @@ int set_eisconn(struct bpf_sockopt *ctx) ...@@ -31,6 +36,10 @@ int set_eisconn(struct bpf_sockopt *ctx)
if (bpf_set_retval(-EISCONN)) if (bpf_set_retval(-EISCONN))
assertion_error = 1; assertion_error = 1;
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 1; return 1;
} }
...@@ -41,5 +50,9 @@ int clear_retval(struct bpf_sockopt *ctx) ...@@ -41,5 +50,9 @@ int clear_retval(struct bpf_sockopt *ctx)
ctx->retval = 0; ctx->retval = 0;
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 1; return 1;
} }
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
__u32 invocations = 0; __u32 invocations = 0;
__u32 assertion_error = 0; __u32 assertion_error = 0;
__u32 retval_value = 0; __u32 retval_value = 0;
__u32 page_size = 0;
SEC("cgroup/setsockopt") SEC("cgroup/setsockopt")
int get_retval(struct bpf_sockopt *ctx) int get_retval(struct bpf_sockopt *ctx)
...@@ -18,6 +19,10 @@ int get_retval(struct bpf_sockopt *ctx) ...@@ -18,6 +19,10 @@ int get_retval(struct bpf_sockopt *ctx)
retval_value = bpf_get_retval(); retval_value = bpf_get_retval();
__sync_fetch_and_add(&invocations, 1); __sync_fetch_and_add(&invocations, 1);
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 1; return 1;
} }
...@@ -29,6 +34,10 @@ int set_eunatch(struct bpf_sockopt *ctx) ...@@ -29,6 +34,10 @@ int set_eunatch(struct bpf_sockopt *ctx)
if (bpf_set_retval(-EUNATCH)) if (bpf_set_retval(-EUNATCH))
assertion_error = 1; assertion_error = 1;
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 0; return 0;
} }
...@@ -40,6 +49,10 @@ int set_eisconn(struct bpf_sockopt *ctx) ...@@ -40,6 +49,10 @@ int set_eisconn(struct bpf_sockopt *ctx)
if (bpf_set_retval(-EISCONN)) if (bpf_set_retval(-EISCONN))
assertion_error = 1; assertion_error = 1;
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 0; return 0;
} }
...@@ -48,5 +61,9 @@ int legacy_eperm(struct bpf_sockopt *ctx) ...@@ -48,5 +61,9 @@ int legacy_eperm(struct bpf_sockopt *ctx)
{ {
__sync_fetch_and_add(&invocations, 1); __sync_fetch_and_add(&invocations, 1);
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 0; return 0;
} }
...@@ -9,6 +9,8 @@ char _license[] SEC("license") = "GPL"; ...@@ -9,6 +9,8 @@ char _license[] SEC("license") = "GPL";
#define CUSTOM_INHERIT2 1 #define CUSTOM_INHERIT2 1
#define CUSTOM_LISTENER 2 #define CUSTOM_LISTENER 2
__u32 page_size = 0;
struct sockopt_inherit { struct sockopt_inherit {
__u8 val; __u8 val;
}; };
...@@ -55,7 +57,7 @@ int _getsockopt(struct bpf_sockopt *ctx) ...@@ -55,7 +57,7 @@ int _getsockopt(struct bpf_sockopt *ctx)
__u8 *optval = ctx->optval; __u8 *optval = ctx->optval;
if (ctx->level != SOL_CUSTOM) if (ctx->level != SOL_CUSTOM)
return 1; /* only interested in SOL_CUSTOM */ goto out; /* only interested in SOL_CUSTOM */
if (optval + 1 > optval_end) if (optval + 1 > optval_end)
return 0; /* EPERM, bounds check */ return 0; /* EPERM, bounds check */
...@@ -70,6 +72,12 @@ int _getsockopt(struct bpf_sockopt *ctx) ...@@ -70,6 +72,12 @@ int _getsockopt(struct bpf_sockopt *ctx)
ctx->optlen = 1; ctx->optlen = 1;
return 1; return 1;
out:
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 1;
} }
SEC("cgroup/setsockopt") SEC("cgroup/setsockopt")
...@@ -80,7 +88,7 @@ int _setsockopt(struct bpf_sockopt *ctx) ...@@ -80,7 +88,7 @@ int _setsockopt(struct bpf_sockopt *ctx)
__u8 *optval = ctx->optval; __u8 *optval = ctx->optval;
if (ctx->level != SOL_CUSTOM) if (ctx->level != SOL_CUSTOM)
return 1; /* only interested in SOL_CUSTOM */ goto out; /* only interested in SOL_CUSTOM */
if (optval + 1 > optval_end) if (optval + 1 > optval_end)
return 0; /* EPERM, bounds check */ return 0; /* EPERM, bounds check */
...@@ -93,4 +101,10 @@ int _setsockopt(struct bpf_sockopt *ctx) ...@@ -93,4 +101,10 @@ int _setsockopt(struct bpf_sockopt *ctx)
ctx->optlen = -1; ctx->optlen = -1;
return 1; return 1;
out:
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 1;
} }
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
char _license[] SEC("license") = "GPL"; char _license[] SEC("license") = "GPL";
__u32 page_size = 0;
SEC("cgroup/getsockopt") SEC("cgroup/getsockopt")
int _getsockopt_child(struct bpf_sockopt *ctx) int _getsockopt_child(struct bpf_sockopt *ctx)
{ {
...@@ -12,7 +14,7 @@ int _getsockopt_child(struct bpf_sockopt *ctx) ...@@ -12,7 +14,7 @@ int _getsockopt_child(struct bpf_sockopt *ctx)
__u8 *optval = ctx->optval; __u8 *optval = ctx->optval;
if (ctx->level != SOL_IP || ctx->optname != IP_TOS) if (ctx->level != SOL_IP || ctx->optname != IP_TOS)
return 1; goto out;
if (optval + 1 > optval_end) if (optval + 1 > optval_end)
return 0; /* EPERM, bounds check */ return 0; /* EPERM, bounds check */
...@@ -26,6 +28,12 @@ int _getsockopt_child(struct bpf_sockopt *ctx) ...@@ -26,6 +28,12 @@ int _getsockopt_child(struct bpf_sockopt *ctx)
ctx->optlen = 1; ctx->optlen = 1;
return 1; return 1;
out:
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 1;
} }
SEC("cgroup/getsockopt") SEC("cgroup/getsockopt")
...@@ -35,7 +43,7 @@ int _getsockopt_parent(struct bpf_sockopt *ctx) ...@@ -35,7 +43,7 @@ int _getsockopt_parent(struct bpf_sockopt *ctx)
__u8 *optval = ctx->optval; __u8 *optval = ctx->optval;
if (ctx->level != SOL_IP || ctx->optname != IP_TOS) if (ctx->level != SOL_IP || ctx->optname != IP_TOS)
return 1; goto out;
if (optval + 1 > optval_end) if (optval + 1 > optval_end)
return 0; /* EPERM, bounds check */ return 0; /* EPERM, bounds check */
...@@ -49,6 +57,12 @@ int _getsockopt_parent(struct bpf_sockopt *ctx) ...@@ -49,6 +57,12 @@ int _getsockopt_parent(struct bpf_sockopt *ctx)
ctx->optlen = 1; ctx->optlen = 1;
return 1; return 1;
out:
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 1;
} }
SEC("cgroup/setsockopt") SEC("cgroup/setsockopt")
...@@ -58,7 +72,7 @@ int _setsockopt(struct bpf_sockopt *ctx) ...@@ -58,7 +72,7 @@ int _setsockopt(struct bpf_sockopt *ctx)
__u8 *optval = ctx->optval; __u8 *optval = ctx->optval;
if (ctx->level != SOL_IP || ctx->optname != IP_TOS) if (ctx->level != SOL_IP || ctx->optname != IP_TOS)
return 1; goto out;
if (optval + 1 > optval_end) if (optval + 1 > optval_end)
return 0; /* EPERM, bounds check */ return 0; /* EPERM, bounds check */
...@@ -67,4 +81,10 @@ int _setsockopt(struct bpf_sockopt *ctx) ...@@ -67,4 +81,10 @@ int _setsockopt(struct bpf_sockopt *ctx)
ctx->optlen = 1; ctx->optlen = 1;
return 1; return 1;
out:
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 1;
} }
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
char _license[] SEC("license") = "GPL"; char _license[] SEC("license") = "GPL";
__u32 page_size = 0;
SEC("cgroup/setsockopt") SEC("cgroup/setsockopt")
int sockopt_qos_to_cc(struct bpf_sockopt *ctx) int sockopt_qos_to_cc(struct bpf_sockopt *ctx)
{ {
...@@ -19,7 +21,7 @@ int sockopt_qos_to_cc(struct bpf_sockopt *ctx) ...@@ -19,7 +21,7 @@ int sockopt_qos_to_cc(struct bpf_sockopt *ctx)
char cc_cubic[TCP_CA_NAME_MAX] = "cubic"; char cc_cubic[TCP_CA_NAME_MAX] = "cubic";
if (ctx->level != SOL_IPV6 || ctx->optname != IPV6_TCLASS) if (ctx->level != SOL_IPV6 || ctx->optname != IPV6_TCLASS)
return 1; goto out;
if (optval + 1 > optval_end) if (optval + 1 > optval_end)
return 0; /* EPERM, bounds check */ return 0; /* EPERM, bounds check */
...@@ -36,4 +38,10 @@ int sockopt_qos_to_cc(struct bpf_sockopt *ctx) ...@@ -36,4 +38,10 @@ int sockopt_qos_to_cc(struct bpf_sockopt *ctx)
return 0; return 0;
} }
return 1; return 1;
out:
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 1;
} }
...@@ -37,7 +37,7 @@ int _getsockopt(struct bpf_sockopt *ctx) ...@@ -37,7 +37,7 @@ int _getsockopt(struct bpf_sockopt *ctx)
/* Bypass AF_NETLINK. */ /* Bypass AF_NETLINK. */
sk = ctx->sk; sk = ctx->sk;
if (sk && sk->family == AF_NETLINK) if (sk && sk->family == AF_NETLINK)
return 1; goto out;
/* Make sure bpf_get_netns_cookie is callable. /* Make sure bpf_get_netns_cookie is callable.
*/ */
...@@ -52,8 +52,7 @@ int _getsockopt(struct bpf_sockopt *ctx) ...@@ -52,8 +52,7 @@ int _getsockopt(struct bpf_sockopt *ctx)
* let next BPF program in the cgroup chain or kernel * let next BPF program in the cgroup chain or kernel
* handle it. * handle it.
*/ */
ctx->optlen = 0; /* bypass optval>PAGE_SIZE */ goto out;
return 1;
} }
if (ctx->level == SOL_SOCKET && ctx->optname == SO_SNDBUF) { if (ctx->level == SOL_SOCKET && ctx->optname == SO_SNDBUF) {
...@@ -61,7 +60,7 @@ int _getsockopt(struct bpf_sockopt *ctx) ...@@ -61,7 +60,7 @@ int _getsockopt(struct bpf_sockopt *ctx)
* let next BPF program in the cgroup chain or kernel * let next BPF program in the cgroup chain or kernel
* handle it. * handle it.
*/ */
return 1; goto out;
} }
if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION) { if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION) {
...@@ -69,7 +68,7 @@ int _getsockopt(struct bpf_sockopt *ctx) ...@@ -69,7 +68,7 @@ int _getsockopt(struct bpf_sockopt *ctx)
* let next BPF program in the cgroup chain or kernel * let next BPF program in the cgroup chain or kernel
* handle it. * handle it.
*/ */
return 1; goto out;
} }
if (ctx->level == SOL_TCP && ctx->optname == TCP_ZEROCOPY_RECEIVE) { if (ctx->level == SOL_TCP && ctx->optname == TCP_ZEROCOPY_RECEIVE) {
...@@ -85,7 +84,7 @@ int _getsockopt(struct bpf_sockopt *ctx) ...@@ -85,7 +84,7 @@ int _getsockopt(struct bpf_sockopt *ctx)
if (((struct tcp_zerocopy_receive *)optval)->address != 0) if (((struct tcp_zerocopy_receive *)optval)->address != 0)
return 0; /* unexpected data */ return 0; /* unexpected data */
return 1; goto out;
} }
if (ctx->level == SOL_IP && ctx->optname == IP_FREEBIND) { if (ctx->level == SOL_IP && ctx->optname == IP_FREEBIND) {
...@@ -129,6 +128,12 @@ int _getsockopt(struct bpf_sockopt *ctx) ...@@ -129,6 +128,12 @@ int _getsockopt(struct bpf_sockopt *ctx)
ctx->optlen = 1; ctx->optlen = 1;
return 1; return 1;
out:
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 1;
} }
SEC("cgroup/setsockopt") SEC("cgroup/setsockopt")
...@@ -142,7 +147,7 @@ int _setsockopt(struct bpf_sockopt *ctx) ...@@ -142,7 +147,7 @@ int _setsockopt(struct bpf_sockopt *ctx)
/* Bypass AF_NETLINK. */ /* Bypass AF_NETLINK. */
sk = ctx->sk; sk = ctx->sk;
if (sk && sk->family == AF_NETLINK) if (sk && sk->family == AF_NETLINK)
return 1; goto out;
/* Make sure bpf_get_netns_cookie is callable. /* Make sure bpf_get_netns_cookie is callable.
*/ */
...@@ -224,4 +229,10 @@ int _setsockopt(struct bpf_sockopt *ctx) ...@@ -224,4 +229,10 @@ int _setsockopt(struct bpf_sockopt *ctx)
*/ */
return 1; return 1;
out:
/* optval larger than PAGE_SIZE use kernel's buffer. */
if (ctx->optlen > page_size)
ctx->optlen = 0;
return 1;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment