linux_dsm_epyc7002/kernel
Andrey Ignatov 7bb09c69f3 bpf: Fix possible out of bound write in narrow load handling
[ Upstream commit d7af7e497f0308bc97809cc48b58e8e0f13887e1 ]

Fix a verifier bug found by smatch static checker in [0].

This problem has never been seen in prod to my best knowledge. Fixing it
still seems to be a good idea since it's hard to say for sure whether
it's possible or not to have a scenario where a combination of
convert_ctx_access() and a narrow load would lead to an out of bound
write.

When narrow load is handled, one or two new instructions are added to
insn_buf array, but before it was only checked that

	cnt >= ARRAY_SIZE(insn_buf)

And it's safe to add a new instruction to insn_buf[cnt++] only once. The
second try will lead to out of bound write. And this is what can happen
if `shift` is set.

Fix it by making sure that if the BPF_RSH instruction has to be added in
addition to BPF_AND then there is enough space for two more instructions
in insn_buf.

The full report [0] is below:

kernel/bpf/verifier.c:12304 convert_ctx_accesses() warn: offset 'cnt' incremented past end of array
kernel/bpf/verifier.c:12311 convert_ctx_accesses() warn: offset 'cnt' incremented past end of array

kernel/bpf/verifier.c
    12282
    12283 			insn->off = off & ~(size_default - 1);
    12284 			insn->code = BPF_LDX | BPF_MEM | size_code;
    12285 		}
    12286
    12287 		target_size = 0;
    12288 		cnt = convert_ctx_access(type, insn, insn_buf, env->prog,
    12289 					 &target_size);
    12290 		if (cnt == 0 || cnt >= ARRAY_SIZE(insn_buf) ||
                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Bounds check.

    12291 		    (ctx_field_size && !target_size)) {
    12292 			verbose(env, "bpf verifier is misconfigured\n");
    12293 			return -EINVAL;
    12294 		}
    12295
    12296 		if (is_narrower_load && size < target_size) {
    12297 			u8 shift = bpf_ctx_narrow_access_offset(
    12298 				off, size, size_default) * 8;
    12299 			if (ctx_field_size <= 4) {
    12300 				if (shift)
    12301 					insn_buf[cnt++] = BPF_ALU32_IMM(BPF_RSH,
                                                         ^^^^^
increment beyond end of array

    12302 									insn->dst_reg,
    12303 									shift);
--> 12304 				insn_buf[cnt++] = BPF_ALU32_IMM(BPF_AND, insn->dst_reg,
                                                 ^^^^^
out of bounds write

    12305 								(1 << size * 8) - 1);
    12306 			} else {
    12307 				if (shift)
    12308 					insn_buf[cnt++] = BPF_ALU64_IMM(BPF_RSH,
    12309 									insn->dst_reg,
    12310 									shift);
    12311 				insn_buf[cnt++] = BPF_ALU64_IMM(BPF_AND, insn->dst_reg,
                                        ^^^^^^^^^^^^^^^
Same.

    12312 								(1ULL << size * 8) - 1);
    12313 			}
    12314 		}
    12315
    12316 		new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
    12317 		if (!new_prog)
    12318 			return -ENOMEM;
    12319
    12320 		delta += cnt - 1;
    12321
    12322 		/* keep walking new program and skip insns we just inserted */
    12323 		env->prog = new_prog;
    12324 		insn      = new_prog->insnsi + i + delta;
    12325 	}
    12326
    12327 	return 0;
    12328 }

[0] https://lore.kernel.org/bpf/20210817050843.GA21456@kili/

v1->v2:
- clarify that problem was only seen by static checker but not in prod;

Fixes: 46f53a65d2 ("bpf: Allow narrow loads with offset > 0")
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Andrey Ignatov <rdna@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20210820163935.1902398-1-rdna@fb.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
2024-07-05 19:12:23 +02:00
..
bpf bpf: Fix possible out of bound write in narrow load handling 2024-07-05 19:12:23 +02:00
cgroup cgroup/cpuset: Fix violation of cpuset locking rule 2024-07-05 19:11:38 +02:00
configs
debug
dma dma-mapping: handle vmalloc addresses in dma_common_{mmap,get_sgtable} 2021-07-28 14:35:38 +02:00
entry x86/entry: Move nmi entry/exit into common code 2021-03-17 17:06:36 +01:00
events init: add dsm gpl source 2024-07-05 18:00:04 +02:00
gcov gcov: re-fix clang-11+ support 2021-04-14 08:41:58 +02:00
irq genirq/timings: Fix error return code in irq_timings_test_irqs() 2024-07-05 19:10:07 +02:00
kcsan kcsan: Fix debugfs initcall return type 2021-05-26 12:06:54 +02:00
livepatch
locking locking/lockdep: Mark local_lock_t 2024-07-05 19:12:04 +02:00
power PM: EM: Increase energy calculation precision 2024-07-05 19:11:38 +02:00
printk init: add dsm gpl source 2024-07-05 18:00:04 +02:00
rcu rcu: Fix stall-warning deadlock due to non-release of rcu_node ->lock 2024-07-05 19:09:59 +02:00
sched sched: Fix UCLAMP_FLAG_IDLE setting 2024-07-05 19:09:59 +02:00
time hrtimer: Ensure timerfd notification for HIGHRES=n 2024-07-05 19:08:50 +02:00
trace tracing / histogram: Fix NULL pointer dereference on strcmp() on NULL event name 2024-07-05 18:55:58 +02:00
.gitignore kbuild: update config_data.gz only when the content of .config is changed 2021-05-11 14:47:37 +02:00
acct.c
async.c
audit_fsnotify.c
audit_tree.c audit: move put_tree() to avoid trim_trees refcount underflow and UAF 2024-07-05 19:02:28 +02:00
audit_watch.c
audit.c
audit.h
auditfilter.c
auditsc.c
backtracetest.c
bounds.c
capability.c
compat.c
configs.c
context_tracking.c
cpu_pm.c PM: cpu: Make notifier chain use a raw_spinlock_t 2024-07-05 19:11:56 +02:00
cpu.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
crash_core.c crash_core, vmcoreinfo: append 'SECTION_SIZE_BITS' to vmcoreinfo 2021-06-23 14:42:52 +02:00
crash_dump.c
cred.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
delayacct.c
dma.c
exec_domain.c
exit.c
extable.c
fail_function.c
fork.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
freezer.c Revert "kernel: freezer should treat PF_IO_WORKER like PF_KTHREAD for freezing" 2021-04-07 15:00:14 +02:00
futex.c mm, futex: fix shared futex pgoff on shmem huge page 2021-06-30 08:47:29 -04:00
gen_kheaders.sh
groups.c
hung_task.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
iomem.c
irq_work.c
jump_label.c jump_label: Fix jump_label_text_reserved() vs __init 2021-07-20 16:05:58 +02:00
kallsyms.c
kcmp.c
Kconfig.freezer
Kconfig.hz
Kconfig.locks
Kconfig.preempt
kcov.c
kexec_core.c
kexec_elf.c
kexec_file.c kernel: kexec_file: fix error return code of kexec_calculate_store_digests() 2021-05-19 10:13:09 +02:00
kexec_internal.h
kexec.c
kheaders.c
kmod.c
kprobes.c
ksysfs.c
kthread.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
latencytop.c
Makefile init: add dsm gpl source 2024-07-05 18:00:04 +02:00
module_signature.c module: harden ELF info handling 2021-03-25 09:04:11 +01:00
module_signing.c module: harden ELF info handling 2021-03-25 09:04:11 +01:00
module-internal.h
module.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
notifier.c
nsproxy.c
padata.c
panic.c
params.c
pid_namespace.c
pid.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
profile.c
ptrace.c ptrace: make ptrace() fail if the tracee changed its pid unexpectedly 2021-05-26 12:06:49 +02:00
range.c
reboot.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
regset.c
relay.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
resource.c kernel/resource: make walk_mem_res() find all busy IORESOURCE_MEM resources 2021-05-19 10:13:09 +02:00
rseq.c
scftorture.c
scs.c
seccomp.c seccomp: Fix setting loaded filter count during TSYNC 2024-07-05 18:53:59 +02:00
signal.c
smp.c smp: Fix smp_call_function_single_async prototype 2021-05-14 09:50:46 +02:00
smpboot.c sched/core: Initialize the idle task with preemption disabled 2021-07-14 16:55:50 +02:00
smpboot.h
softirq.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
stackleak.c
stacktrace.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
static_call.c static_call: Fix unused variable warn w/o MODULE 2024-07-05 19:04:17 +02:00
stop_machine.c
syno_bootargs.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
syno-module-internal.h init: add dsm gpl source 2024-07-05 18:00:04 +02:00
sys_ni.c
sys.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
sysctl-test.c
sysctl.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
task_work.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
taskstats.c
test_kprobes.c
torture.c
tracepoint.c tracepoint: Use rcu get state and cond sync for static call updates 2024-07-05 19:01:27 +02:00
tsacct.c
ucount.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
uid16.c
uid16.h
umh.c
up.c smp: Fix smp_call_function_single_async prototype 2021-05-14 09:50:46 +02:00
user_namespace.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
user-return-notifier.c
user.c
usermode_driver.c bpf: Fix umd memory leak in copy_process() 2021-03-30 14:32:03 +02:00
utsname_sysctl.c
utsname.c
watch_queue.c
watchdog_hld.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
watchdog.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
workqueue_internal.h init: add dsm gpl source 2024-07-05 18:00:04 +02:00
workqueue.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00
workstat.c init: add dsm gpl source 2024-07-05 18:00:04 +02:00