Skip to content

Commit b55cf35

Browse files
authored
MONGOCRYPT-865 replace sprintf with safer alternatives (#1127)
* remove unused `_mongocrypt_new_json_string_from_binary` * remove unused `tmp_buf` * replace calls of `sprintf` with `bson_snprintf` or `snprintf` * check return values of `snprintf` and `bson_snprintf` * fix bound check of `bson_snprintf` The return value does not include the NULL byte. To ensure no truncation occurs, the return value must be strictly less than the buffer size.
1 parent 8411f5d commit b55cf35

12 files changed

Lines changed: 19 additions & 77 deletions

kms-message/src/hexlify.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ hexlify (const uint8_t *buf, size_t len)
3535
size_t i;
3636

3737
for (i = 0; i < len; i++) {
38-
p += sprintf (p, "%02x", buf[i]);
38+
KMS_ASSERT (2 == snprintf (p, 3, "%02x", buf[i]));
39+
p += 2;
3940
}
4041

4142
*p = '\0';

kms-message/src/kms_request_str.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ kms_request_str_append_escaped (kms_request_str_t *str,
303303
++out;
304304
++str->len;
305305
} else {
306-
sprintf ((char *) out, "%%%02X", *in);
306+
KMS_ASSERT (3 == snprintf ((char *) out, 4, "%%%02X", *in));
307307
out += 3;
308308
str->len += 3;
309309
}

kms-message/test/test_kms_request.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ test_file_path (const char *path, const char *suffix)
9999
char *r;
100100
char *test_name = last_segment (path);
101101
char file_path[PATH_MAX];
102-
snprintf (file_path, PATH_MAX, "%s/%s.%s", path, test_name, suffix);
102+
int ret = snprintf (file_path, PATH_MAX, "%s/%s.%s", path, test_name, suffix);
103+
KMS_ASSERT (ret > 0 && ret < PATH_MAX);
103104
r = strdup (file_path);
104105
free (test_name);
105106
return r;

src/mc-schema-broker.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ bool mc_schema_broker_append_listCollections_filter(const mc_schema_broker_t *sb
185185

186186
char idx_str[32];
187187
int ret = bson_snprintf(idx_str, sizeof idx_str, "%zu", idx);
188-
BSON_ASSERT(ret > 0 && ret <= (int)sizeof idx_str);
188+
BSON_ASSERT(ret > 0 && ret < (int)sizeof idx_str);
189189

190190
TRY_BSON_OR(BSON_APPEND_UTF8(&in_array, idx_str, se->coll)) {
191191
return false;

src/mongocrypt-buffer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ char *_mongocrypt_buffer_to_hex(_mongocrypt_buffer_t *buf) {
462462
char *out = hex;
463463

464464
for (uint32_t i = 0; i < buf->len; i++, out += 2) {
465-
sprintf(out, "%02X", buf->data[i]);
465+
BSON_ASSERT(2 == bson_snprintf(out, 3, "%02X", buf->data[i]));
466466
}
467467
return hex;
468468
}

src/mongocrypt-private.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,6 @@ bool _mongocrypt_validate_and_copy_string(const char *in, int32_t in_len, char *
163163

164164
char *_mongocrypt_new_string_from_bytes(const void *in, int len);
165165

166-
char *_mongocrypt_new_json_string_from_binary(mongocrypt_binary_t *binary);
167-
168166
/* _mongocrypt_needs_credentials returns true if @crypt was configured to
169167
* request credentials for any KMS provider. */
170168
bool _mongocrypt_needs_credentials(mongocrypt_t *crypt);

src/mongocrypt.c

Lines changed: 1 addition & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -75,31 +75,11 @@ const char *tmp_json(const bson_t *bson) {
7575

7676
memset(storage, 0, 1024);
7777
json = bson_as_canonical_extended_json(bson, NULL);
78-
bson_snprintf(storage, sizeof(storage), "%s", json);
78+
BSON_ASSERT(0 < bson_snprintf(storage, sizeof(storage), "%s", json)); // Truncation OK.
7979
bson_free(json);
8080
return (const char *)storage;
8181
}
8282

83-
const char *tmp_buf(const _mongocrypt_buffer_t *buf) {
84-
static char storage[1024];
85-
size_t i, n;
86-
87-
BSON_ASSERT_PARAM(buf);
88-
89-
memset(storage, 0, 1024);
90-
/* capped at two characters per byte, minus 1 for trailing \0 */
91-
n = sizeof(storage) / 2 - 1;
92-
if (buf->len < n) {
93-
n = buf->len;
94-
}
95-
96-
for (i = 0; i < n; i++) {
97-
bson_snprintf(storage + (i * 2), 3, "%02x", buf->data[i]);
98-
}
99-
100-
return (const char *)storage;
101-
}
102-
10383
static void _mongocrypt_do_init(void) {
10484
(void)kms_message_init();
10585
_native_crypto_init();
@@ -218,47 +198,6 @@ bool mongocrypt_setopt_key_expiration(mongocrypt_t *crypt, uint64_t cache_expira
218198
return true;
219199
}
220200

221-
char *_mongocrypt_new_string_from_bytes(const void *in, int len) {
222-
const int max_bytes = 100;
223-
const int chars_per_byte = 2;
224-
int out_size = max_bytes * chars_per_byte;
225-
const unsigned char *src = in;
226-
char *out;
227-
char *ret;
228-
229-
out_size += len > max_bytes ? (int)sizeof("...") : 1 /* for null */;
230-
out = bson_malloc0((size_t)out_size);
231-
BSON_ASSERT(out);
232-
233-
ret = out;
234-
235-
for (int i = 0; i < len && i < max_bytes; i++, out += chars_per_byte) {
236-
sprintf(out, "%02X", src[i]);
237-
}
238-
239-
sprintf(out, (len > max_bytes) ? "..." : "");
240-
return ret;
241-
}
242-
243-
char *_mongocrypt_new_json_string_from_binary(mongocrypt_binary_t *binary) {
244-
bson_t bson;
245-
uint32_t len;
246-
247-
BSON_ASSERT_PARAM(binary);
248-
249-
if (!_mongocrypt_binary_to_bson(binary, &bson) || !bson_validate(&bson, BSON_VALIDATE_NONE, NULL)) {
250-
char *hex;
251-
char *full_str;
252-
253-
BSON_ASSERT(binary->len <= (uint32_t)INT_MAX);
254-
hex = _mongocrypt_new_string_from_bytes(binary->data, (int)binary->len);
255-
full_str = bson_strdup_printf("(malformed) %s", hex);
256-
bson_free(hex);
257-
return full_str;
258-
}
259-
return bson_as_canonical_extended_json(&bson, (size_t *)&len);
260-
}
261-
262201
bool mongocrypt_setopt_schema_map(mongocrypt_t *crypt, mongocrypt_binary_t *schema_map) {
263202
ASSERT_MONGOCRYPT_PARAM_UNINIT(crypt);
264203

test/test-mongocrypt-assert-match-bson.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ static void match_err(match_ctx_t *ctx, const char *fmt, ...) {
230230
formatted = bson_strdupv_printf(fmt, args);
231231
va_end(args);
232232

233-
bson_snprintf(ctx->errmsg, sizeof ctx->errmsg, "%s: %s", ctx->path, formatted);
233+
BSON_ASSERT(0 < bson_snprintf(ctx->errmsg, sizeof ctx->errmsg, "%s: %s", ctx->path, formatted)); // Truncation OK.
234234

235235
bson_free(formatted);
236236
}
@@ -245,9 +245,9 @@ static void derive(match_ctx_t *ctx, match_ctx_t *derived, const char *key) {
245245
derived->strict_numeric_types = ctx->strict_numeric_types;
246246

247247
if (strlen(ctx->path) > 0) {
248-
bson_snprintf(derived->path, sizeof derived->path, "%s.%s", ctx->path, key);
248+
BSON_ASSERT(0 < bson_snprintf(derived->path, sizeof derived->path, "%s.%s", ctx->path, key)); // Truncation OK.
249249
} else {
250-
bson_snprintf(derived->path, sizeof derived->path, "%s", key);
250+
BSON_ASSERT(0 < bson_snprintf(derived->path, sizeof derived->path, "%s", key)); // Truncation OK.
251251
}
252252
derived->retain_dots_in_keys = ctx->retain_dots_in_keys;
253253
derived->allow_placeholders = ctx->allow_placeholders;

test/test-mongocrypt-buffer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ static void _get_bytes(const void *in, char *out, int len) {
3030
char *dest = out;
3131

3232
for (int i = 0; i < len; i++, dest += 3) {
33-
sprintf(dest, "%02X ", src[i]);
33+
ASSERT(3 == bson_snprintf(dest, 4, "%02X ", src[i]));
3434
}
3535
dest[-1] = '\0';
3636
}

test/test-mongocrypt-marking.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2036,8 +2036,10 @@ static void test_ciphertext_len_steps_fle2_text_search(_mongocrypt_tester_t *tes
20362036
char *v = bson_malloc0(str_len + 1);
20372037
memset(v, 'a', str_len);
20382038
size_t bufsize = snprintf(NULL, 0, MARKING_JSON_FORMAT, v) + 1;
2039+
ASSERT(bufsize > 0);
20392040
char *markingJSON = bson_malloc(bufsize);
2040-
sprintf(markingJSON, MARKING_JSON_FORMAT, v);
2041+
int ret = bson_snprintf(markingJSON, bufsize, MARKING_JSON_FORMAT, v);
2042+
BSON_ASSERT(0 < ret && ret < (int)bufsize);
20412043
bson_t *marking_bson = TMP_BSON_STR(markingJSON);
20422044

20432045
_mongocrypt_ciphertext_t ciphertext;

0 commit comments

Comments
 (0)