1 /* Copyright (C) 2018-2019 Björn Esser <besser82@fedoraproject.org>
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted.
5 *
6 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
7 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
9 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
10 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
11 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
14 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
15 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
16 * SUCH DAMAGE.
17 */
18
19 #include "crypt-port.h"
20
21 #if INCLUDE_explicit_bzero
22 /* As long as this function is defined in a translation unit all by
23 itself, and we aren't doing LTO, it would be enough for it to just
24 call memset. While compiling _this_ translation unit, the compiler
25 has no information about what the callers do with the buffer, so it
26 cannot eliminate the memset. While compiling code that _calls_
27 this function, the compiler doesn't know what it does, so it cannot
28 eliminate the call (if it has special knowledge of a function with
29 this name, we would hope that it knows _not_ to optimize it out!)
30
31 However, in anticipation of doing LTO on this library one day, we
32 add two more defensive measures, when we know how: the function is
33 marked no-inline, and there is a no-op assembly insert immediately
34 after the memset call, declared to read the memory that the memset
35 writes. */
36
37 #if defined __GNUC__ && __GNUC__ >= 3
38 /* This construct is known to work with GCC and *probably* also works
39 with clang. It uses a VLA, which is normally forbidden in
40 libxcrypt, but not in a way that can cause arbitrarily large stack
41 allocations (which is *why* they are forbidden); disable the error
42 for this file only. */
43
44 # define OBSERVE_MEM(s, len) \
45 asm volatile ("" : : "m" (*(const char (*)[len]) s))
46
47 # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
48 # pragma GCC diagnostic ignored "-Wvla"
49 # elif defined __clang_major__ && __clang_major__ >= 4
50 # pragma clang diagnostic ignored "-Wvla"
51 # endif
52
53 #else
54 # error "Don't know how to observe memory access"
55 #endif
56
57 NO_INLINE void
58 explicit_bzero (void *s, size_t len)
59 {
60 memset (s, 0, len);
61 OBSERVE_MEM (s, len);
62 }
63 #endif