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