1*33772c1eSriastradh #ifndef __STDC_WANT_LIB_EXT1__
2*33772c1eSriastradh # define __STDC_WANT_LIB_EXT1__ 1
3*33772c1eSriastradh #endif
4*33772c1eSriastradh #include <assert.h>
5*33772c1eSriastradh #include <errno.h>
6*33772c1eSriastradh #include <limits.h>
7*33772c1eSriastradh #include <signal.h>
8*33772c1eSriastradh #include <stddef.h>
9*33772c1eSriastradh #include <stdint.h>
10*33772c1eSriastradh #include <stdlib.h>
11*33772c1eSriastradh #include <string.h>
12*33772c1eSriastradh 
13*33772c1eSriastradh #ifdef HAVE_SYS_MMAN_H
14*33772c1eSriastradh # include <sys/mman.h>
15*33772c1eSriastradh #endif
16*33772c1eSriastradh 
17*33772c1eSriastradh #ifdef _WIN32
18*33772c1eSriastradh # include <windows.h>
19*33772c1eSriastradh # include <wincrypt.h>
20*33772c1eSriastradh #else
21*33772c1eSriastradh # include <unistd.h>
22*33772c1eSriastradh #endif
23*33772c1eSriastradh 
24*33772c1eSriastradh #ifndef HAVE_C_VARARRAYS
25*33772c1eSriastradh # ifdef HAVE_ALLOCA_H
26*33772c1eSriastradh #  include <alloca.h>
27*33772c1eSriastradh # elif !defined(alloca)
28*33772c1eSriastradh #  if defined(__GNUC__)
29*33772c1eSriastradh #   define alloca __builtin_alloca
30*33772c1eSriastradh #  elif defined _AIX
31*33772c1eSriastradh #   define alloca __alloca
32*33772c1eSriastradh #  elif defined _MSC_VER
33*33772c1eSriastradh #   include <malloc.h>
34*33772c1eSriastradh #   define alloca _alloca
35*33772c1eSriastradh #  else
36*33772c1eSriastradh #   include <stddef.h>
37*33772c1eSriastradh #   ifdef  __cplusplus
38*33772c1eSriastradh extern "C"
39*33772c1eSriastradh #   endif
40*33772c1eSriastradh void *alloca (size_t);
41*33772c1eSriastradh #  endif
42*33772c1eSriastradh # endif
43*33772c1eSriastradh #endif
44*33772c1eSriastradh 
45*33772c1eSriastradh #include "core.h"
46*33772c1eSriastradh #include "randombytes.h"
47*33772c1eSriastradh #include "utils.h"
48*33772c1eSriastradh 
49*33772c1eSriastradh #ifndef ENOSYS
50*33772c1eSriastradh # define ENOSYS ENXIO
51*33772c1eSriastradh #endif
52*33772c1eSriastradh 
53*33772c1eSriastradh #if defined(_WIN32) && \
54*33772c1eSriastradh     (!defined(WINAPI_FAMILY) || WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
55*33772c1eSriastradh # define WINAPI_DESKTOP
56*33772c1eSriastradh #endif
57*33772c1eSriastradh 
58*33772c1eSriastradh #define CANARY_SIZE 16U
59*33772c1eSriastradh #define GARBAGE_VALUE 0xdb
60*33772c1eSriastradh 
61*33772c1eSriastradh #ifndef MAP_NOCORE
62*33772c1eSriastradh # define MAP_NOCORE 0
63*33772c1eSriastradh #endif
64*33772c1eSriastradh #if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
65*33772c1eSriastradh # define MAP_ANON MAP_ANONYMOUS
66*33772c1eSriastradh #endif
67*33772c1eSriastradh #if defined(WINAPI_DESKTOP) || (defined(MAP_ANON) && defined(HAVE_MMAP)) || \
68*33772c1eSriastradh     defined(HAVE_POSIX_MEMALIGN)
69*33772c1eSriastradh # define HAVE_ALIGNED_MALLOC
70*33772c1eSriastradh #endif
71*33772c1eSriastradh #if defined(HAVE_MPROTECT) && \
72*33772c1eSriastradh     !(defined(PROT_NONE) && defined(PROT_READ) && defined(PROT_WRITE))
73*33772c1eSriastradh # undef HAVE_MPROTECT
74*33772c1eSriastradh #endif
75*33772c1eSriastradh #if defined(HAVE_ALIGNED_MALLOC) && \
76*33772c1eSriastradh     (defined(WINAPI_DESKTOP) || defined(HAVE_MPROTECT))
77*33772c1eSriastradh # define HAVE_PAGE_PROTECTION
78*33772c1eSriastradh #endif
79*33772c1eSriastradh #if !defined(MADV_DODUMP) && defined(MADV_CORE)
80*33772c1eSriastradh # define MADV_DODUMP   MADV_CORE
81*33772c1eSriastradh # define MADV_DONTDUMP MADV_NOCORE
82*33772c1eSriastradh #endif
83*33772c1eSriastradh 
84*33772c1eSriastradh static size_t        page_size;
85*33772c1eSriastradh static unsigned char canary[CANARY_SIZE];
86*33772c1eSriastradh 
87*33772c1eSriastradh /* LCOV_EXCL_START */
88*33772c1eSriastradh #ifdef HAVE_WEAK_SYMBOLS
89*33772c1eSriastradh __attribute__((weak)) void
90*33772c1eSriastradh _sodium_dummy_symbol_to_prevent_memzero_lto(void *const  pnt,
91*33772c1eSriastradh                                             const size_t len);
92*33772c1eSriastradh __attribute__((weak)) void
_sodium_dummy_symbol_to_prevent_memzero_lto(void * const pnt,const size_t len)93*33772c1eSriastradh _sodium_dummy_symbol_to_prevent_memzero_lto(void *const  pnt,
94*33772c1eSriastradh                                             const size_t len)
95*33772c1eSriastradh {
96*33772c1eSriastradh     (void) pnt; /* LCOV_EXCL_LINE */
97*33772c1eSriastradh     (void) len; /* LCOV_EXCL_LINE */
98*33772c1eSriastradh }
99*33772c1eSriastradh #endif
100*33772c1eSriastradh /* LCOV_EXCL_STOP */
101*33772c1eSriastradh 
102*33772c1eSriastradh void
sodium_memzero(void * const pnt,const size_t len)103*33772c1eSriastradh sodium_memzero(void *const pnt, const size_t len)
104*33772c1eSriastradh {
105*33772c1eSriastradh #ifdef _WIN32
106*33772c1eSriastradh     SecureZeroMemory(pnt, len);
107*33772c1eSriastradh #elif defined(HAVE_MEMSET_S)
108*33772c1eSriastradh     if (len > 0U && memset_s(pnt, (rsize_t) len, 0, (rsize_t) len) != 0) {
109*33772c1eSriastradh         sodium_misuse(); /* LCOV_EXCL_LINE */
110*33772c1eSriastradh     }
111*33772c1eSriastradh #elif defined(HAVE_EXPLICIT_BZERO)
112*33772c1eSriastradh     explicit_bzero(pnt, len);
113*33772c1eSriastradh #elif HAVE_WEAK_SYMBOLS
114*33772c1eSriastradh     memset(pnt, 0, len);
115*33772c1eSriastradh     _sodium_dummy_symbol_to_prevent_memzero_lto(pnt, len);
116*33772c1eSriastradh # ifdef HAVE_AMD64_ASM
117*33772c1eSriastradh     __asm__ __volatile__ ("" : : "p"(pnt));
118*33772c1eSriastradh # endif
119*33772c1eSriastradh #else
120*33772c1eSriastradh     volatile unsigned char *volatile pnt_ =
121*33772c1eSriastradh         (volatile unsigned char *volatile) pnt;
122*33772c1eSriastradh     size_t i = (size_t) 0U;
123*33772c1eSriastradh 
124*33772c1eSriastradh     while (i < len) {
125*33772c1eSriastradh         pnt_[i++] = 0U;
126*33772c1eSriastradh     }
127*33772c1eSriastradh #endif
128*33772c1eSriastradh }
129*33772c1eSriastradh 
130*33772c1eSriastradh void
sodium_stackzero(const size_t len)131*33772c1eSriastradh sodium_stackzero(const size_t len)
132*33772c1eSriastradh {
133*33772c1eSriastradh #ifdef HAVE_C_VARARRAYS
134*33772c1eSriastradh     unsigned char fodder[len];
135*33772c1eSriastradh     sodium_memzero(fodder, len);
136*33772c1eSriastradh #elif HAVE_ALLOCA
137*33772c1eSriastradh     sodium_memzero(alloca(len), len);
138*33772c1eSriastradh #endif
139*33772c1eSriastradh }
140*33772c1eSriastradh 
141*33772c1eSriastradh #ifdef HAVE_WEAK_SYMBOLS
142*33772c1eSriastradh __attribute__((weak)) void
143*33772c1eSriastradh _sodium_dummy_symbol_to_prevent_memcmp_lto(const unsigned char *b1,
144*33772c1eSriastradh                                            const unsigned char *b2,
145*33772c1eSriastradh                                            const size_t         len);
146*33772c1eSriastradh __attribute__((weak)) void
_sodium_dummy_symbol_to_prevent_memcmp_lto(const unsigned char * b1,const unsigned char * b2,const size_t len)147*33772c1eSriastradh _sodium_dummy_symbol_to_prevent_memcmp_lto(const unsigned char *b1,
148*33772c1eSriastradh                                            const unsigned char *b2,
149*33772c1eSriastradh                                            const size_t         len)
150*33772c1eSriastradh {
151*33772c1eSriastradh     (void) b1;
152*33772c1eSriastradh     (void) b2;
153*33772c1eSriastradh     (void) len;
154*33772c1eSriastradh }
155*33772c1eSriastradh #endif
156*33772c1eSriastradh 
157*33772c1eSriastradh int
sodium_memcmp(const void * const b1_,const void * const b2_,size_t len)158*33772c1eSriastradh sodium_memcmp(const void *const b1_, const void *const b2_, size_t len)
159*33772c1eSriastradh {
160*33772c1eSriastradh #ifdef HAVE_WEAK_SYMBOLS
161*33772c1eSriastradh     const unsigned char *b1 = (const unsigned char *) b1_;
162*33772c1eSriastradh     const unsigned char *b2 = (const unsigned char *) b2_;
163*33772c1eSriastradh #else
164*33772c1eSriastradh     const volatile unsigned char *volatile b1 =
165*33772c1eSriastradh         (const volatile unsigned char *volatile) b1_;
166*33772c1eSriastradh     const volatile unsigned char *volatile b2 =
167*33772c1eSriastradh         (const volatile unsigned char *volatile) b2_;
168*33772c1eSriastradh #endif
169*33772c1eSriastradh     size_t                 i;
170*33772c1eSriastradh     volatile unsigned char d = 0U;
171*33772c1eSriastradh 
172*33772c1eSriastradh #if HAVE_WEAK_SYMBOLS
173*33772c1eSriastradh     _sodium_dummy_symbol_to_prevent_memcmp_lto(b1, b2, len);
174*33772c1eSriastradh #endif
175*33772c1eSriastradh     for (i = 0U; i < len; i++) {
176*33772c1eSriastradh         d |= b1[i] ^ b2[i];
177*33772c1eSriastradh     }
178*33772c1eSriastradh     return (1 & ((d - 1) >> 8)) - 1;
179*33772c1eSriastradh }
180*33772c1eSriastradh 
181*33772c1eSriastradh #ifdef HAVE_WEAK_SYMBOLS
182*33772c1eSriastradh __attribute__((weak)) void
183*33772c1eSriastradh _sodium_dummy_symbol_to_prevent_compare_lto(const unsigned char *b1,
184*33772c1eSriastradh                                             const unsigned char *b2,
185*33772c1eSriastradh                                             const size_t         len);
186*33772c1eSriastradh __attribute__((weak)) void
_sodium_dummy_symbol_to_prevent_compare_lto(const unsigned char * b1,const unsigned char * b2,const size_t len)187*33772c1eSriastradh _sodium_dummy_symbol_to_prevent_compare_lto(const unsigned char *b1,
188*33772c1eSriastradh                                             const unsigned char *b2,
189*33772c1eSriastradh                                             const size_t         len)
190*33772c1eSriastradh {
191*33772c1eSriastradh     (void) b1;
192*33772c1eSriastradh     (void) b2;
193*33772c1eSriastradh     (void) len;
194*33772c1eSriastradh }
195*33772c1eSriastradh #endif
196*33772c1eSriastradh 
197*33772c1eSriastradh int
sodium_compare(const unsigned char * b1_,const unsigned char * b2_,size_t len)198*33772c1eSriastradh sodium_compare(const unsigned char *b1_, const unsigned char *b2_, size_t len)
199*33772c1eSriastradh {
200*33772c1eSriastradh #ifdef HAVE_WEAK_SYMBOLS
201*33772c1eSriastradh     const unsigned char *b1 = b1_;
202*33772c1eSriastradh     const unsigned char *b2 = b2_;
203*33772c1eSriastradh #else
204*33772c1eSriastradh     const volatile unsigned char *volatile b1 =
205*33772c1eSriastradh         (const volatile unsigned char *volatile) b1_;
206*33772c1eSriastradh     const volatile unsigned char *volatile b2 =
207*33772c1eSriastradh         (const volatile unsigned char *volatile) b2_;
208*33772c1eSriastradh #endif
209*33772c1eSriastradh     size_t                 i;
210*33772c1eSriastradh     volatile unsigned char gt = 0U;
211*33772c1eSriastradh     volatile unsigned char eq = 1U;
212*33772c1eSriastradh     uint16_t               x1, x2;
213*33772c1eSriastradh 
214*33772c1eSriastradh #if HAVE_WEAK_SYMBOLS
215*33772c1eSriastradh     _sodium_dummy_symbol_to_prevent_compare_lto(b1, b2, len);
216*33772c1eSriastradh #endif
217*33772c1eSriastradh     i = len;
218*33772c1eSriastradh     while (i != 0U) {
219*33772c1eSriastradh         i--;
220*33772c1eSriastradh         x1 = b1[i];
221*33772c1eSriastradh         x2 = b2[i];
222*33772c1eSriastradh         gt |= ((x2 - x1) >> 8) & eq;
223*33772c1eSriastradh         eq &= ((x2 ^ x1) - 1) >> 8;
224*33772c1eSriastradh     }
225*33772c1eSriastradh     return (int) (gt + gt + eq) - 1;
226*33772c1eSriastradh }
227*33772c1eSriastradh 
228*33772c1eSriastradh int
sodium_is_zero(const unsigned char * n,const size_t nlen)229*33772c1eSriastradh sodium_is_zero(const unsigned char *n, const size_t nlen)
230*33772c1eSriastradh {
231*33772c1eSriastradh     size_t                 i;
232*33772c1eSriastradh     volatile unsigned char d = 0U;
233*33772c1eSriastradh 
234*33772c1eSriastradh     for (i = 0U; i < nlen; i++) {
235*33772c1eSriastradh         d |= n[i];
236*33772c1eSriastradh     }
237*33772c1eSriastradh     return 1 & ((d - 1) >> 8);
238*33772c1eSriastradh }
239*33772c1eSriastradh 
240*33772c1eSriastradh void
sodium_increment(unsigned char * n,const size_t nlen)241*33772c1eSriastradh sodium_increment(unsigned char *n, const size_t nlen)
242*33772c1eSriastradh {
243*33772c1eSriastradh     size_t        i = 0U;
244*33772c1eSriastradh     uint_fast16_t c = 1U;
245*33772c1eSriastradh 
246*33772c1eSriastradh #ifdef HAVE_AMD64_ASM
247*33772c1eSriastradh     uint64_t t64, t64_2;
248*33772c1eSriastradh     uint32_t t32;
249*33772c1eSriastradh 
250*33772c1eSriastradh     if (nlen == 12U) {
251*33772c1eSriastradh         __asm__ __volatile__(
252*33772c1eSriastradh             "xorq %[t64], %[t64] \n"
253*33772c1eSriastradh             "xorl %[t32], %[t32] \n"
254*33772c1eSriastradh             "stc \n"
255*33772c1eSriastradh             "adcq %[t64], (%[out]) \n"
256*33772c1eSriastradh             "adcl %[t32], 8(%[out]) \n"
257*33772c1eSriastradh             : [t64] "=&r"(t64), [t32] "=&r"(t32)
258*33772c1eSriastradh             : [out] "D"(n)
259*33772c1eSriastradh             : "memory", "flags", "cc");
260*33772c1eSriastradh         return;
261*33772c1eSriastradh     } else if (nlen == 24U) {
262*33772c1eSriastradh         __asm__ __volatile__(
263*33772c1eSriastradh             "movq $1, %[t64] \n"
264*33772c1eSriastradh             "xorq %[t64_2], %[t64_2] \n"
265*33772c1eSriastradh             "addq %[t64], (%[out]) \n"
266*33772c1eSriastradh             "adcq %[t64_2], 8(%[out]) \n"
267*33772c1eSriastradh             "adcq %[t64_2], 16(%[out]) \n"
268*33772c1eSriastradh             : [t64] "=&r"(t64), [t64_2] "=&r"(t64_2)
269*33772c1eSriastradh             : [out] "D"(n)
270*33772c1eSriastradh             : "memory", "flags", "cc");
271*33772c1eSriastradh         return;
272*33772c1eSriastradh     } else if (nlen == 8U) {
273*33772c1eSriastradh         __asm__ __volatile__("incq (%[out]) \n"
274*33772c1eSriastradh                              :
275*33772c1eSriastradh                              : [out] "D"(n)
276*33772c1eSriastradh                              : "memory", "flags", "cc");
277*33772c1eSriastradh         return;
278*33772c1eSriastradh     }
279*33772c1eSriastradh #endif
280*33772c1eSriastradh     for (; i < nlen; i++) {
281*33772c1eSriastradh         c += (uint_fast16_t) n[i];
282*33772c1eSriastradh         n[i] = (unsigned char) c;
283*33772c1eSriastradh         c >>= 8;
284*33772c1eSriastradh     }
285*33772c1eSriastradh }
286*33772c1eSriastradh 
287*33772c1eSriastradh void
sodium_add(unsigned char * a,const unsigned char * b,const size_t len)288*33772c1eSriastradh sodium_add(unsigned char *a, const unsigned char *b, const size_t len)
289*33772c1eSriastradh {
290*33772c1eSriastradh     size_t        i = 0U;
291*33772c1eSriastradh     uint_fast16_t c = 0U;
292*33772c1eSriastradh 
293*33772c1eSriastradh #ifdef HAVE_AMD64_ASM
294*33772c1eSriastradh     uint64_t t64, t64_2, t64_3;
295*33772c1eSriastradh     uint32_t t32;
296*33772c1eSriastradh 
297*33772c1eSriastradh     if (len == 12U) {
298*33772c1eSriastradh         __asm__ __volatile__(
299*33772c1eSriastradh             "movq (%[in]), %[t64] \n"
300*33772c1eSriastradh             "movl 8(%[in]), %[t32] \n"
301*33772c1eSriastradh             "addq %[t64], (%[out]) \n"
302*33772c1eSriastradh             "adcl %[t32], 8(%[out]) \n"
303*33772c1eSriastradh             : [t64] "=&r"(t64), [t32] "=&r"(t32)
304*33772c1eSriastradh             : [in] "S"(b), [out] "D"(a)
305*33772c1eSriastradh             : "memory", "flags", "cc");
306*33772c1eSriastradh         return;
307*33772c1eSriastradh     } else if (len == 24U) {
308*33772c1eSriastradh         __asm__ __volatile__(
309*33772c1eSriastradh             "movq (%[in]), %[t64] \n"
310*33772c1eSriastradh             "movq 8(%[in]), %[t64_2] \n"
311*33772c1eSriastradh             "movq 16(%[in]), %[t64_3] \n"
312*33772c1eSriastradh             "addq %[t64], (%[out]) \n"
313*33772c1eSriastradh             "adcq %[t64_2], 8(%[out]) \n"
314*33772c1eSriastradh             "adcq %[t64_3], 16(%[out]) \n"
315*33772c1eSriastradh             : [t64] "=&r"(t64), [t64_2] "=&r"(t64_2), [t64_3] "=&r"(t64_3)
316*33772c1eSriastradh             : [in] "S"(b), [out] "D"(a)
317*33772c1eSriastradh             : "memory", "flags", "cc");
318*33772c1eSriastradh         return;
319*33772c1eSriastradh     } else if (len == 8U) {
320*33772c1eSriastradh         __asm__ __volatile__(
321*33772c1eSriastradh             "movq (%[in]), %[t64] \n"
322*33772c1eSriastradh             "addq %[t64], (%[out]) \n"
323*33772c1eSriastradh             : [t64] "=&r"(t64)
324*33772c1eSriastradh             : [in] "S"(b), [out] "D"(a)
325*33772c1eSriastradh             : "memory", "flags", "cc");
326*33772c1eSriastradh         return;
327*33772c1eSriastradh     }
328*33772c1eSriastradh #endif
329*33772c1eSriastradh     for (; i < len; i++) {
330*33772c1eSriastradh         c += (uint_fast16_t) a[i] + (uint_fast16_t) b[i];
331*33772c1eSriastradh         a[i] = (unsigned char) c;
332*33772c1eSriastradh         c >>= 8;
333*33772c1eSriastradh     }
334*33772c1eSriastradh }
335*33772c1eSriastradh 
336*33772c1eSriastradh int
_sodium_alloc_init(void)337*33772c1eSriastradh _sodium_alloc_init(void)
338*33772c1eSriastradh {
339*33772c1eSriastradh #ifdef HAVE_ALIGNED_MALLOC
340*33772c1eSriastradh # if defined(_SC_PAGESIZE)
341*33772c1eSriastradh     long page_size_ = sysconf(_SC_PAGESIZE);
342*33772c1eSriastradh     if (page_size_ > 0L) {
343*33772c1eSriastradh         page_size = (size_t) page_size_;
344*33772c1eSriastradh     }
345*33772c1eSriastradh # elif defined(WINAPI_DESKTOP)
346*33772c1eSriastradh     SYSTEM_INFO si;
347*33772c1eSriastradh     GetSystemInfo(&si);
348*33772c1eSriastradh     page_size = (size_t) si.dwPageSize;
349*33772c1eSriastradh # endif
350*33772c1eSriastradh     if (page_size < CANARY_SIZE || page_size < sizeof(size_t)) {
351*33772c1eSriastradh         sodium_misuse(); /* LCOV_EXCL_LINE */
352*33772c1eSriastradh     }
353*33772c1eSriastradh #endif
354*33772c1eSriastradh     randombytes_buf(canary, sizeof canary);
355*33772c1eSriastradh 
356*33772c1eSriastradh     return 0;
357*33772c1eSriastradh }
358*33772c1eSriastradh 
359*33772c1eSriastradh int
sodium_mlock(void * const addr,const size_t len)360*33772c1eSriastradh sodium_mlock(void *const addr, const size_t len)
361*33772c1eSriastradh {
362*33772c1eSriastradh #if defined(MADV_DONTDUMP) && defined(HAVE_MADVISE)
363*33772c1eSriastradh     (void) madvise(addr, len, MADV_DONTDUMP);
364*33772c1eSriastradh #endif
365*33772c1eSriastradh #ifdef HAVE_MLOCK
366*33772c1eSriastradh     return mlock(addr, len);
367*33772c1eSriastradh #elif defined(WINAPI_DESKTOP)
368*33772c1eSriastradh     return -(VirtualLock(addr, len) == 0);
369*33772c1eSriastradh #else
370*33772c1eSriastradh     errno = ENOSYS;
371*33772c1eSriastradh     return -1;
372*33772c1eSriastradh #endif
373*33772c1eSriastradh }
374*33772c1eSriastradh 
375*33772c1eSriastradh int
sodium_munlock(void * const addr,const size_t len)376*33772c1eSriastradh sodium_munlock(void *const addr, const size_t len)
377*33772c1eSriastradh {
378*33772c1eSriastradh     sodium_memzero(addr, len);
379*33772c1eSriastradh #if defined(MADV_DODUMP) && defined(HAVE_MADVISE)
380*33772c1eSriastradh     (void) madvise(addr, len, MADV_DODUMP);
381*33772c1eSriastradh #endif
382*33772c1eSriastradh #ifdef HAVE_MLOCK
383*33772c1eSriastradh     return munlock(addr, len);
384*33772c1eSriastradh #elif defined(WINAPI_DESKTOP)
385*33772c1eSriastradh     return -(VirtualUnlock(addr, len) == 0);
386*33772c1eSriastradh #else
387*33772c1eSriastradh     errno = ENOSYS;
388*33772c1eSriastradh     return -1;
389*33772c1eSriastradh #endif
390*33772c1eSriastradh }
391*33772c1eSriastradh 
392*33772c1eSriastradh static int
_mprotect_noaccess(void * ptr,size_t size)393*33772c1eSriastradh _mprotect_noaccess(void *ptr, size_t size)
394*33772c1eSriastradh {
395*33772c1eSriastradh #ifdef HAVE_MPROTECT
396*33772c1eSriastradh     return mprotect(ptr, size, PROT_NONE);
397*33772c1eSriastradh #elif defined(WINAPI_DESKTOP)
398*33772c1eSriastradh     DWORD old;
399*33772c1eSriastradh     return -(VirtualProtect(ptr, size, PAGE_NOACCESS, &old) == 0);
400*33772c1eSriastradh #else
401*33772c1eSriastradh     errno = ENOSYS;
402*33772c1eSriastradh     return -1;
403*33772c1eSriastradh #endif
404*33772c1eSriastradh }
405*33772c1eSriastradh 
406*33772c1eSriastradh static int
_mprotect_readonly(void * ptr,size_t size)407*33772c1eSriastradh _mprotect_readonly(void *ptr, size_t size)
408*33772c1eSriastradh {
409*33772c1eSriastradh #ifdef HAVE_MPROTECT
410*33772c1eSriastradh     return mprotect(ptr, size, PROT_READ);
411*33772c1eSriastradh #elif defined(WINAPI_DESKTOP)
412*33772c1eSriastradh     DWORD old;
413*33772c1eSriastradh     return -(VirtualProtect(ptr, size, PAGE_READONLY, &old) == 0);
414*33772c1eSriastradh #else
415*33772c1eSriastradh     errno = ENOSYS;
416*33772c1eSriastradh     return -1;
417*33772c1eSriastradh #endif
418*33772c1eSriastradh }
419*33772c1eSriastradh 
420*33772c1eSriastradh static int
_mprotect_readwrite(void * ptr,size_t size)421*33772c1eSriastradh _mprotect_readwrite(void *ptr, size_t size)
422*33772c1eSriastradh {
423*33772c1eSriastradh #ifdef HAVE_MPROTECT
424*33772c1eSriastradh     return mprotect(ptr, size, PROT_READ | PROT_WRITE);
425*33772c1eSriastradh #elif defined(WINAPI_DESKTOP)
426*33772c1eSriastradh     DWORD old;
427*33772c1eSriastradh     return -(VirtualProtect(ptr, size, PAGE_READWRITE, &old) == 0);
428*33772c1eSriastradh #else
429*33772c1eSriastradh     errno = ENOSYS;
430*33772c1eSriastradh     return -1;
431*33772c1eSriastradh #endif
432*33772c1eSriastradh }
433*33772c1eSriastradh 
434*33772c1eSriastradh #ifdef HAVE_ALIGNED_MALLOC
435*33772c1eSriastradh 
436*33772c1eSriastradh __attribute__((noreturn)) static void
_out_of_bounds(void)437*33772c1eSriastradh _out_of_bounds(void)
438*33772c1eSriastradh {
439*33772c1eSriastradh # ifdef SIGSEGV
440*33772c1eSriastradh     raise(SIGSEGV);
441*33772c1eSriastradh # elif defined(SIGKILL)
442*33772c1eSriastradh     raise(SIGKILL);
443*33772c1eSriastradh # endif
444*33772c1eSriastradh     abort(); /* not something we want any higher-level API to catch */
445*33772c1eSriastradh } /* LCOV_EXCL_LINE */
446*33772c1eSriastradh 
447*33772c1eSriastradh static inline size_t
_page_round(const size_t size)448*33772c1eSriastradh _page_round(const size_t size)
449*33772c1eSriastradh {
450*33772c1eSriastradh     const size_t page_mask = page_size - 1U;
451*33772c1eSriastradh 
452*33772c1eSriastradh     return (size + page_mask) & ~page_mask;
453*33772c1eSriastradh }
454*33772c1eSriastradh 
455*33772c1eSriastradh static __attribute__((malloc)) unsigned char *
_alloc_aligned(const size_t size)456*33772c1eSriastradh _alloc_aligned(const size_t size)
457*33772c1eSriastradh {
458*33772c1eSriastradh     void *ptr;
459*33772c1eSriastradh 
460*33772c1eSriastradh # if defined(MAP_ANON) && defined(HAVE_MMAP)
461*33772c1eSriastradh     if ((ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
462*33772c1eSriastradh                     MAP_ANON | MAP_PRIVATE | MAP_NOCORE, -1, 0)) ==
463*33772c1eSriastradh         MAP_FAILED) {
464*33772c1eSriastradh         ptr = NULL; /* LCOV_EXCL_LINE */
465*33772c1eSriastradh     }               /* LCOV_EXCL_LINE */
466*33772c1eSriastradh # elif defined(HAVE_POSIX_MEMALIGN)
467*33772c1eSriastradh     if (posix_memalign(&ptr, page_size, size) != 0) {
468*33772c1eSriastradh         ptr = NULL; /* LCOV_EXCL_LINE */
469*33772c1eSriastradh     }               /* LCOV_EXCL_LINE */
470*33772c1eSriastradh # elif defined(WINAPI_DESKTOP)
471*33772c1eSriastradh     ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
472*33772c1eSriastradh # else
473*33772c1eSriastradh #  error Bug
474*33772c1eSriastradh # endif
475*33772c1eSriastradh     return (unsigned char *) ptr;
476*33772c1eSriastradh }
477*33772c1eSriastradh 
478*33772c1eSriastradh static void
_free_aligned(unsigned char * const ptr,const size_t size)479*33772c1eSriastradh _free_aligned(unsigned char *const ptr, const size_t size)
480*33772c1eSriastradh {
481*33772c1eSriastradh # if defined(MAP_ANON) && defined(HAVE_MMAP)
482*33772c1eSriastradh     (void) munmap(ptr, size);
483*33772c1eSriastradh # elif defined(HAVE_POSIX_MEMALIGN)
484*33772c1eSriastradh     free(ptr);
485*33772c1eSriastradh # elif defined(WINAPI_DESKTOP)
486*33772c1eSriastradh     VirtualFree(ptr, 0U, MEM_RELEASE);
487*33772c1eSriastradh # else
488*33772c1eSriastradh #  error Bug
489*33772c1eSriastradh #endif
490*33772c1eSriastradh }
491*33772c1eSriastradh 
492*33772c1eSriastradh static unsigned char *
_unprotected_ptr_from_user_ptr(void * const ptr)493*33772c1eSriastradh _unprotected_ptr_from_user_ptr(void *const ptr)
494*33772c1eSriastradh {
495*33772c1eSriastradh     uintptr_t      unprotected_ptr_u;
496*33772c1eSriastradh     unsigned char *canary_ptr;
497*33772c1eSriastradh     size_t         page_mask;
498*33772c1eSriastradh 
499*33772c1eSriastradh     canary_ptr = ((unsigned char *) ptr) - sizeof canary;
500*33772c1eSriastradh     page_mask = page_size - 1U;
501*33772c1eSriastradh     unprotected_ptr_u = ((uintptr_t) canary_ptr & (uintptr_t) ~page_mask);
502*33772c1eSriastradh     if (unprotected_ptr_u <= page_size * 2U) {
503*33772c1eSriastradh         sodium_misuse(); /* LCOV_EXCL_LINE */
504*33772c1eSriastradh     }
505*33772c1eSriastradh     return (unsigned char *) unprotected_ptr_u;
506*33772c1eSriastradh }
507*33772c1eSriastradh 
508*33772c1eSriastradh #endif /* HAVE_ALIGNED_MALLOC */
509*33772c1eSriastradh 
510*33772c1eSriastradh #ifndef HAVE_ALIGNED_MALLOC
511*33772c1eSriastradh static __attribute__((malloc)) void *
_sodium_malloc(const size_t size)512*33772c1eSriastradh _sodium_malloc(const size_t size)
513*33772c1eSriastradh {
514*33772c1eSriastradh     return malloc(size > (size_t) 0U ? size : (size_t) 1U);
515*33772c1eSriastradh }
516*33772c1eSriastradh #else
517*33772c1eSriastradh static __attribute__((malloc)) void *
_sodium_malloc(const size_t size)518*33772c1eSriastradh _sodium_malloc(const size_t size)
519*33772c1eSriastradh {
520*33772c1eSriastradh     void          *user_ptr;
521*33772c1eSriastradh     unsigned char *base_ptr;
522*33772c1eSriastradh     unsigned char *canary_ptr;
523*33772c1eSriastradh     unsigned char *unprotected_ptr;
524*33772c1eSriastradh     size_t         size_with_canary;
525*33772c1eSriastradh     size_t         total_size;
526*33772c1eSriastradh     size_t         unprotected_size;
527*33772c1eSriastradh 
528*33772c1eSriastradh     if (size >= (size_t) SIZE_MAX - page_size * 4U) {
529*33772c1eSriastradh         errno = ENOMEM;
530*33772c1eSriastradh         return NULL;
531*33772c1eSriastradh     }
532*33772c1eSriastradh     if (page_size <= sizeof canary || page_size < sizeof unprotected_size) {
533*33772c1eSriastradh         sodium_misuse(); /* LCOV_EXCL_LINE */
534*33772c1eSriastradh     }
535*33772c1eSriastradh     size_with_canary = (sizeof canary) + size;
536*33772c1eSriastradh     unprotected_size = _page_round(size_with_canary);
537*33772c1eSriastradh     total_size       = page_size + page_size + unprotected_size + page_size;
538*33772c1eSriastradh     if ((base_ptr = _alloc_aligned(total_size)) == NULL) {
539*33772c1eSriastradh         return NULL; /* LCOV_EXCL_LINE */
540*33772c1eSriastradh     }
541*33772c1eSriastradh     unprotected_ptr = base_ptr + page_size * 2U;
542*33772c1eSriastradh     _mprotect_noaccess(base_ptr + page_size, page_size);
543*33772c1eSriastradh # ifndef HAVE_PAGE_PROTECTION
544*33772c1eSriastradh     memcpy(unprotected_ptr + unprotected_size, canary, sizeof canary);
545*33772c1eSriastradh # endif
546*33772c1eSriastradh     _mprotect_noaccess(unprotected_ptr + unprotected_size, page_size);
547*33772c1eSriastradh     sodium_mlock(unprotected_ptr, unprotected_size);
548*33772c1eSriastradh     canary_ptr =
549*33772c1eSriastradh         unprotected_ptr + _page_round(size_with_canary) - size_with_canary;
550*33772c1eSriastradh     user_ptr = canary_ptr + sizeof canary;
551*33772c1eSriastradh     memcpy(canary_ptr, canary, sizeof canary);
552*33772c1eSriastradh     memcpy(base_ptr, &unprotected_size, sizeof unprotected_size);
553*33772c1eSriastradh     _mprotect_readonly(base_ptr, page_size);
554*33772c1eSriastradh     assert(_unprotected_ptr_from_user_ptr(user_ptr) == unprotected_ptr);
555*33772c1eSriastradh 
556*33772c1eSriastradh     return user_ptr;
557*33772c1eSriastradh }
558*33772c1eSriastradh #endif /* !HAVE_ALIGNED_MALLOC */
559*33772c1eSriastradh 
560*33772c1eSriastradh __attribute__((malloc)) void *
sodium_malloc(const size_t size)561*33772c1eSriastradh sodium_malloc(const size_t size)
562*33772c1eSriastradh {
563*33772c1eSriastradh     void *ptr;
564*33772c1eSriastradh 
565*33772c1eSriastradh     if ((ptr = _sodium_malloc(size)) == NULL) {
566*33772c1eSriastradh         return NULL;
567*33772c1eSriastradh     }
568*33772c1eSriastradh     memset(ptr, (int) GARBAGE_VALUE, size);
569*33772c1eSriastradh 
570*33772c1eSriastradh     return ptr;
571*33772c1eSriastradh }
572*33772c1eSriastradh 
573*33772c1eSriastradh __attribute__((malloc)) void *
sodium_allocarray(size_t count,size_t size)574*33772c1eSriastradh sodium_allocarray(size_t count, size_t size)
575*33772c1eSriastradh {
576*33772c1eSriastradh     size_t total_size;
577*33772c1eSriastradh 
578*33772c1eSriastradh     if (count > (size_t) 0U && size >= (size_t) SIZE_MAX / count) {
579*33772c1eSriastradh         errno = ENOMEM;
580*33772c1eSriastradh         return NULL;
581*33772c1eSriastradh     }
582*33772c1eSriastradh     total_size = count * size;
583*33772c1eSriastradh 
584*33772c1eSriastradh     return sodium_malloc(total_size);
585*33772c1eSriastradh }
586*33772c1eSriastradh 
587*33772c1eSriastradh #ifndef HAVE_ALIGNED_MALLOC
588*33772c1eSriastradh void
sodium_free(void * ptr)589*33772c1eSriastradh sodium_free(void *ptr)
590*33772c1eSriastradh {
591*33772c1eSriastradh     free(ptr);
592*33772c1eSriastradh }
593*33772c1eSriastradh #else
594*33772c1eSriastradh void
sodium_free(void * ptr)595*33772c1eSriastradh sodium_free(void *ptr)
596*33772c1eSriastradh {
597*33772c1eSriastradh     unsigned char *base_ptr;
598*33772c1eSriastradh     unsigned char *canary_ptr;
599*33772c1eSriastradh     unsigned char *unprotected_ptr;
600*33772c1eSriastradh     size_t         total_size;
601*33772c1eSriastradh     size_t         unprotected_size;
602*33772c1eSriastradh 
603*33772c1eSriastradh     if (ptr == NULL) {
604*33772c1eSriastradh         return;
605*33772c1eSriastradh     }
606*33772c1eSriastradh     canary_ptr      = ((unsigned char *) ptr) - sizeof canary;
607*33772c1eSriastradh     unprotected_ptr = _unprotected_ptr_from_user_ptr(ptr);
608*33772c1eSriastradh     base_ptr        = unprotected_ptr - page_size * 2U;
609*33772c1eSriastradh     memcpy(&unprotected_size, base_ptr, sizeof unprotected_size);
610*33772c1eSriastradh     total_size = page_size + page_size + unprotected_size + page_size;
611*33772c1eSriastradh     _mprotect_readwrite(base_ptr, total_size);
612*33772c1eSriastradh     if (sodium_memcmp(canary_ptr, canary, sizeof canary) != 0) {
613*33772c1eSriastradh         _out_of_bounds();
614*33772c1eSriastradh     }
615*33772c1eSriastradh # ifndef HAVE_PAGE_PROTECTION
616*33772c1eSriastradh     if (sodium_memcmp(unprotected_ptr + unprotected_size, canary,
617*33772c1eSriastradh                       sizeof canary) != 0) {
618*33772c1eSriastradh         _out_of_bounds();
619*33772c1eSriastradh     }
620*33772c1eSriastradh # endif
621*33772c1eSriastradh     sodium_munlock(unprotected_ptr, unprotected_size);
622*33772c1eSriastradh     _free_aligned(base_ptr, total_size);
623*33772c1eSriastradh }
624*33772c1eSriastradh #endif /* HAVE_ALIGNED_MALLOC */
625*33772c1eSriastradh 
626*33772c1eSriastradh #ifndef HAVE_PAGE_PROTECTION
627*33772c1eSriastradh static int
_sodium_mprotect(void * ptr,int (* cb)(void * ptr,size_t size))628*33772c1eSriastradh _sodium_mprotect(void *ptr, int (*cb)(void *ptr, size_t size))
629*33772c1eSriastradh {
630*33772c1eSriastradh     (void) ptr;
631*33772c1eSriastradh     (void) cb;
632*33772c1eSriastradh     errno = ENOSYS;
633*33772c1eSriastradh     return -1;
634*33772c1eSriastradh }
635*33772c1eSriastradh #else
636*33772c1eSriastradh static int
_sodium_mprotect(void * ptr,int (* cb)(void * ptr,size_t size))637*33772c1eSriastradh _sodium_mprotect(void *ptr, int (*cb)(void *ptr, size_t size))
638*33772c1eSriastradh {
639*33772c1eSriastradh     unsigned char *base_ptr;
640*33772c1eSriastradh     unsigned char *unprotected_ptr;
641*33772c1eSriastradh     size_t         unprotected_size;
642*33772c1eSriastradh 
643*33772c1eSriastradh     unprotected_ptr = _unprotected_ptr_from_user_ptr(ptr);
644*33772c1eSriastradh     base_ptr        = unprotected_ptr - page_size * 2U;
645*33772c1eSriastradh     memcpy(&unprotected_size, base_ptr, sizeof unprotected_size);
646*33772c1eSriastradh 
647*33772c1eSriastradh     return cb(unprotected_ptr, unprotected_size);
648*33772c1eSriastradh }
649*33772c1eSriastradh #endif
650*33772c1eSriastradh 
651*33772c1eSriastradh int
sodium_mprotect_noaccess(void * ptr)652*33772c1eSriastradh sodium_mprotect_noaccess(void *ptr)
653*33772c1eSriastradh {
654*33772c1eSriastradh     return _sodium_mprotect(ptr, _mprotect_noaccess);
655*33772c1eSriastradh }
656*33772c1eSriastradh 
657*33772c1eSriastradh int
sodium_mprotect_readonly(void * ptr)658*33772c1eSriastradh sodium_mprotect_readonly(void *ptr)
659*33772c1eSriastradh {
660*33772c1eSriastradh     return _sodium_mprotect(ptr, _mprotect_readonly);
661*33772c1eSriastradh }
662*33772c1eSriastradh 
663*33772c1eSriastradh int
sodium_mprotect_readwrite(void * ptr)664*33772c1eSriastradh sodium_mprotect_readwrite(void *ptr)
665*33772c1eSriastradh {
666*33772c1eSriastradh     return _sodium_mprotect(ptr, _mprotect_readwrite);
667*33772c1eSriastradh }
668*33772c1eSriastradh 
669*33772c1eSriastradh int
sodium_pad(size_t * padded_buflen_p,unsigned char * buf,size_t unpadded_buflen,size_t blocksize,size_t max_buflen)670*33772c1eSriastradh sodium_pad(size_t *padded_buflen_p, unsigned char *buf,
671*33772c1eSriastradh            size_t unpadded_buflen, size_t blocksize, size_t max_buflen)
672*33772c1eSriastradh {
673*33772c1eSriastradh     unsigned char          *tail;
674*33772c1eSriastradh     size_t                  i;
675*33772c1eSriastradh     size_t                  xpadlen;
676*33772c1eSriastradh     size_t                  xpadded_len;
677*33772c1eSriastradh     volatile unsigned char  mask;
678*33772c1eSriastradh     unsigned char           barrier_mask;
679*33772c1eSriastradh 
680*33772c1eSriastradh     if (blocksize <= 0U) {
681*33772c1eSriastradh         return -1;
682*33772c1eSriastradh     }
683*33772c1eSriastradh     xpadlen = blocksize - 1U;
684*33772c1eSriastradh     if ((blocksize & (blocksize - 1U)) == 0U) {
685*33772c1eSriastradh         xpadlen -= unpadded_buflen & (blocksize - 1U);
686*33772c1eSriastradh     } else {
687*33772c1eSriastradh         xpadlen -= unpadded_buflen % blocksize;
688*33772c1eSriastradh     }
689*33772c1eSriastradh     if ((size_t) SIZE_MAX - unpadded_buflen <= xpadlen) {
690*33772c1eSriastradh         sodium_misuse();
691*33772c1eSriastradh     }
692*33772c1eSriastradh     xpadded_len = unpadded_buflen + xpadlen;
693*33772c1eSriastradh     if (xpadded_len >= max_buflen) {
694*33772c1eSriastradh         return -1;
695*33772c1eSriastradh     }
696*33772c1eSriastradh     tail = &buf[xpadded_len];
697*33772c1eSriastradh     if (padded_buflen_p != NULL) {
698*33772c1eSriastradh         *padded_buflen_p = xpadded_len + 1U;
699*33772c1eSriastradh     }
700*33772c1eSriastradh     mask = 0U;
701*33772c1eSriastradh     for (i = 0; i < blocksize; i++) {
702*33772c1eSriastradh         barrier_mask = (unsigned char) (((i ^ xpadlen) - 1U) >> 8);
703*33772c1eSriastradh         tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask);
704*33772c1eSriastradh         mask |= barrier_mask;
705*33772c1eSriastradh     }
706*33772c1eSriastradh     return 0;
707*33772c1eSriastradh }
708*33772c1eSriastradh 
709*33772c1eSriastradh int
sodium_unpad(size_t * unpadded_buflen_p,const unsigned char * buf,size_t padded_buflen,size_t blocksize)710*33772c1eSriastradh sodium_unpad(size_t *unpadded_buflen_p, const unsigned char *buf,
711*33772c1eSriastradh              size_t padded_buflen, size_t blocksize)
712*33772c1eSriastradh {
713*33772c1eSriastradh     const unsigned char *tail;
714*33772c1eSriastradh     unsigned char        acc = 0U;
715*33772c1eSriastradh     unsigned char        c;
716*33772c1eSriastradh     unsigned char        valid = 0U;
717*33772c1eSriastradh     volatile size_t      pad_len = 0U;
718*33772c1eSriastradh     size_t               i;
719*33772c1eSriastradh     size_t               is_barrier;
720*33772c1eSriastradh 
721*33772c1eSriastradh     if (padded_buflen < blocksize || blocksize <= 0U) {
722*33772c1eSriastradh         return -1;
723*33772c1eSriastradh     }
724*33772c1eSriastradh     tail = &buf[padded_buflen - 1U];
725*33772c1eSriastradh 
726*33772c1eSriastradh     for (i = 0U; i < blocksize; i++) {
727*33772c1eSriastradh         c = tail[-i];
728*33772c1eSriastradh         is_barrier =
729*33772c1eSriastradh             (( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U;
730*33772c1eSriastradh         acc |= c;
731*33772c1eSriastradh         pad_len |= i & (1U + ~is_barrier);
732*33772c1eSriastradh         valid |= (unsigned char) is_barrier;
733*33772c1eSriastradh     }
734*33772c1eSriastradh     *unpadded_buflen_p = padded_buflen - 1U - pad_len;
735*33772c1eSriastradh 
736*33772c1eSriastradh     return (int) (valid - 1U);
737*33772c1eSriastradh }
738