diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e7106f3a..bf52c328f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,11 +28,12 @@ - Cap rate-limit retry-after values at 24 hours to prevent a MITM-provided response from disabling event delivery for the process lifetime. ([#1744](https://github.com/getsentry/sentry-native/pull/1744)) - Fix a shutdown-time use-after-free window in `sentry_close()`. ([#1750](https://github.com/getsentry/sentry-native/pull/1750)) - Native: validate ELF header entry sizes. ([#1746](https://github.com/getsentry/sentry-native/pull/1746)) -- Native: clamp `module_count` from the shared crash context before. ([#1770](https://github.com/getsentry/sentry-native/pull/1770)) +- Native: clamp `module_count` from the shared crash context. ([#1770](https://github.com/getsentry/sentry-native/pull/1770)) - Prevent database cleanup from following symlinks in run and cache directories. ([#1751](https://github.com/getsentry/sentry-native/pull/1751)) - Structured logs: respect printf argument widths when extracting log parameters to avoid stack-data disclosure and corrupted attributes on 32-bit platforms. ([#1752](https://github.com/getsentry/sentry-native/pull/1752)) - Fix a potential out-of-bounds read when parsing non-NUL-terminated `sentry-trace` headers. ([#1749](https://github.com/getsentry/sentry-native/pull/1749)) - Fix division by zero when breadcrumbs are disabled. ([#1767](https://github.com/getsentry/sentry-native/pull/1767)) +- Native: escape JSON attachments. ([#1771](https://github.com/getsentry/sentry-native/pull/1771)) - Handle memory allocation failures during JSON serialization to prevent truncated output. ([#1772](https://github.com/getsentry/sentry-native/pull/1772)) ## 0.14.2 diff --git a/src/backends/native/sentry_crash_daemon.c b/src/backends/native/sentry_crash_daemon.c index 308dafeac..19b06fce5 100644 --- a/src/backends/native/sentry_crash_daemon.c +++ b/src/backends/native/sentry_crash_daemon.c @@ -116,32 +116,37 @@ write_attachment_to_envelope(int fd, const char *file_path, #endif // Write attachment item header - char header[SENTRY_CRASH_ENVELOPE_HEADER_SIZE]; - int header_written; + sentry_jsonwriter_t *jw = sentry__jsonwriter_new_sb(NULL); + if (!jw) { + SENTRY_WARN("Failed to create attachment header writer"); +#if defined(SENTRY_PLATFORM_UNIX) + close(attach_fd); +#elif defined(SENTRY_PLATFORM_WINDOWS) + _close(attach_fd); +#endif + return false; + } + + sentry__jsonwriter_write_object_start(jw); + sentry__jsonwriter_write_key(jw, "type"); + sentry__jsonwriter_write_str(jw, "attachment"); + sentry__jsonwriter_write_key(jw, "length"); + sentry__jsonwriter_write_int64(jw, file_size); + sentry__jsonwriter_write_key(jw, "attachment_type"); + sentry__jsonwriter_write_str(jw, + sentry__string_empty(attachment_type) ? SENTRY_ATTACHMENT_TYPE_GENERIC + : attachment_type); if (content_type) { - header_written = snprintf(header, sizeof(header), - "{\"type\":\"attachment\",\"length\":%lld," - "\"attachment_type\":\"%s\"," - "\"content_type\":\"%s\"," - "\"filename\":\"%s\"}\n", - file_size, - sentry__string_empty(attachment_type) - ? SENTRY_ATTACHMENT_TYPE_GENERIC - : attachment_type, - content_type, filename ? filename : "attachment"); - } else { - header_written = snprintf(header, sizeof(header), - "{\"type\":\"attachment\",\"length\":%lld," - "\"attachment_type\":\"%s\"," - "\"filename\":\"%s\"}\n", - file_size, - sentry__string_empty(attachment_type) - ? SENTRY_ATTACHMENT_TYPE_GENERIC - : attachment_type, - filename ? filename : "attachment"); - } - - if (header_written < 0 || header_written >= (int)sizeof(header)) { + sentry__jsonwriter_write_key(jw, "content_type"); + sentry__jsonwriter_write_str(jw, content_type); + } + sentry__jsonwriter_write_key(jw, "filename"); + sentry__jsonwriter_write_str(jw, filename ? filename : "attachment"); + sentry__jsonwriter_write_object_end(jw); + + size_t header_written = 0; + char *header = sentry__jsonwriter_into_string(jw, &header_written); + if (!header) { SENTRY_WARN("Failed to write attachment header"); #if defined(SENTRY_PLATFORM_UNIX) close(attach_fd); @@ -152,12 +157,15 @@ write_attachment_to_envelope(int fd, const char *file_path, } #if defined(SENTRY_PLATFORM_UNIX) - if (write(fd, header, header_written) != (ssize_t)header_written) { + if (write(fd, header, header_written) != (ssize_t)header_written + || write(fd, "\n", 1) != 1) { SENTRY_WARN("Failed to write attachment header to envelope"); } #elif defined(SENTRY_PLATFORM_WINDOWS) _write(fd, header, (unsigned int)header_written); + _write(fd, "\n", 1); #endif + sentry_free(header); // Copy attachment content char buf[SENTRY_CRASH_FILE_BUFFER_SIZE]; diff --git a/src/sentry_json.c b/src/sentry_json.c index 8d2d94748..b68d1a9eb 100644 --- a/src/sentry_json.c +++ b/src/sentry_json.c @@ -287,8 +287,6 @@ write_json_str(sentry_jsonwriter_t *jw, const char *str) { // using unsigned here because utf-8 is > 127 :-) const unsigned char *ptr = (const unsigned char *)str; - write_char(jw, '"'); - const unsigned char *start = ptr; for (; *ptr && !jw->failed; ptr++) { if (!needs_escaping[*ptr]) { @@ -350,8 +348,6 @@ write_json_str(sentry_jsonwriter_t *jw, const char *str) if (len) { write_buf(jw, (const char *)start, len); } - - write_char(jw, '"'); } static bool @@ -444,7 +440,9 @@ sentry__jsonwriter_write_str(sentry_jsonwriter_t *jw, const char *val) return; } if (can_write_item(jw)) { + write_char(jw, '"'); write_json_str(jw, val); + write_char(jw, '"'); } } @@ -473,7 +471,9 @@ void sentry__jsonwriter_write_key(sentry_jsonwriter_t *jw, const char *val) { if (can_write_item(jw)) { + write_char(jw, '"'); write_json_str(jw, val); + write_char(jw, '"'); write_char(jw, ':'); jw->last_was_key = true; }