Skip to content

Commit 0c3e247

Browse files
committed
Daniel Borkmann says: ==================== pull-request: bpf 2021-12-16 We've added 15 non-merge commits during the last 7 day(s) which contain a total of 12 files changed, 434 insertions(+), 30 deletions(-). The main changes are: 1) Fix incorrect verifier state pruning behavior for <8B register spill/fill, from Paul Chaignon. 2) Fix x86-64 JIT's extable handling for fentry/fexit when return pointer is an ERR_PTR(), from Alexei Starovoitov. 3) Fix 3 different possibilities that BPF verifier missed where unprivileged could leak kernel addresses, from Daniel Borkmann. 4) Fix xsk's poll behavior under need_wakeup flag, from Magnus Karlsson. 5) Fix an oob-write in test_verifier due to a missed MAX_NR_MAPS bump, from Kumar Kartikeya Dwivedi. 6) Fix a race in test_btf_skc_cls_ingress selftest, from Martin KaFai Lau. * https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: bpf, selftests: Fix racing issue in btf_skc_cls_ingress test selftest/bpf: Add a test that reads various addresses. bpf: Fix extable address check. bpf: Fix extable fixup offset. bpf, selftests: Add test case trying to taint map value pointer bpf: Make 32->64 bounds propagation slightly more robust bpf: Fix signed bounds propagation after mov32 bpf, selftests: Update test case for atomic cmpxchg on r0 with pointer bpf: Fix kernel address leakage in atomic cmpxchg's r0 aux reg bpf, selftests: Add test case for atomic fetch on spilled pointer bpf: Fix kernel address leakage in atomic fetch selftests/bpf: Fix OOB write in test_verifier xsk: Do not sleep in poll() when need_wakeup set selftests/bpf: Tests for state pruning with u32 spill/fill bpf: Fix incorrect state pruning for <8B spill/fill ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents e28587c + c2fcbf8 commit 0c3e247

File tree

12 files changed

+434
-30
lines changed

12 files changed

+434
-30
lines changed

arch/x86/net/bpf_jit_comp.c

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,19 +1252,54 @@ st: if (is_imm8(insn->off))
12521252
case BPF_LDX | BPF_MEM | BPF_DW:
12531253
case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
12541254
if (BPF_MODE(insn->code) == BPF_PROBE_MEM) {
1255-
/* test src_reg, src_reg */
1256-
maybe_emit_mod(&prog, src_reg, src_reg, true); /* always 1 byte */
1257-
EMIT2(0x85, add_2reg(0xC0, src_reg, src_reg));
1258-
/* jne start_of_ldx */
1259-
EMIT2(X86_JNE, 0);
1255+
/* Though the verifier prevents negative insn->off in BPF_PROBE_MEM
1256+
* add abs(insn->off) to the limit to make sure that negative
1257+
* offset won't be an issue.
1258+
* insn->off is s16, so it won't affect valid pointers.
1259+
*/
1260+
u64 limit = TASK_SIZE_MAX + PAGE_SIZE + abs(insn->off);
1261+
u8 *end_of_jmp1, *end_of_jmp2;
1262+
1263+
/* Conservatively check that src_reg + insn->off is a kernel address:
1264+
* 1. src_reg + insn->off >= limit
1265+
* 2. src_reg + insn->off doesn't become small positive.
1266+
* Cannot do src_reg + insn->off >= limit in one branch,
1267+
* since it needs two spare registers, but JIT has only one.
1268+
*/
1269+
1270+
/* movabsq r11, limit */
1271+
EMIT2(add_1mod(0x48, AUX_REG), add_1reg(0xB8, AUX_REG));
1272+
EMIT((u32)limit, 4);
1273+
EMIT(limit >> 32, 4);
1274+
/* cmp src_reg, r11 */
1275+
maybe_emit_mod(&prog, src_reg, AUX_REG, true);
1276+
EMIT2(0x39, add_2reg(0xC0, src_reg, AUX_REG));
1277+
/* if unsigned '<' goto end_of_jmp2 */
1278+
EMIT2(X86_JB, 0);
1279+
end_of_jmp1 = prog;
1280+
1281+
/* mov r11, src_reg */
1282+
emit_mov_reg(&prog, true, AUX_REG, src_reg);
1283+
/* add r11, insn->off */
1284+
maybe_emit_1mod(&prog, AUX_REG, true);
1285+
EMIT2_off32(0x81, add_1reg(0xC0, AUX_REG), insn->off);
1286+
/* jmp if not carry to start_of_ldx
1287+
* Otherwise ERR_PTR(-EINVAL) + 128 will be the user addr
1288+
* that has to be rejected.
1289+
*/
1290+
EMIT2(0x73 /* JNC */, 0);
1291+
end_of_jmp2 = prog;
1292+
12601293
/* xor dst_reg, dst_reg */
12611294
emit_mov_imm32(&prog, false, dst_reg, 0);
12621295
/* jmp byte_after_ldx */
12631296
EMIT2(0xEB, 0);
12641297

1265-
/* populate jmp_offset for JNE above */
1266-
temp[4] = prog - temp - 5 /* sizeof(test + jne) */;
1298+
/* populate jmp_offset for JB above to jump to xor dst_reg */
1299+
end_of_jmp1[-1] = end_of_jmp2 - end_of_jmp1;
1300+
/* populate jmp_offset for JNC above to jump to start_of_ldx */
12671301
start_of_ldx = prog;
1302+
end_of_jmp2[-1] = start_of_ldx - end_of_jmp2;
12681303
}
12691304
emit_ldx(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn->off);
12701305
if (BPF_MODE(insn->code) == BPF_PROBE_MEM) {
@@ -1305,7 +1340,7 @@ st: if (is_imm8(insn->off))
13051340
* End result: x86 insn "mov rbx, qword ptr [rax+0x14]"
13061341
* of 4 bytes will be ignored and rbx will be zero inited.
13071342
*/
1308-
ex->fixup = (prog - temp) | (reg2pt_regs[dst_reg] << 8);
1343+
ex->fixup = (prog - start_of_ldx) | (reg2pt_regs[dst_reg] << 8);
13091344
}
13101345
break;
13111346

kernel/bpf/verifier.c

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,22 +1366,28 @@ static void __reg_bound_offset(struct bpf_reg_state *reg)
13661366
reg->var_off = tnum_or(tnum_clear_subreg(var64_off), var32_off);
13671367
}
13681368

1369+
static bool __reg32_bound_s64(s32 a)
1370+
{
1371+
return a >= 0 && a <= S32_MAX;
1372+
}
1373+
13691374
static void __reg_assign_32_into_64(struct bpf_reg_state *reg)
13701375
{
13711376
reg->umin_value = reg->u32_min_value;
13721377
reg->umax_value = reg->u32_max_value;
1373-
/* Attempt to pull 32-bit signed bounds into 64-bit bounds
1374-
* but must be positive otherwise set to worse case bounds
1375-
* and refine later from tnum.
1378+
1379+
/* Attempt to pull 32-bit signed bounds into 64-bit bounds but must
1380+
* be positive otherwise set to worse case bounds and refine later
1381+
* from tnum.
13761382
*/
1377-
if (reg->s32_min_value >= 0 && reg->s32_max_value >= 0)
1378-
reg->smax_value = reg->s32_max_value;
1379-
else
1380-
reg->smax_value = U32_MAX;
1381-
if (reg->s32_min_value >= 0)
1383+
if (__reg32_bound_s64(reg->s32_min_value) &&
1384+
__reg32_bound_s64(reg->s32_max_value)) {
13821385
reg->smin_value = reg->s32_min_value;
1383-
else
1386+
reg->smax_value = reg->s32_max_value;
1387+
} else {
13841388
reg->smin_value = 0;
1389+
reg->smax_value = U32_MAX;
1390+
}
13851391
}
13861392

13871393
static void __reg_combine_32_into_64(struct bpf_reg_state *reg)
@@ -2379,8 +2385,6 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx,
23792385
*/
23802386
if (insn->src_reg != BPF_REG_FP)
23812387
return 0;
2382-
if (BPF_SIZE(insn->code) != BPF_DW)
2383-
return 0;
23842388

23852389
/* dreg = *(u64 *)[fp - off] was a fill from the stack.
23862390
* that [fp - off] slot contains scalar that needs to be
@@ -2403,8 +2407,6 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx,
24032407
/* scalars can only be spilled into stack */
24042408
if (insn->dst_reg != BPF_REG_FP)
24052409
return 0;
2406-
if (BPF_SIZE(insn->code) != BPF_DW)
2407-
return 0;
24082410
spi = (-insn->off - 1) / BPF_REG_SIZE;
24092411
if (spi >= 64) {
24102412
verbose(env, "BUG spi %d\n", spi);
@@ -4551,9 +4553,16 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i
45514553

45524554
if (insn->imm == BPF_CMPXCHG) {
45534555
/* Check comparison of R0 with memory location */
4554-
err = check_reg_arg(env, BPF_REG_0, SRC_OP);
4556+
const u32 aux_reg = BPF_REG_0;
4557+
4558+
err = check_reg_arg(env, aux_reg, SRC_OP);
45554559
if (err)
45564560
return err;
4561+
4562+
if (is_pointer_value(env, aux_reg)) {
4563+
verbose(env, "R%d leaks addr into mem\n", aux_reg);
4564+
return -EACCES;
4565+
}
45574566
}
45584567

45594568
if (is_pointer_value(env, insn->src_reg)) {
@@ -4588,13 +4597,19 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i
45884597
load_reg = -1;
45894598
}
45904599

4591-
/* check whether we can read the memory */
4600+
/* Check whether we can read the memory, with second call for fetch
4601+
* case to simulate the register fill.
4602+
*/
45924603
err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
4593-
BPF_SIZE(insn->code), BPF_READ, load_reg, true);
4604+
BPF_SIZE(insn->code), BPF_READ, -1, true);
4605+
if (!err && load_reg >= 0)
4606+
err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
4607+
BPF_SIZE(insn->code), BPF_READ, load_reg,
4608+
true);
45944609
if (err)
45954610
return err;
45964611

4597-
/* check whether we can write into the same memory */
4612+
/* Check whether we can write into the same memory. */
45984613
err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
45994614
BPF_SIZE(insn->code), BPF_WRITE, -1, true);
46004615
if (err)
@@ -8308,6 +8323,10 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
83088323
insn->dst_reg);
83098324
}
83108325
zext_32_to_64(dst_reg);
8326+
8327+
__update_reg_bounds(dst_reg);
8328+
__reg_deduce_bounds(dst_reg);
8329+
__reg_bound_offset(dst_reg);
83118330
}
83128331
} else {
83138332
/* case: R = imm

net/xdp/xsk.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -677,8 +677,6 @@ static __poll_t xsk_poll(struct file *file, struct socket *sock,
677677
struct xdp_sock *xs = xdp_sk(sk);
678678
struct xsk_buff_pool *pool;
679679

680-
sock_poll_wait(file, sock, wait);
681-
682680
if (unlikely(!xsk_is_bound(xs)))
683681
return mask;
684682

@@ -690,6 +688,8 @@ static __poll_t xsk_poll(struct file *file, struct socket *sock,
690688
else
691689
/* Poll needs to drive Tx also in copy mode */
692690
__xsk_sendmsg(sk);
691+
} else {
692+
sock_poll_wait(file, sock, wait);
693693
}
694694

695695
if (xs->rx && !xskq_prod_is_empty(xs->rx))

tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,22 @@ noinline int bpf_testmod_loop_test(int n)
3333
return sum;
3434
}
3535

36+
__weak noinline struct file *bpf_testmod_return_ptr(int arg)
37+
{
38+
static struct file f = {};
39+
40+
switch (arg) {
41+
case 1: return (void *)EINVAL; /* user addr */
42+
case 2: return (void *)0xcafe4a11; /* user addr */
43+
case 3: return (void *)-EINVAL; /* canonical, but invalid */
44+
case 4: return (void *)(1ull << 60); /* non-canonical and invalid */
45+
case 5: return (void *)~(1ull << 30); /* trigger extable */
46+
case 6: return &f; /* valid addr */
47+
case 7: return (void *)((long)&f | 1); /* kernel tricks */
48+
default: return NULL;
49+
}
50+
}
51+
3652
noinline ssize_t
3753
bpf_testmod_test_read(struct file *file, struct kobject *kobj,
3854
struct bin_attribute *bin_attr,
@@ -43,6 +59,10 @@ bpf_testmod_test_read(struct file *file, struct kobject *kobj,
4359
.off = off,
4460
.len = len,
4561
};
62+
int i = 1;
63+
64+
while (bpf_testmod_return_ptr(i))
65+
i++;
4666

4767
/* This is always true. Use the check to make sure the compiler
4868
* doesn't remove bpf_testmod_loop_test.

tools/testing/selftests/bpf/prog_tests/btf_skc_cls_ingress.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ static void print_err_line(void)
9090

9191
static void test_conn(void)
9292
{
93-
int listen_fd = -1, cli_fd = -1, err;
93+
int listen_fd = -1, cli_fd = -1, srv_fd = -1, err;
9494
socklen_t addrlen = sizeof(srv_sa6);
9595
int srv_port;
9696

@@ -112,6 +112,10 @@ static void test_conn(void)
112112
if (CHECK_FAIL(cli_fd == -1))
113113
goto done;
114114

115+
srv_fd = accept(listen_fd, NULL, NULL);
116+
if (CHECK_FAIL(srv_fd == -1))
117+
goto done;
118+
115119
if (CHECK(skel->bss->listen_tp_sport != srv_port ||
116120
skel->bss->req_sk_sport != srv_port,
117121
"Unexpected sk src port",
@@ -134,11 +138,13 @@ static void test_conn(void)
134138
close(listen_fd);
135139
if (cli_fd != -1)
136140
close(cli_fd);
141+
if (srv_fd != -1)
142+
close(srv_fd);
137143
}
138144

139145
static void test_syncookie(void)
140146
{
141-
int listen_fd = -1, cli_fd = -1, err;
147+
int listen_fd = -1, cli_fd = -1, srv_fd = -1, err;
142148
socklen_t addrlen = sizeof(srv_sa6);
143149
int srv_port;
144150

@@ -161,6 +167,10 @@ static void test_syncookie(void)
161167
if (CHECK_FAIL(cli_fd == -1))
162168
goto done;
163169

170+
srv_fd = accept(listen_fd, NULL, NULL);
171+
if (CHECK_FAIL(srv_fd == -1))
172+
goto done;
173+
164174
if (CHECK(skel->bss->listen_tp_sport != srv_port,
165175
"Unexpected tp src port",
166176
"listen_tp_sport:%u expected:%u\n",
@@ -188,6 +198,8 @@ static void test_syncookie(void)
188198
close(listen_fd);
189199
if (cli_fd != -1)
190200
close(cli_fd);
201+
if (srv_fd != -1)
202+
close(srv_fd);
191203
}
192204

193205
struct test {

tools/testing/selftests/bpf/progs/test_module_attach.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,18 @@ int BPF_PROG(handle_fexit,
8787
return 0;
8888
}
8989

90+
SEC("fexit/bpf_testmod_return_ptr")
91+
int BPF_PROG(handle_fexit_ret, int arg, struct file *ret)
92+
{
93+
long buf = 0;
94+
95+
bpf_probe_read_kernel(&buf, 8, ret);
96+
bpf_probe_read_kernel(&buf, 8, (char *)ret + 256);
97+
*(volatile long long *)ret;
98+
*(volatile int *)&ret->f_mode;
99+
return 0;
100+
}
101+
90102
__u32 fmod_ret_read_sz = 0;
91103

92104
SEC("fmod_ret/bpf_testmod_test_read")

tools/testing/selftests/bpf/test_verifier.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
#define MAX_INSNS BPF_MAXINSNS
5555
#define MAX_TEST_INSNS 1000000
5656
#define MAX_FIXUPS 8
57-
#define MAX_NR_MAPS 21
57+
#define MAX_NR_MAPS 22
5858
#define MAX_TEST_RUNS 8
5959
#define POINTER_VALUE 0xcafe4all
6060
#define TEST_DATA_LEN 64

0 commit comments

Comments
 (0)