process_jpg_image(): bail out early when the input is shorter than the
minimum needed to safely access the SOF fields referenced as p[4..7].
Pointer-arithmetic associativity already makes the existing
`end = p + data->len - 8` benign on standard targets (the loop simply
doesn't execute for tiny buffers), but the explicit precondition makes
the intent obvious and is robust against future refactors.
rspamd_decode_qp2047_buf(): when an encoded-word ends with a bare `=`
that has no following hex digits, emit a literal `=` instead of reading
one byte past the input. Two paths could reach the OOB read - the
direct `*p == '='` block and the else-branch's `goto decode` after
memcspn finds a trailing `=` - both are now guarded. In production the
read landed inside the surrounding header-value buffer (mempool
allocated, null-terminated), so this is cosmetic, but it silences
fuzzer/ASAN noise on direct-call test harnesses.
uint16_t h, w;
struct rspamd_image *img;
+ /*
+ * Need room for the 2-byte SOI plus a marker (2 bytes) plus the
+ * SOF fields (8 bytes) referenced as p[4..7] below.
+ */
+ if (data->len < 12) {
+ return NULL;
+ }
+
img = rspamd_mempool_alloc0(pool, sizeof(struct rspamd_image));
img->type = IMAGE_TYPE_JPG;
img->data = data;
remain--;
if (remain == 0) {
+ /* Last '=' character without following hex digits */
if (end - o > 0) {
- *o++ = *p;
- break;
+ *o++ = '=';
}
+ break;
}
decode:
/* Decode character after '=' */
p++;
/* Skip comparison, as we know that we have found match */
remain--;
+
+ if (remain == 0) {
+ /* Trailing '=' without hex digits */
+ if (end - o > 0) {
+ *o++ = '=';
+ }
+ break;
+ }
goto decode;
}
else {