aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/filter.h8
-rw-r--r--kernel/bpf/cgroup.c10
-rw-r--r--kernel/bpf/verifier.c4
-rw-r--r--tools/testing/selftests/bpf/test_sysctl.c9
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
751static inline u8 751static inline u8
752bpf_ctx_narrow_load_shift(u32 off, u32 size, u32 size_default) 752bpf_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