Skip to content

Commit fbd7f9b

Browse files
authored
FIPS-2022-11-02: thread-local using system allocator (#1401)
1 parent 0a111e8 commit fbd7f9b

File tree

11 files changed

+202
-92
lines changed

11 files changed

+202
-92
lines changed

crypto/err/err.c

Lines changed: 73 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@
106106
* ([email protected]). This product includes software written by Tim
107107
* Hudson ([email protected]). */
108108

109+
// Ensure we can't call OPENSSL_malloc circularly.
110+
#define _BORINGSSL_PROHIBIT_OPENSSL_MALLOC
109111
#include <openssl/err.h>
110112

111113
#include <assert.h>
@@ -115,7 +117,8 @@
115117
#define __STDC_FORMAT_MACROS
116118
#endif
117119
#include <inttypes.h>
118-
120+
#include <limits.h>
121+
#include <stdarg.h>
119122
#include <string.h>
120123

121124
#if defined(OPENSSL_WINDOWS)
@@ -134,8 +137,8 @@ OPENSSL_MSVC_PRAGMA(warning(pop))
134137
struct err_error_st {
135138
// file contains the filename where the error occurred.
136139
const char *file;
137-
// data contains a NUL-terminated string with optional data. It must be freed
138-
// with |OPENSSL_free|.
140+
// data contains a NUL-terminated string with optional data. It is allocated
141+
// with system |malloc| and must be freed with |free| (not |OPENSSL_free|)
139142
char *data;
140143
// packed contains the error library and reason, as packed by ERR_PACK.
141144
uint32_t packed;
@@ -167,20 +170,27 @@ extern const char kOpenSSLReasonStringData[];
167170

168171
// err_clear clears the given queued error.
169172
static void err_clear(struct err_error_st *error) {
170-
OPENSSL_free(error->data);
173+
free(error->data);
171174
OPENSSL_memset(error, 0, sizeof(struct err_error_st));
172175
}
173176

174177
static void err_copy(struct err_error_st *dst, const struct err_error_st *src) {
175178
err_clear(dst);
176179
dst->file = src->file;
177180
if (src->data != NULL) {
178-
dst->data = OPENSSL_strdup(src->data);
181+
// Disable deprecated functions on msvc so it doesn't complain about strdup.
182+
OPENSSL_MSVC_PRAGMA(warning(push))
183+
OPENSSL_MSVC_PRAGMA(warning(disable : 4996))
184+
// We can't use OPENSSL_strdup because we don't want to call OPENSSL_malloc,
185+
// which can affect the error stack.
186+
dst->data = strdup(src->data);
187+
OPENSSL_MSVC_PRAGMA(warning(pop))
179188
}
180189
dst->packed = src->packed;
181190
dst->line = src->line;
182191
}
183192

193+
184194
// global_next_library contains the next custom library value to return.
185195
static int global_next_library = ERR_NUM_LIBS;
186196

@@ -199,15 +209,15 @@ static void err_state_free(void *statep) {
199209
for (unsigned i = 0; i < ERR_NUM_ERRORS; i++) {
200210
err_clear(&state->errors[i]);
201211
}
202-
OPENSSL_free(state->to_free);
203-
OPENSSL_free(state);
212+
free(state->to_free);
213+
free(state);
204214
}
205215

206216
// err_get_state gets the ERR_STATE object for the current thread.
207217
static ERR_STATE *err_get_state(void) {
208218
ERR_STATE *state = CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_ERR);
209219
if (state == NULL) {
210-
state = OPENSSL_malloc(sizeof(ERR_STATE));
220+
state = malloc(sizeof(ERR_STATE));
211221
if (state == NULL) {
212222
return NULL;
213223
}
@@ -263,7 +273,10 @@ static uint32_t get_error_values(int inc, int top, const char **file, int *line,
263273
} else {
264274
*data = error->data;
265275
if (flags != NULL) {
266-
*flags = ERR_FLAG_STRING;
276+
// Without |ERR_FLAG_MALLOCED|, rust-openssl assumes the string has a
277+
// static lifetime. In both cases, we retain ownership of the string,
278+
// and the caller is not expected to free it.
279+
*flags = ERR_FLAG_STRING | ERR_FLAG_MALLOCED;
267280
}
268281
// If this error is being removed, take ownership of data from
269282
// the error. The semantics are such that the caller doesn't
@@ -272,7 +285,7 @@ static uint32_t get_error_values(int inc, int top, const char **file, int *line,
272285
// error queue.
273286
if (inc) {
274287
if (error->data != NULL) {
275-
OPENSSL_free(state->to_free);
288+
free(state->to_free);
276289
state->to_free = error->data;
277290
}
278291
error->data = NULL;
@@ -340,7 +353,7 @@ void ERR_clear_error(void) {
340353
for (i = 0; i < ERR_NUM_ERRORS; i++) {
341354
err_clear(&state->errors[i]);
342355
}
343-
OPENSSL_free(state->to_free);
356+
free(state->to_free);
344357
state->to_free = NULL;
345358

346359
state->top = state->bottom = 0;
@@ -634,13 +647,13 @@ static void err_set_error_data(char *data) {
634647
struct err_error_st *error;
635648

636649
if (state == NULL || state->top == state->bottom) {
637-
OPENSSL_free(data);
650+
free(data);
638651
return;
639652
}
640653

641654
error = &state->errors[state->top];
642655

643-
OPENSSL_free(error->data);
656+
free(error->data);
644657
error->data = data;
645658
}
646659

@@ -677,48 +690,42 @@ void ERR_put_error(int library, int unused, int reason, const char *file,
677690
// concatenates them and sets the result as the data on the most recent
678691
// error.
679692
static void err_add_error_vdata(unsigned num, va_list args) {
680-
size_t alloced, new_len, len = 0, substr_len;
681-
char *buf;
693+
size_t total_size = 0;
682694
const char *substr;
683-
unsigned i;
695+
char *buf;
684696

685-
alloced = 80;
686-
buf = OPENSSL_malloc(alloced + 1);
687-
if (buf == NULL) {
697+
va_list args_copy;
698+
va_copy(args_copy, args);
699+
for (size_t i = 0; i < num; i++) {
700+
substr = va_arg(args_copy, const char *);
701+
if (substr == NULL) {
702+
continue;
703+
}
704+
size_t substr_len = strlen(substr);
705+
if (SIZE_MAX - total_size < substr_len) {
706+
return; // Would overflow.
707+
}
708+
total_size += substr_len;
709+
}
710+
va_end(args_copy);
711+
if (total_size == SIZE_MAX) {
712+
return; // Would overflow.
713+
}
714+
total_size += 1; // NUL terminator.
715+
if ((buf = malloc(total_size)) == NULL) {
688716
return;
689717
}
690-
691-
for (i = 0; i < num; i++) {
718+
buf[0] = '\0';
719+
for (size_t i = 0; i < num; i++) {
692720
substr = va_arg(args, const char *);
693721
if (substr == NULL) {
694722
continue;
695723
}
696-
697-
substr_len = strlen(substr);
698-
new_len = len + substr_len;
699-
if (new_len > alloced) {
700-
char *new_buf;
701-
702-
if (alloced + 20 + 1 < alloced) {
703-
// overflow.
704-
OPENSSL_free(buf);
705-
return;
706-
}
707-
708-
alloced = new_len + 20;
709-
new_buf = OPENSSL_realloc(buf, alloced + 1);
710-
if (new_buf == NULL) {
711-
OPENSSL_free(buf);
712-
return;
713-
}
714-
buf = new_buf;
724+
if (OPENSSL_strlcat(buf, substr, total_size) >= total_size) {
725+
assert(0); // should not be possible.
715726
}
716-
717-
OPENSSL_memcpy(buf + len, substr, substr_len);
718-
len = new_len;
719727
}
720-
721-
buf[len] = 0;
728+
va_end(args);
722729
err_set_error_data(buf);
723730
}
724731

@@ -730,21 +737,13 @@ void ERR_add_error_data(unsigned count, ...) {
730737
}
731738

732739
void ERR_add_error_dataf(const char *format, ...) {
740+
char *buf = NULL;
733741
va_list ap;
734-
char *buf;
735-
static const unsigned buf_len = 256;
736742

737-
// A fixed-size buffer is used because va_copy (which would be needed in
738-
// order to call vsnprintf twice and measure the buffer) wasn't defined until
739-
// C99.
740-
buf = OPENSSL_malloc(buf_len + 1);
741-
if (buf == NULL) {
743+
va_start(ap, format);
744+
if (OPENSSL_vasprintf_internal(&buf, format, ap, /*system_malloc=*/1) == -1) {
742745
return;
743746
}
744-
745-
va_start(ap, format);
746-
BIO_vsnprintf(buf, buf_len, format, ap);
747-
buf[buf_len] = 0;
748747
va_end(ap);
749748

750749
err_set_error_data(buf);
@@ -756,13 +755,20 @@ void ERR_set_error_data(char *data, int flags) {
756755
assert(0);
757756
return;
758757
}
758+
// Disable deprecated functions on msvc so it doesn't complain about strdup.
759+
OPENSSL_MSVC_PRAGMA(warning(push))
760+
OPENSSL_MSVC_PRAGMA(warning(disable : 4996))
761+
// We can not use OPENSSL_strdup because we don't want to call OPENSSL_malloc,
762+
// which can affect the error stack.
763+
char *copy = strdup(data);
764+
OPENSSL_MSVC_PRAGMA(warning(pop))
765+
if (copy != NULL) {
766+
err_set_error_data(copy);
767+
}
759768
if (flags & ERR_FLAG_MALLOCED) {
760-
err_set_error_data(data);
761-
} else {
762-
char *copy = OPENSSL_strdup(data);
763-
if (copy != NULL) {
764-
err_set_error_data(copy);
765-
}
769+
// We can not take ownership of |data| directly because it is allocated with
770+
// |OPENSSL_malloc| and we will free it with system |free| later.
771+
OPENSSL_free(data);
766772
}
767773
}
768774

@@ -824,8 +830,8 @@ void ERR_SAVE_STATE_free(ERR_SAVE_STATE *state) {
824830
for (size_t i = 0; i < state->num_errors; i++) {
825831
err_clear(&state->errors[i]);
826832
}
827-
OPENSSL_free(state->errors);
828-
OPENSSL_free(state);
833+
free(state->errors);
834+
free(state);
829835
}
830836

831837
ERR_SAVE_STATE *ERR_save_state(void) {
@@ -834,7 +840,7 @@ ERR_SAVE_STATE *ERR_save_state(void) {
834840
return NULL;
835841
}
836842

837-
ERR_SAVE_STATE *ret = OPENSSL_malloc(sizeof(ERR_SAVE_STATE));
843+
ERR_SAVE_STATE *ret = malloc(sizeof(ERR_SAVE_STATE));
838844
if (ret == NULL) {
839845
return NULL;
840846
}
@@ -844,9 +850,9 @@ ERR_SAVE_STATE *ERR_save_state(void) {
844850
? state->top - state->bottom
845851
: ERR_NUM_ERRORS + state->top - state->bottom;
846852
assert(num_errors < ERR_NUM_ERRORS);
847-
ret->errors = OPENSSL_malloc(num_errors * sizeof(struct err_error_st));
853+
ret->errors = malloc(num_errors * sizeof(struct err_error_st));
848854
if (ret->errors == NULL) {
849-
OPENSSL_free(ret);
855+
free(ret);
850856
return NULL;
851857
}
852858
OPENSSL_memset(ret->errors, 0, num_errors * sizeof(struct err_error_st));

crypto/err/err_test.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ TEST(ErrTest, PutError) {
7171

7272
EXPECT_STREQ("test", file);
7373
EXPECT_EQ(4, line);
74-
EXPECT_TRUE(flags & ERR_FLAG_STRING);
74+
EXPECT_EQ(flags, ERR_FLAG_STRING | ERR_FLAG_MALLOCED);
7575
EXPECT_EQ(1, ERR_GET_LIB(packed_error));
7676
EXPECT_EQ(2, ERR_GET_REASON(packed_error));
7777
EXPECT_STREQ("testing", data);
@@ -167,7 +167,7 @@ TEST(ErrTest, SaveAndRestore) {
167167
EXPECT_STREQ("test1.c", file);
168168
EXPECT_EQ(line, 1);
169169
EXPECT_STREQ(data, "data1");
170-
EXPECT_EQ(flags, ERR_FLAG_STRING);
170+
EXPECT_EQ(flags, ERR_FLAG_STRING | ERR_FLAG_MALLOCED);
171171

172172
// The state may be restored, both over an empty and non-empty state.
173173
for (unsigned i = 0; i < 2; i++) {
@@ -180,7 +180,7 @@ TEST(ErrTest, SaveAndRestore) {
180180
EXPECT_STREQ("test1.c", file);
181181
EXPECT_EQ(line, 1);
182182
EXPECT_STREQ(data, "data1");
183-
EXPECT_EQ(flags, ERR_FLAG_STRING);
183+
EXPECT_EQ(flags, ERR_FLAG_STRING | ERR_FLAG_MALLOCED);
184184

185185
packed_error = ERR_get_error_line_data(&file, &line, &data, &flags);
186186
EXPECT_EQ(ERR_GET_LIB(packed_error), 2);
@@ -196,7 +196,7 @@ TEST(ErrTest, SaveAndRestore) {
196196
EXPECT_STREQ("test3.c", file);
197197
EXPECT_EQ(line, 3);
198198
EXPECT_STREQ(data, "data3");
199-
EXPECT_EQ(flags, ERR_FLAG_STRING);
199+
EXPECT_EQ(flags, ERR_FLAG_STRING | ERR_FLAG_MALLOCED);
200200

201201
// The error queue is now empty for the next iteration.
202202
EXPECT_EQ(0u, ERR_get_error());

crypto/fipsmodule/rand/rand.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
1313
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
1414

15+
// Ensure we can't call OPENSSL_malloc.
16+
#define _BORINGSSL_PROHIBIT_OPENSSL_MALLOC
1517
#include <openssl/rand.h>
1618

1719
#include <assert.h>
@@ -259,9 +261,11 @@ static void rand_thread_state_free(void *state_in) {
259261
CRYPTO_STATIC_MUTEX_unlock_write(thread_states_list_lock_bss_get());
260262

261263
rand_state_fips_clear(state);
264+
#else
265+
OPENSSL_cleanse(state, sizeof(struct rand_thread_state));
262266
#endif
263267

264-
OPENSSL_free(state);
268+
free(state);
265269
}
266270

267271
#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM) && \
@@ -402,7 +406,7 @@ void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len,
402406
CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_RAND);
403407

404408
if (state == NULL) {
405-
state = OPENSSL_malloc(sizeof(struct rand_thread_state));
409+
state = malloc(sizeof(struct rand_thread_state));
406410
if (state != NULL) {
407411
OPENSSL_memset(state, 0, sizeof(struct rand_thread_state));
408412
}

crypto/fipsmodule/self_check/fips.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
1313
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
1414

15+
// Ensure we can't call OPENSSL_malloc
16+
#define _BORINGSSL_PROHIBIT_OPENSSL_MALLOC
1517
#include <openssl/crypto.h>
1618

1719
#include "../../internal.h"
@@ -97,14 +99,14 @@ void boringssl_fips_inc_counter(enum fips_counter_t counter) {
9799
CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_FIPS_COUNTERS);
98100
if (!array) {
99101
const size_t num_bytes = sizeof(size_t) * (fips_counter_max + 1);
100-
array = OPENSSL_malloc(num_bytes);
102+
array = malloc(num_bytes);
101103
if (!array) {
102104
return;
103105
}
104106

105107
OPENSSL_memset(array, 0, num_bytes);
106108
if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_FIPS_COUNTERS, array,
107-
OPENSSL_free)) {
109+
free)) {
108110
// |OPENSSL_free| has already been called by |CRYPTO_set_thread_local|.
109111
return;
110112
}

0 commit comments

Comments
 (0)