diff options
-rw-r--r-- | include/linux/filter.h | 8 | ||||
-rw-r--r-- | kernel/bpf/cgroup.c | 10 | ||||
-rw-r--r-- | kernel/bpf/verifier.c | 4 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/test_sysctl.c | 9 |
4 files changed, 22 insertions, 9 deletions
diff --git a/include/linux/filter.h b/include/linux/filter.h index 92c6e31fb008..2ce57645f3cd 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h | |||
@@ -749,14 +749,14 @@ bpf_ctx_narrow_access_ok(u32 off, u32 size, u32 size_default) | |||
749 | } | 749 | } |
750 | 750 | ||
751 | static inline u8 | 751 | static inline u8 |
752 | bpf_ctx_narrow_load_shift(u32 off, u32 size, u32 size_default) | 752 | bpf_ctx_narrow_access_offset(u32 off, u32 size, u32 size_default) |
753 | { | 753 | { |
754 | u8 load_off = off & (size_default - 1); | 754 | u8 access_off = off & (size_default - 1); |
755 | 755 | ||
756 | #ifdef __LITTLE_ENDIAN | 756 | #ifdef __LITTLE_ENDIAN |
757 | return load_off * 8; | 757 | return access_off; |
758 | #else | 758 | #else |
759 | return (size_default - (load_off + size)) * 8; | 759 | return size_default - (access_off + size); |
760 | #endif | 760 | #endif |
761 | } | 761 | } |
762 | 762 | ||
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 6a6a154cfa7b..ddd8addcdb5c 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c | |||
@@ -1334,6 +1334,7 @@ static u32 sysctl_convert_ctx_access(enum bpf_access_type type, | |||
1334 | struct bpf_prog *prog, u32 *target_size) | 1334 | struct bpf_prog *prog, u32 *target_size) |
1335 | { | 1335 | { |
1336 | struct bpf_insn *insn = insn_buf; | 1336 | struct bpf_insn *insn = insn_buf; |
1337 | u32 read_size; | ||
1337 | 1338 | ||
1338 | switch (si->off) { | 1339 | switch (si->off) { |
1339 | case offsetof(struct bpf_sysctl, write): | 1340 | case offsetof(struct bpf_sysctl, write): |
@@ -1365,7 +1366,9 @@ static u32 sysctl_convert_ctx_access(enum bpf_access_type type, | |||
1365 | treg, si->dst_reg, | 1366 | treg, si->dst_reg, |
1366 | offsetof(struct bpf_sysctl_kern, ppos)); | 1367 | offsetof(struct bpf_sysctl_kern, ppos)); |
1367 | *insn++ = BPF_STX_MEM( | 1368 | *insn++ = BPF_STX_MEM( |
1368 | BPF_SIZEOF(u32), treg, si->src_reg, 0); | 1369 | BPF_SIZEOF(u32), treg, si->src_reg, |
1370 | bpf_ctx_narrow_access_offset( | ||
1371 | 0, sizeof(u32), sizeof(loff_t))); | ||
1369 | *insn++ = BPF_LDX_MEM( | 1372 | *insn++ = BPF_LDX_MEM( |
1370 | BPF_DW, treg, si->dst_reg, | 1373 | BPF_DW, treg, si->dst_reg, |
1371 | offsetof(struct bpf_sysctl_kern, tmp_reg)); | 1374 | offsetof(struct bpf_sysctl_kern, tmp_reg)); |
@@ -1374,8 +1377,11 @@ static u32 sysctl_convert_ctx_access(enum bpf_access_type type, | |||
1374 | BPF_FIELD_SIZEOF(struct bpf_sysctl_kern, ppos), | 1377 | BPF_FIELD_SIZEOF(struct bpf_sysctl_kern, ppos), |
1375 | si->dst_reg, si->src_reg, | 1378 | si->dst_reg, si->src_reg, |
1376 | offsetof(struct bpf_sysctl_kern, ppos)); | 1379 | offsetof(struct bpf_sysctl_kern, ppos)); |
1380 | read_size = bpf_size_to_bytes(BPF_SIZE(si->code)); | ||
1377 | *insn++ = BPF_LDX_MEM( | 1381 | *insn++ = BPF_LDX_MEM( |
1378 | BPF_SIZE(si->code), si->dst_reg, si->dst_reg, 0); | 1382 | BPF_SIZE(si->code), si->dst_reg, si->dst_reg, |
1383 | bpf_ctx_narrow_access_offset( | ||
1384 | 0, read_size, sizeof(loff_t))); | ||
1379 | } | 1385 | } |
1380 | *target_size = sizeof(u32); | 1386 | *target_size = sizeof(u32); |
1381 | break; | 1387 | break; |
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 3fb50757e812..92a4332b041d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -8619,8 +8619,8 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env) | |||
8619 | } | 8619 | } |
8620 | 8620 | ||
8621 | if (is_narrower_load && size < target_size) { | 8621 | if (is_narrower_load && size < target_size) { |
8622 | u8 shift = bpf_ctx_narrow_load_shift(off, size, | 8622 | u8 shift = bpf_ctx_narrow_access_offset( |
8623 | size_default); | 8623 | off, size, size_default) * 8; |
8624 | if (ctx_field_size <= 4) { | 8624 | if (ctx_field_size <= 4) { |
8625 | if (shift) | 8625 | if (shift) |
8626 | insn_buf[cnt++] = BPF_ALU32_IMM(BPF_RSH, | 8626 | insn_buf[cnt++] = BPF_ALU32_IMM(BPF_RSH, |
diff --git a/tools/testing/selftests/bpf/test_sysctl.c b/tools/testing/selftests/bpf/test_sysctl.c index fc33ae36b760..4f8ec1f10a80 100644 --- a/tools/testing/selftests/bpf/test_sysctl.c +++ b/tools/testing/selftests/bpf/test_sysctl.c | |||
@@ -32,6 +32,7 @@ struct sysctl_test { | |||
32 | enum bpf_attach_type attach_type; | 32 | enum bpf_attach_type attach_type; |
33 | const char *sysctl; | 33 | const char *sysctl; |
34 | int open_flags; | 34 | int open_flags; |
35 | int seek; | ||
35 | const char *newval; | 36 | const char *newval; |
36 | const char *oldval; | 37 | const char *oldval; |
37 | enum { | 38 | enum { |
@@ -140,7 +141,7 @@ static struct sysctl_test tests[] = { | |||
140 | /* If (file_pos == X) */ | 141 | /* If (file_pos == X) */ |
141 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1, | 142 | BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1, |
142 | offsetof(struct bpf_sysctl, file_pos)), | 143 | offsetof(struct bpf_sysctl, file_pos)), |
143 | BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0, 2), | 144 | BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 3, 2), |
144 | 145 | ||
145 | /* return ALLOW; */ | 146 | /* return ALLOW; */ |
146 | BPF_MOV64_IMM(BPF_REG_0, 1), | 147 | BPF_MOV64_IMM(BPF_REG_0, 1), |
@@ -153,6 +154,7 @@ static struct sysctl_test tests[] = { | |||
153 | .attach_type = BPF_CGROUP_SYSCTL, | 154 | .attach_type = BPF_CGROUP_SYSCTL, |
154 | .sysctl = "kernel/ostype", | 155 | .sysctl = "kernel/ostype", |
155 | .open_flags = O_RDONLY, | 156 | .open_flags = O_RDONLY, |
157 | .seek = 3, | ||
156 | .result = SUCCESS, | 158 | .result = SUCCESS, |
157 | }, | 159 | }, |
158 | { | 160 | { |
@@ -1481,6 +1483,11 @@ static int access_sysctl(const char *sysctl_path, | |||
1481 | if (fd < 0) | 1483 | if (fd < 0) |
1482 | return fd; | 1484 | return fd; |
1483 | 1485 | ||
1486 | if (test->seek && lseek(fd, test->seek, SEEK_SET) == -1) { | ||
1487 | log_err("lseek(%d) failed", test->seek); | ||
1488 | goto err; | ||
1489 | } | ||
1490 | |||
1484 | if (test->open_flags == O_RDONLY) { | 1491 | if (test->open_flags == O_RDONLY) { |
1485 | char buf[128]; | 1492 | char buf[128]; |
1486 | 1493 | ||