46 lines
1.1 KiB
C
46 lines
1.1 KiB
C
/*
|
|
* Clean reference implementation - no exploitable vulnerability.
|
|
* Looks superficially scary (memcpy, length fields, allocation from network input)
|
|
* but every read is bounds-checked against the actual record length.
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#define MAX_PAYLOAD 4096
|
|
|
|
typedef struct {
|
|
const uint8_t *data;
|
|
size_t length;
|
|
} record_t;
|
|
|
|
int copy_bounded_payload(const record_t *rec, uint8_t **out, size_t *out_len) {
|
|
if (rec == NULL || rec->data == NULL || rec->length < 2) {
|
|
return -1;
|
|
}
|
|
|
|
/* Declared payload length is the first two bytes of the record. */
|
|
size_t declared = ((size_t)rec->data[0] << 8) | (size_t)rec->data[1];
|
|
|
|
/* Bounds checks: declared must fit within remaining record bytes AND a cap. */
|
|
if (declared > rec->length - 2) {
|
|
return -2;
|
|
}
|
|
if (declared > MAX_PAYLOAD) {
|
|
return -3;
|
|
}
|
|
|
|
uint8_t *buf = (uint8_t *)malloc(declared);
|
|
if (buf == NULL) {
|
|
return -4;
|
|
}
|
|
|
|
memcpy(buf, rec->data + 2, declared);
|
|
|
|
*out = buf;
|
|
*out_len = declared;
|
|
return 0;
|
|
}
|