An error occurred while fetching folder content.
lib: memzero_explicit: use barrier instead of OPTIMIZER_HIDE_VAR
mancha security authored
commit 0b053c95 upstream.

OPTIMIZER_HIDE_VAR(), as defined when using gcc, is insufficient to
ensure protection from dead store optimization.

For the random driver and crypto drivers, calls are emitted ...

  $ gdb vmlinux
  (gdb) disassemble memzero_explicit
  Dump of assembler code for function memzero_explicit:
    0xffffffff813a18b0 <+0>:	push   %rbp
    0xffffffff813a18b1 <+1>:	mov    %rsi,%rdx
    0xffffffff813a18b4 <+4>:	xor    %esi,%esi
    0xffffffff813a18b6 <+6>:	mov    %rsp,%rbp
    0xffffffff813a18b9 <+9>:	callq  0xffffffff813a7120 <memset>
    0xffffffff813a18be <+14>:	pop    %rbp
    0xffffffff813a18bf <+15>:	retq
  End of assembler dump.

  (gdb) disassemble extract_entropy
  [...]
    0xffffffff814a5009 <+313>:	mov    %r12,%rdi
    0xffffffff814a500c <+316>:	mov    $0xa,%esi
    0xffffffff814a5011 <+321>:	callq  0xffffffff813a18b0 <memzero_explicit>
    0xffffffff814a5016 <+326>:	mov    -0x48(%rbp),%rax
  [...]

... but in case in future we might use facilities such as LTO, then
OPTIMIZER_HIDE_VAR() is not sufficient to protect gcc from a possible
eviction of the memset(). We have to use a compiler barrier instead.

Minimal test example when we assume memzero_explicit() would *not* be
a call, but would have been *inlined* instead:

  static inline void memzero_explicit(void *s, size_t count)
  {
    memset(s, 0, count);
    <foo>
  }

  int main(void)
  {
    char buff[20];

    snprintf(buff, sizeof(buff) - 1, "test");
    printf("%s", buff);

    memzero_explicit(buff, sizeof(buff));
    return 0;
  }

With <foo> := OPTIMIZER_HIDE_VAR():

  (gdb) disassemble main
  Dump of assembler code for function main:
  [...]
   0x0000000000400464 <+36>:	callq  0x400410 <printf@plt>
   0x0000000000400469 <+41>:	xor    %eax,%eax
   0x000000000040046b <+43>:	add    $0x28,%rsp
   0x000000000040046f <+47>:	retq
  End of assembler dump.

With <foo> := barrier():

  (gdb) disassemble main
  Dump of assembler code for function main:
  [...]
   0x0000000000400464 <+36>:	callq  0x400410 <printf@plt>
   0x0000000000400469 <+41>:	movq   $0x0,(%rsp)
   0x0000000000400471 <+49>:	movq   $0x0,0x8(%rsp)
   0x000000000040047a <+58>:	movl   $0x0,0x10(%rsp)
   0x0000000000400482 <+66>:	xor    %eax,%eax
   0x0000000000400484 <+68>:	add    $0x28,%rsp
   0x0000000000400488 <+72>:	retq
  End of assembler dump.

As can be seen, movq, movq, movl are being emitted inlined
via memset().

Reference: http://thread.gmane.org/gmane.linux.kernel.cryptoapi/13764/
Fixes: d4c5efdb

 ("random: add and use memzero_explicit() for clearing data")
Cc: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: default avatarmancha security <mancha1@zoho.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarHannes Frederic Sowa <hannes@stressinduktion.org>
Acked-by: default avatarStephan Mueller <smueller@chronox.de>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
e60e4dc0
Name Last commit Last update
..
lzo lzo: check for length overrun in variable length encoding.
mpi lib/mpi/mpicoder.c: looping issue, need stop when equal to zero, found by 'EXTRA_FLAGS=-W'.
raid6 lib/raid6: build proper files on corresponding arch
reed_solomon lib: Remove unnecessary inclusions of asm/semaphore.h
xz decompressors: fix typo "POWERPC"
zlib_deflate zlib: slim down zlib_deflate() workspace when possible
zlib_inflate inflate_fast: sout is already a short so ptr arith was off by one.
.gitignore X.509: Implement simple static OID registry
Kconfig Move utf16 functions to kernel core and rename
Kconfig.debug lib/Kconfig.debug: Restrict FRAME_POINTER for MIPS
Kconfig.kgdb Merge tag 'for_linux-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/kgdb
Kconfig.kmemcheck kmemcheck: depend on HAVE_ARCH_KMEMCHECK
Makefile x86, hweight: Fix BUG when booting with CONFIG_GCOV_PROFILE_ALL=y
argv_split.c argv_split(): teach it to handle mutable strings
asn1_decoder.c Merge tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux
atomic64.c lib: atomic64: Initialize locks statically to fix early users
atomic64_test.c atomic64_test: simplify the #ifdef for atomic64_dec_if_positive() test
audit.c audit: support the "standard" <asm-generic/unistd.h>
average.c lib: reduce the use of module.h wherever possible
bcd.c usb/core: use bin2bcd() for bcdDevice in RH
bch.c lib: add shared BCH ECC library
bitmap.c lib/bitmap.c: fix undefined shift in __bitmap_shift_{left|right}()
bitrev.c lib: export bitrev16
bsearch.c lib: reduce the use of module.h wherever possible
btree.c lib/btree.c: fix leak of whole btree nodes
bug.c
build_OID_registry
bust_spinlocks.c
check_signature.c
checksum.c
clz_tab.c
cmdline.c
cordic.c
cpu-notifier-error-inject.c
cpu_rmap.c
cpumask.c
crc-ccitt.c
crc-itu-t.c
crc-t10dif.c
crc16.c
crc32.c
crc32defs.h
crc7.c
crc8.c
ctype.c
debug_locks.c
debugobjects.c
dec_and_lock.c
decompress.c
decompress_bunzip2.c
decompress_inflate.c
decompress_unlzma.c
decompress_unlzo.c
decompress_unxz.c
devres.c
digsig.c
div64.c
dma-debug.c
dump_stack.c
dynamic_debug.c
dynamic_queue_limits.c
earlycpio.c
extable.c
fault-inject.c
fdt.c
fdt_ro.c
fdt_rw.c
fdt_strerror.c
fdt_sw.c
fdt_wip.c
find_last_bit.c
find_next_bit.c
flex_array.c
flex_proportions.c
gcd.c
gen_crc32table.c
genalloc.c
halfmd4.c
hexdump.c
hweight.c
idr.c
inflate.c
int_sqrt.c
interval_tree.c
interval_tree_test_main.c
iomap.c
iomap_copy.c
iommu-helper.c
ioremap.c
iovec.c
irq_regs.c
is_single_threaded.c
jedec_ddr_data.c
kasprintf.c
kfifo.c
klist.c
kobject.c
kobject_uevent.c
kstrtox.c
kstrtox.h