Ubuntu-focal-kernel/kernel
Luis Gerhorst a49eb128bf bpf: Fix pointer-leak due to insufficient speculative store bypass mitigation
BugLink: https://bugs.launchpad.net/bugs/2011226

[ Upstream commit e4f4db47794c9f474b184ee1418f42e6a07412b6 ]

To mitigate Spectre v4, 2039f26f3a ("bpf: Fix leakage due to
insufficient speculative store bypass mitigation") inserts lfence
instructions after 1) initializing a stack slot and 2) spilling a
pointer to the stack.

However, this does not cover cases where a stack slot is first
initialized with a pointer (subject to sanitization) but then
overwritten with a scalar (not subject to sanitization because
the slot was already initialized). In this case, the second write
may be subject to speculative store bypass (SSB) creating a
speculative pointer-as-scalar type confusion. This allows the
program to subsequently leak the numerical pointer value using,
for example, a branch-based cache side channel.

To fix this, also sanitize scalars if they write a stack slot
that previously contained a pointer. Assuming that pointer-spills
are only generated by LLVM on register-pressure, the performance
impact on most real-world BPF programs should be small.

The following unprivileged BPF bytecode drafts a minimal exploit
and the mitigation:

  [...]
  // r6 = 0 or 1 (skalar, unknown user input)
  // r7 = accessible ptr for side channel
  // r10 = frame pointer (fp), to be leaked
  //
  r9 = r10 # fp alias to encourage ssb
  *(u64 *)(r9 - 8) = r10 // fp[-8] = ptr, to be leaked
  // lfence added here because of pointer spill to stack.
  //
  // Ommitted: Dummy bpf_ringbuf_output() here to train alias predictor
  // for no r9-r10 dependency.
  //
  *(u64 *)(r10 - 8) = r6 // fp[-8] = scalar, overwrites ptr
  // 2039f26f3aca: no lfence added because stack slot was not STACK_INVALID,
  // store may be subject to SSB
  //
  // fix: also add an lfence when the slot contained a ptr
  //
  r8 = *(u64 *)(r9 - 8)
  // r8 = architecturally a scalar, speculatively a ptr
  //
  // leak ptr using branch-based cache side channel:
  r8 &= 1 // choose bit to leak
  if r8 == 0 goto SLOW // no mispredict
  // architecturally dead code if input r6 is 0,
  // only executes speculatively iff ptr bit is 1
  r8 = *(u64 *)(r7 + 0) # encode bit in cache (0: slow, 1: fast)
SLOW:
  [...]

After running this, the program can time the access to *(r7 + 0) to
determine whether the chosen pointer bit was 0 or 1. Repeat this 64
times to recover the whole address on amd64.

In summary, sanitization can only be skipped if one scalar is
overwritten with another scalar. Scalar-confusion due to speculative
store bypass can not lead to invalid accesses because the pointer
bounds deducted during verification are enforced using branchless
logic. See 979d63d50c ("bpf: prevent out of bounds speculation on
pointer arithmetic") for details.

Do not make the mitigation depend on !env->allow_{uninit_stack,ptr_leaks}
because speculative leaks are likely unexpected if these were enabled.
For example, leaking the address to a protected log file may be acceptable
while disabling the mitigation might unintentionally leak the address
into the cached-state of a map that is accessible to unprivileged
processes.

Fixes: 2039f26f3a ("bpf: Fix leakage due to insufficient speculative store bypass mitigation")
Signed-off-by: Luis Gerhorst <gerhorst@cs.fau.de>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Henriette Hofmeier <henriette.hofmeier@rub.de>
Link: https://lore.kernel.org/bpf/edc95bad-aada-9cfc-ffe2-fa9bb206583c@cs.fau.de
Link: https://lore.kernel.org/bpf/20230109150544.41465-1-gerhorst@cs.fau.de
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Luke Nowakowski-Krijger <luke.nowakowskikrijger@canonical.com>
Acked-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
2023-03-21 10:08:57 +01:00
..
bpf bpf: Fix pointer-leak due to insufficient speculative store bypass mitigation 2023-03-21 10:08:57 +01:00
cgroup memcg: fix possible use-after-free in memcg_write_event_control() 2023-02-01 15:21:53 +01:00
configs
debug UBUNTU: SAUCE: debug: Lock down kgdb 2022-05-21 11:27:20 -03:00
dma dma-debug: make things less spammy under memory pressure 2022-08-26 11:10:39 +02:00
events perf: Fix possible memleak in pmu_dev_alloc() 2023-02-01 15:22:13 +01:00
gcov gcov: add support for checksum field 2023-02-01 15:23:18 +01:00
irq genirq/irqdesc: Don't try to remove non-existing sysfs files 2023-02-01 15:22:15 +01:00
livepatch livepatch: fix race between fork and KLP transition 2023-01-06 08:43:53 -08:00
locking locking/lockdep: Avoid RCU-induced noinstr fail 2022-01-13 18:42:05 +01:00
power PM: hibernate: Fix mistake in kerneldoc comment 2023-02-01 15:22:13 +01:00
printk printk: fix return value of printk.devkmsg __setup handler 2022-05-20 15:18:43 +02:00
rcu rcu: Fix __this_cpu_read() lockdep warning in rcu_force_quiescent_state() 2023-02-01 15:23:09 +01:00
sched sched/deadline: Fix priority inheritance with multiple scheduling classes 2022-10-17 15:02:09 +02:00
time timekeeping: contribute wall clock to rng on time change 2022-10-17 15:01:30 +02:00
trace tracing: Fix infinite loop in tracing_read_pipe on overflowed print_trace_line 2023-02-01 15:23:25 +01:00
.gitignore kbuild: update config_data.gz only when the content of .config is changed 2021-05-19 10:59:49 +02:00
Kconfig.freezer
Kconfig.hz
Kconfig.locks
Kconfig.preempt
Makefile kbuild: update config_data.gz only when the content of .config is changed 2021-05-19 10:59:49 +02:00
acct.c acct: fix potential integer overflow in encode_comp_t() 2023-02-01 15:23:09 +01:00
async.c Revert "module, async: async_synchronize_full() on module init iff async is used" 2022-04-14 11:32:16 +02:00
audit.c audit: improve audit queue handling when "audit=1" on cmdline 2022-03-29 09:13:56 +02:00
audit.h audit: log AUDIT_TIME_* records only from rules 2022-05-20 15:18:33 +02:00
audit_fsnotify.c audit: fix potential double free on error path from fsnotify_add_inode_mark 2022-10-17 15:02:07 +02:00
audit_tree.c audit: move put_tree() to avoid trim_trees refcount underflow and UAF 2021-10-01 11:31:10 +02:00
audit_watch.c audit: CONFIG_CHANGE don't log internal bookkeeping as an event 2020-11-09 14:47:30 +01:00
auditfilter.c audit: fix a net reference leak in audit_list_rules_send() 2020-08-08 01:53:12 -04:00
auditsc.c audit: log AUDIT_TIME_* records only from rules 2022-05-20 15:18:33 +02:00
backtracetest.c
bounds.c
capability.c
compat.c
configs.c
context_tracking.c
cpu.c random: clear fast pool, crng, and batches in cpuhp bring up 2022-08-26 11:10:11 +02:00
cpu_pm.c kernel/cpu_pm: Fix uninitted local in cpu_pm 2020-08-08 01:53:12 -04:00
crash_core.c
crash_dump.c
cred.c keys: Fix request_key() cache 2020-01-30 16:24:47 +01:00
delayacct.c
dma.c
exec_domain.c
exit.c don't dump the threads that had been already exiting when zapped. 2020-12-10 12:06:38 +01:00
extable.c
fail_function.c fail_function: Remove a redundant mutex unlock 2021-01-20 14:24:22 +01:00
fork.c copy_process(): Move fd_install() out of sighand->siglock critical section 2022-04-14 11:32:25 +02:00
freezer.c Revert "libata, freezer: avoid block device removal while system is frozen" 2019-10-06 09:11:37 -06:00
futex.c mm, futex: fix shared futex pgoff on shmem huge page 2021-08-13 09:44:31 +02:00
gen_kheaders.sh kbuild: add variables for compression tools 2020-09-16 05:15:01 -04:00
groups.c
hung_task.c
iomem.c
irq_work.c
jump_label.c jump_label: Fix usage in module __init 2021-11-25 12:09:02 +01:00
kallsyms.c kallsyms: Refactor kallsyms_show_value() to take cred 2020-08-08 01:53:12 -04:00
kcmp.c exec: Transform exec_update_mutex into a rw_semaphore 2021-02-19 16:43:34 +01:00
kcov.c
kexec.c
kexec_core.c kernel: kexec: remove the lock operation of system_transition_mutex 2021-03-24 11:11:19 +01:00
kexec_elf.c
kexec_file.c kexec_file: drop weak attribute from arch_kexec_apply_relocations[_add] 2022-08-26 11:11:25 +02:00
kexec_internal.h
kheaders.c
kmod.c kmod: make request_module() return an error when autoloading is disabled 2020-05-05 12:32:22 +02:00
kprobes.c kprobes: Skip clearing aggrprobe's post_handler in kprobe-on-ftrace case 2023-02-01 15:21:17 +01:00
ksysfs.c
kthread.c kthread: Fix PF_KTHREAD vs to_kthread() race 2021-10-01 11:33:59 +02:00
latencytop.c
module-internal.h
module.c module/ftrace: handle patchable-function-entry 2022-04-14 11:32:17 +02:00
module_signature.c module: harden ELF info handling 2021-04-23 11:58:31 +02:00
module_signing.c module: harden ELF info handling 2021-04-23 11:58:31 +02:00
notifier.c kernel/notifier.c: intercept duplicate registrations to avoid infinite loops 2020-11-09 14:47:25 +01:00
nsproxy.c
padata.c padata: add separate cpuhp node for CPUHP_PADATA_DEAD 2020-08-08 01:53:12 -04:00
panic.c panic: ensure preemption is disabled during panic() 2019-10-07 15:47:19 -07:00
params.c
pid.c
pid_namespace.c memcg: enable accounting for pids in nested pid namespaces 2021-10-12 16:31:40 -06:00
profile.c profiling: fix shift too large makes kernel panic 2022-10-17 15:01:11 +02:00
ptrace.c ptrace: Reimplement PTRACE_KILL by always sending SIGKILL 2022-08-26 11:07:09 +02:00
range.c
reboot.c Revert "PM: ACPI: reboot: Use S5 for reboot" 2022-04-14 11:32:31 +02:00
relay.c relay: fix type mismatch when allocating memory in relay_create_buf() 2023-02-01 15:22:18 +01:00
resource.c /dev/mem: Revoke mappings when a driver claims the region 2020-08-08 01:53:12 -04:00
rseq.c
seccomp.c seccomp: Invalidate seccomp mode to catch death failures 2022-04-14 11:32:10 +02:00
signal.c signal handling: don't use BUG_ON() for debugging 2022-09-16 10:59:30 +02:00
smp.c smp: Fix offline cpu check in flush_smp_call_function_queue() 2022-06-22 14:50:41 +02:00
smpboot.c kthread: Extract KTHREAD_IS_PER_CPU 2021-03-24 11:11:35 +01:00
smpboot.h
softirq.c
stackleak.c
stacktrace.c stacktrace: Don't skip first entry on noncurrent tasks 2019-11-04 21:19:25 +01:00
stop_machine.c stop_machine: Avoid potential race behaviour 2019-10-17 12:47:12 +02:00
sys.c prlimit: do_prlimit needs to have a speculation check 2023-03-21 10:08:55 +01:00
sys_ni.c kernel/sys_ni: add compat entry for fadvise64_64 2022-10-17 15:02:07 +02:00
sysctl-test.c kernel/sysctl-test: Add null pointer test for sysctl.c:proc_dointvec() 2020-11-09 14:47:16 +01:00
sysctl.c proc: proc_skip_spaces() shouldn't think it is working on C strings 2023-02-01 15:21:48 +01:00
sysctl_binary.c
task_work.c UBUNTU: SAUCE: import aufs driver 2019-11-25 14:56:45 +01:00
taskstats.c taskstats: fix data-race 2020-01-30 16:21:42 +01:00
test_kprobes.c
torture.c
tracepoint.c tracepoint: Add tracepoint_probe_register_may_exist() for BPF tracing 2021-08-13 09:44:55 +02:00
tsacct.c taskstats: Cleanup the use of task->exit_code 2022-04-14 11:32:19 +02:00
ucount.c
uid16.c
uid16.h
umh.c usermodehelper: reset umask to default before executing user process 2020-11-09 14:48:17 +01:00
up.c smp: Fix smp_call_function_single_async prototype 2021-05-26 15:39:25 +02:00
user-return-notifier.c
user.c
user_namespace.c UBUNTU: SAUCE: add a sysctl to disable unprivileged user namespace unsharing 2019-11-25 14:56:26 +01:00
utsname.c
utsname_sysctl.c
watchdog.c watchdog: export lockup_detector_reconfigure 2022-10-17 15:02:02 +02:00
watchdog_hld.c
workqueue.c workqueue: don't skip lockdep work dependency in cancel_work_sync() 2022-11-24 10:28:53 +01:00
workqueue_internal.h