• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

open-quantum-safe / liboqs / 23069689359

13 Mar 2026 08:41PM UTC coverage: 83.027% (-0.006%) from 83.033%
23069689359

push

github

web-flow
Check for overflow in arguments passed to OQS_MEM_calloc (#2377)

Not exploitable by codepaths present in liboqs, but patching in case future codepaths are.

Identified by @iiviel.

Signed-off-by: Douglas Stebila <dstebila@uwaterloo.ca>

0 of 2 new or added lines in 1 file covered. (0.0%)

24 existing lines in 17 files now uncovered.

207515 of 249938 relevant lines covered (83.03%)

8168401.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.82
/src/common/common.c
1
// SPDX-License-Identifier: Apache-2.0 AND MIT
2

3
#if !defined(OQS_USE_OPENSSL) && !defined(_WIN32) && !defined(OQS_HAVE_EXPLICIT_BZERO) && !defined(OQS_HAVE_EXPLICIT_MEMSET)
4
// Request memset_s
5
#define __STDC_WANT_LIB_EXT1__ 1
6
#endif
7

8
#include <oqs/common.h>
9

10
#include <errno.h>
11
#include <stdint.h>
12
#include <stdio.h>
13
#include <stdlib.h>
14
#include <stddef.h>
15
#include <string.h>
16
#include <stddef.h>
17

18
#if defined(OQS_DIST_BUILD) && defined(OQS_USE_PTHREADS)
19
#include <pthread.h>
20
#endif
21

22
#if !defined(OQS_HAVE_POSIX_MEMALIGN) || defined(__MINGW32__) || defined(__MINGW64__) || defined(_MSC_VER)
23
#include <malloc.h>
24
#endif
25

26
#if defined(_WIN32)
27
#include <windows.h>
28
#endif
29

30
#if defined(OQS_USE_OPENSSL)
31
#include "ossl_helpers.h"
32
#endif
33

34
/* Identifying the CPU is expensive so we cache the results in cpu_ext_data */
35
#if defined(OQS_DIST_BUILD)
36
static unsigned int cpu_ext_data[OQS_CPU_EXT_COUNT] = {0};
37
#if defined(OQS_USE_PTHREADS)
38
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
39
#endif
40
#endif
41

42
#if defined(OQS_DIST_X86_64_BUILD)
43
/* set_available_cpu_extensions_x86_64() has been written using:
44
 * https://github.com/google/cpu_features/blob/339bfd32be1285877ff517cba8b82ce72e946afd/src/cpuinfo_x86.c
45
 */
46
#include "x86_64_helpers.h"
47
static void set_available_cpu_extensions(void) {
3,750✔
48
        /* mark that this function has been called */
49
        cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
3,750✔
50

51
        cpuid_out leaf_1;
52
        cpuid(&leaf_1, 1);
3,750✔
53
        if (leaf_1.eax == 0) {
3,750✔
54
                return;
55
        }
56

57
        cpuid_out leaf_7;
58
        cpuid(&leaf_7, 7);
3,750✔
59

60
        const unsigned int has_xsave = is_bit_set(leaf_1.ecx, 26);
3,750✔
61
        const unsigned int has_osxsave = is_bit_set(leaf_1.ecx, 27);
3,750✔
62
        const uint32_t xcr0_eax = (has_xsave && has_osxsave) ? xgetbv_eax(0) : 0;
3,750✔
63

64
        cpu_ext_data[OQS_CPU_EXT_AES] = is_bit_set(leaf_1.ecx, 25);
3,750✔
65
        if (has_mask(xcr0_eax, MASK_XMM | MASK_YMM)) {
3,750✔
66
                cpu_ext_data[OQS_CPU_EXT_AVX] = is_bit_set(leaf_1.ecx, 28);
3,750✔
67
                cpu_ext_data[OQS_CPU_EXT_AVX2] = is_bit_set(leaf_7.ebx, 5);
3,750✔
68
        }
69
        cpu_ext_data[OQS_CPU_EXT_PCLMULQDQ] = is_bit_set(leaf_1.ecx, 1);
3,750✔
70
        cpu_ext_data[OQS_CPU_EXT_POPCNT] = is_bit_set(leaf_1.ecx, 23);
3,750✔
71
        cpu_ext_data[OQS_CPU_EXT_BMI1] = is_bit_set(leaf_7.ebx, 3);
3,750✔
72
        cpu_ext_data[OQS_CPU_EXT_BMI2] = is_bit_set(leaf_7.ebx, 8);
3,750✔
73
        cpu_ext_data[OQS_CPU_EXT_ADX] = is_bit_set(leaf_7.ebx, 19);
3,750✔
74

75
        if (has_mask(xcr0_eax, MASK_XMM)) {
3,750✔
76
                cpu_ext_data[OQS_CPU_EXT_SSE] = is_bit_set(leaf_1.edx, 25);
3,750✔
77
                cpu_ext_data[OQS_CPU_EXT_SSE2] = is_bit_set(leaf_1.edx, 26);
3,750✔
78
                cpu_ext_data[OQS_CPU_EXT_SSE3] = is_bit_set(leaf_1.ecx, 0);
3,750✔
79
        }
80

81
        if (has_mask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 | MASK_ZMM16_31)) {
3,750✔
82
                unsigned int avx512f = is_bit_set(leaf_7.ebx, 16);
83
                unsigned int avx512bw = is_bit_set(leaf_7.ebx, 30);
84
                unsigned int avx512dq = is_bit_set(leaf_7.ebx, 17);
85
                if (avx512f && avx512bw && avx512dq) {
86
                        cpu_ext_data[OQS_CPU_EXT_AVX512] = 1;
87
                }
88
                cpu_ext_data[OQS_CPU_EXT_VPCLMULQDQ] = is_bit_set(leaf_7.ecx, 10);
89
        }
90
}
91
#elif defined(OQS_DIST_X86_BUILD)
92
static void set_available_cpu_extensions(void) {
93
        /* mark that this function has been called */
94
        cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
95
}
96
#elif defined(OQS_DIST_ARM64_V8_BUILD)
97
#if defined(__APPLE__)
98
#include <sys/sysctl.h>
99
static unsigned int macos_feature_detection(const char *feature_name) {
100
        int p;
101
        size_t p_len = sizeof(p);
102
        int res = sysctlbyname(feature_name, &p, &p_len, NULL, 0);
103
        if (res != 0) {
104
                return 0;
105
        } else {
106
                return (p != 0) ? 1 : 0;
107
        }
108
}
109
static void set_available_cpu_extensions(void) {
110
        cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
111
        cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
112
        cpu_ext_data[OQS_CPU_EXT_ARM_SHA3] = macos_feature_detection("hw.optional.armv8_2_sha3");
113
        cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = macos_feature_detection("hw.optional.neon");
114
        /* mark that this function has been called */
115
        cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
116
}
117
#elif defined(__FreeBSD__) || defined(__FreeBSD)
118
#include <sys/auxv.h>
119
#include <machine/elf.h>
120

121
static void set_available_cpu_extensions(void) {
122
        /* mark that this function has been called */
123
        u_long hwcaps = 0;
124
        cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
125
        if (elf_aux_info(AT_HWCAP, &hwcaps, sizeof(u_long))) {
126
                fprintf(stderr, "Error getting HWCAP for ARM on FreeBSD\n");
127
                return;
128
        }
129
        if (hwcaps & HWCAP_AES) {
130
                cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
131
        }
132
        if (hwcaps & HWCAP_ASIMD) {
133
                cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = 1;
134
        }
135
        if (hwcaps & HWCAP_SHA2) {
136
                cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
137
        }
138
#ifdef HWCAP_SHA3
139
        if (hwcaps & HWCAP_SHA3) {
140
                cpu_ext_data[OQS_CPU_EXT_ARM_SHA3] = 1;
141
        }
142
#endif
143
}
144
#elif defined(_WIN32)
145
static void set_available_cpu_extensions(void) {
146
        /* mark that this function has been called */
147
        cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
148
        BOOL crypto = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
149
        if (crypto) {
150
                cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
151
                cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
152
        }
153
        BOOL neon = IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE);
154
        if (neon) {
155
                cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = 1;
156
        }
157
}
158
#else
159
#include <sys/auxv.h>
160
#include <asm/hwcap.h>
161
static void set_available_cpu_extensions(void) {
3,750✔
162
        /* mark that this function has been called */
163
        cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
3,750✔
164
        unsigned long int hwcaps = getauxval(AT_HWCAP);
3,750✔
165
        if (hwcaps & HWCAP_AES) {
3,750✔
166
                cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
3,750✔
167
        }
168
        if (hwcaps & HWCAP_SHA2) {
3,750✔
169
                cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
3,750✔
170
        }
171
#ifdef HWCAP_SHA3
172
        if (hwcaps & HWCAP_SHA3) {
3,750✔
173
                cpu_ext_data[OQS_CPU_EXT_ARM_SHA3] = 1;
3,750✔
174
        }
175
#endif
176
        if (hwcaps & HWCAP_ASIMD) {
3,750✔
177
                cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = 1;
3,750✔
178
        }
179
}
3,750✔
180
#endif
181
#elif defined(OQS_DIST_ARM32v7_BUILD)
182
#include <sys/auxv.h>
183
#include <asm/hwcap.h>
184
static void set_available_cpu_extensions(void) {
185
        /* mark that this function has been called */
186
        cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
187
        unsigned long int hwcaps = getauxval(AT_HWCAP);
188
        unsigned long int hwcaps2 = getauxval(AT_HWCAP2);
189
        if (hwcaps2 & HWCAP2_AES) {
190
                cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
191
        }
192
        if (hwcaps2 & HWCAP2_SHA2) {
193
                cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
194
        }
195
        if (hwcaps & HWCAP_NEON) {
196
                cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = 1;
197
        }
198
}
199
#elif defined(OQS_DIST_PPC64LE_BUILD)
200
static void set_available_cpu_extensions(void) {
201
        /* mark that this function has been called */
202
        cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
203
}
204
#elif defined(OQS_DIST_S390X_BUILD)
205
static void set_available_cpu_extensions(void) {
206
        /* mark that this function has been called */
207
        cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
208
}
209
#elif defined(OQS_DIST_LOONGARCH64_BUILD)
210
static void set_available_cpu_extensions(void) {
211
        /* mark that this function has been called */
212
        cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
213
}
214
#elif defined(OQS_DIST_BUILD)
215
static void set_available_cpu_extensions(void) {
216
}
217
#endif
218

219
OQS_API int OQS_CPU_has_extension(OQS_CPU_EXT ext) {
361,737✔
220
#if defined(OQS_DIST_BUILD)
221
#if defined(OQS_USE_PTHREADS)
222
        pthread_once(&once_control, &set_available_cpu_extensions);
361,737✔
223
#else
224
        if (0 == cpu_ext_data[OQS_CPU_EXT_INIT]) {
225
                set_available_cpu_extensions();
226
        }
227
#endif
228
        if (0 < ext && ext < OQS_CPU_EXT_COUNT) {
361,737✔
229
                return (int)cpu_ext_data[ext];
354,237✔
230
        }
231
#else
232
        (void)ext;
233
#endif
234
        return 0;
7,500✔
235
}
236

237
OQS_API void OQS_init(void) {
11,250✔
238
#if defined(OQS_DIST_BUILD)
239
        OQS_CPU_has_extension(OQS_CPU_EXT_INIT);
7,500✔
240
#endif
241
}
11,250✔
242

243
OQS_API void OQS_thread_stop(void) {
201✔
244
#if defined(OQS_USE_OPENSSL)
245
        oqs_thread_stop();
201✔
246
#endif
247
}
201✔
248

249
OQS_API const char *OQS_version(void) {
741✔
250
        return OQS_VERSION_TEXT;
741✔
251
}
252

253
OQS_API void OQS_destroy(void) {
11,250✔
254
#if defined(OQS_USE_OPENSSL)
255
        oqs_ossl_destroy();
11,250✔
256
#endif
257
}
11,250✔
258

259
OQS_API int OQS_MEM_secure_bcmp(const void *a, const void *b, size_t len) {
×
260
        /* Assume CHAR_BIT = 8 */
261
        uint8_t r = 0;
×
262

263
        for (size_t i = 0; i < len; i++) {
×
264
                r |= ((const uint8_t *)a)[i] ^ ((const uint8_t *)b)[i];
×
265
        }
266

267
        // We have 0 <= r < 256, and unsigned int is at least 16 bits.
268
        return 1 & ((-(unsigned int)r) >> 8);
×
269
}
270

271
OQS_API void OQS_MEM_cleanse(void *ptr, size_t len) {
8,314,877✔
272
        if (ptr == NULL) {
8,314,877✔
273
                return;
×
274
        }
275
#if defined(OQS_USE_OPENSSL)
276
        OSSL_FUNC(OPENSSL_cleanse)(ptr, len);
8,314,877✔
277
#elif defined(_WIN32)
278
        SecureZeroMemory(ptr, len);
279
#elif defined(OQS_HAVE_EXPLICIT_BZERO)
280
        explicit_bzero(ptr, len);
281
#elif defined(OQS_HAVE_EXPLICIT_MEMSET)
282
        explicit_memset(ptr, 0, len);
283
#elif defined(__STDC_LIB_EXT1__) || defined(OQS_HAVE_MEMSET_S)
284
        if (0U < len && memset_s(ptr, (rsize_t)len, 0, (rsize_t)len) != 0) {
285
                abort();
286
        }
287
#else
288
        typedef void *(*memset_t)(void *, int, size_t);
289
        static volatile memset_t memset_func = memset;
290
        memset_func(ptr, 0, len);
291
#endif
292
}
293

294
OQS_API void OQS_MEM_secure_free(void *ptr, size_t len) {
47,077✔
295
        if (ptr != NULL) {
47,077✔
296
                OQS_MEM_cleanse(ptr, len);
34,651✔
297
                OQS_MEM_insecure_free(ptr);
34,651✔
298
        }
299
}
47,077✔
300

301
OQS_API void OQS_MEM_insecure_free(void *ptr) {
162,259✔
302
#if defined(OQS_USE_OPENSSL) && defined(OPENSSL_VERSION_NUMBER)
303
        OSSL_FUNC(CRYPTO_free)(ptr, OPENSSL_FILE, OPENSSL_LINE);
162,259✔
304
#else
305
        free(ptr); // IGNORE memory-check
306
#endif
307
}
162,259✔
308

309
void *OQS_MEM_aligned_alloc(size_t alignment, size_t size) {
8,265,068✔
310
#if defined(OQS_USE_OPENSSL)
311
        // Use OpenSSL's memory allocation functions
312
        if (!size) {
8,265,068✔
313
                return NULL;
×
314
        }
315
        const size_t offset = alignment - 1 + sizeof(uint8_t);
8,265,068✔
316
        uint8_t *buffer = OSSL_FUNC(CRYPTO_malloc)(size + offset, OPENSSL_FILE, OPENSSL_LINE);
8,265,068✔
317
        if (!buffer) {
8,265,068✔
318
                return NULL;
×
319
        }
320
        uint8_t *ptr = (uint8_t *)(((uintptr_t)(buffer) + offset) & ~(alignment - 1));
8,265,068✔
321
        ptrdiff_t diff = ptr - buffer;
8,265,068✔
322
        if (diff > UINT8_MAX) {
8,265,068✔
323
                // Free and return NULL if alignment is too large
324
                OSSL_FUNC(CRYPTO_free)(buffer, OPENSSL_FILE, OPENSSL_LINE);
×
325
                errno = EINVAL;
×
326
                return NULL;
×
327
        }
328
        // Store the difference so that the free function can use it
329
        ptr[-1] = (uint8_t)diff;
8,265,068✔
330
        return ptr;
8,265,068✔
331
#elif defined(OQS_HAVE_ALIGNED_ALLOC) // glibc and other implementations providing aligned_alloc
332
        return aligned_alloc(alignment, size);
333
#else
334
        // Check alignment (power of 2, and >= sizeof(void*)) and size (multiple of alignment)
335
        if (alignment & (alignment - 1) || size & (alignment - 1) || alignment < sizeof(void *)) {
336
                errno = EINVAL;
337
                return NULL;
338
        }
339

340
#if defined(OQS_HAVE_POSIX_MEMALIGN)
341
        void *ptr = NULL;
342
        const int err = posix_memalign(&ptr, alignment, size);
343
        if (err) {
344
                errno = err;
345
                ptr = NULL;
346
        }
347
        return ptr;
348
#elif defined(OQS_HAVE_MEMALIGN)
349
        return memalign(alignment, size);
350
#elif defined(__MINGW32__) || defined(__MINGW64__)
351
        return __mingw_aligned_malloc(size, alignment);
352
#elif defined(_MSC_VER)
353
        return _aligned_malloc(size, alignment);
354
#else
355
        if (!size) {
356
                return NULL;
357
        }
358
        // Overallocate to be able to align the pointer (alignment -1) and to store
359
        // the difference between the pointer returned to the user (ptr) and the
360
        // pointer returned by malloc (buffer). The difference is caped to 255 and
361
        // can be made larger if necessary, but this should be enough for all users
362
        // in liboqs.
363
        //
364
        // buffer      ptr
365
        // ↓           ↓
366
        // ...........|...................
367
        //            |
368
        //       diff = ptr - buffer
369
        const size_t offset = alignment - 1 + sizeof(uint8_t);
370
        uint8_t *buffer = malloc(size + offset); // IGNORE memory-check
371
        if (!buffer) {
372
                return NULL;
373
        }
374

375
        // Align the pointer returned to the user.
376
        uint8_t *ptr = (uint8_t *)(((uintptr_t)(buffer) + offset) & ~(alignment - 1));
377
        ptrdiff_t diff = ptr - buffer;
378
        if (diff > UINT8_MAX) {
379
                // This should never happen in our code, but just to be safe
380
                free(buffer); // IGNORE memory-check
381
                errno = EINVAL;
382
                return NULL;
383
        }
384
        // Store the difference one byte ahead the returned poitner so that free
385
        // can reconstruct buffer.
386
        ptr[-1] = diff;
387
        return ptr;
388
#endif
389
#endif
390
}
391

392
void OQS_MEM_aligned_free(void *ptr) {
8,265,068✔
393
        if (ptr == NULL) {
8,265,068✔
394
                return;
×
395
        }
396
#if defined(OQS_USE_OPENSSL)
397
        // Use OpenSSL's free function
398
        uint8_t *u8ptr = ptr;
8,265,068✔
399
        OSSL_FUNC(CRYPTO_free)(u8ptr - u8ptr[-1], OPENSSL_FILE, OPENSSL_LINE);
8,265,068✔
400
#elif defined(OQS_HAVE_ALIGNED_ALLOC) || defined(OQS_HAVE_POSIX_MEMALIGN) || defined(OQS_HAVE_MEMALIGN)
401
        free(ptr); // IGNORE memory-check
402
#elif defined(__MINGW32__) || defined(__MINGW64__)
403
        __mingw_aligned_free(ptr);
404
#elif defined(_MSC_VER)
405
        _aligned_free(ptr);
406
#else
407
        // Reconstruct the pointer returned from malloc using the difference
408
        // stored one byte ahead of ptr.
409
        uint8_t *u8ptr = ptr;
410
        free(u8ptr - u8ptr[-1]); // IGNORE memory-check
411
#endif
412
}
413

414
void OQS_MEM_aligned_secure_free(void *ptr, size_t len) {
8,265,068✔
415
        OQS_MEM_cleanse(ptr, len);
8,265,068✔
416
        OQS_MEM_aligned_free(ptr);
8,265,068✔
417
}
8,265,068✔
418

419
OQS_API void *OQS_MEM_malloc(size_t size) {
96,763✔
420
#if defined(OQS_USE_OPENSSL)
421
        return OSSL_FUNC(CRYPTO_malloc)(size, OPENSSL_FILE, OPENSSL_LINE);
96,763✔
422
#else
423
        return malloc(size); // IGNORE memory-check
424
#endif
425
}
426

427
OQS_API void *OQS_MEM_calloc(size_t num_elements, size_t element_size) {
×
428
#if defined(OQS_USE_OPENSSL)
NEW
429
        if (element_size != 0 && num_elements > SIZE_MAX / element_size) {
×
NEW
430
                return NULL;
×
431
        }
UNCOV
432
        return OSSL_FUNC(CRYPTO_zalloc)(num_elements * element_size,
×
433
                                        OPENSSL_FILE, OPENSSL_LINE);
434
#else
435
        return calloc(num_elements, element_size); // IGNORE memory-check
436
#endif
437
}
438

439
OQS_API char *OQS_MEM_strdup(const char *str) {
×
440
#if defined(OQS_USE_OPENSSL)
441
        return OSSL_FUNC(CRYPTO_strdup)(str, OPENSSL_FILE, OPENSSL_LINE);
×
442
#elif defined(OQS_EMBEDDED_BUILD)
443
        size_t len = strlen(str) + 1;
444
        char *dup = (char *)malloc(len); // IGNORE memory-check
445
        if (dup != NULL) {
446
                memcpy(dup, str, len);
447
        }
448
        return dup;
449
#else
450
        return strdup(str); // IGNORE memory-check
451
#endif
452
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc