This compliant solution serializes the structure data before copying it to an untrusted context:
#include <stddef.h>
#include <string.h>
struct test {
int a;
char b;
int c;
};
/* Safely copy bytes to user space */
void copyToUser(void *dest, void *src, size_t size);
void doStuff(void *usrBuf) {
struct test arg = {.a = 1, .b = 2, .c = 3};
uint8_t buf[sizeof(arg)];
size_t offset = 0;
memcpy(buf offset, &arg.a, sizeof(arg.a));
offset = sizeof(arg.a);
memcpy(buf offset, &arg.b, sizeof(arg.b));
offset = sizeof(arg.b);
memcpy(buf offset, &arg.c, sizeof(arg.c));
offset = sizeof(arg.c);
copyToUser(usrBuf, &buf, offset);
}
Would you be so kind as to tell me whether the following unpacking to recreate the original padded structure looks more or less decent or rather cumbersome?
void copyToUser(void *dest, void *src, size_t size) {
size_t offset = 0;
memcpy(&(((struct test *)dest)->a), src offset, sizeof(((struct test *)dest)->a));
offset = sizeof(((struct test *)dest)->a);
memcpy(&(((struct test *)dest)->b), src offset, sizeof(((struct test *)dest)->b));
offset = sizeof(((struct test *)dest)->b);
memcpy(&(((struct test *)dest)->c), src offset, sizeof(((struct test *)dest)->c));
}
CodePudding user response:
I have not noticed that you pack the struct in the buffer
#define MSIZE(st,mem) sizeof((st){0}.mem)
void copyToUserpackedSRC(void * restrict dest, const void * restrict src, size_t offset)
{
unsigned char * restrict udest = dest;
const unsigned char * restrict usrc = src;
memcpy(udest offsetof(struct test, a), usrc offset, MSIZE(struct test, a));
offset = MSIZE(struct test, a);
memcpy(udest offsetof(struct test, b), usrc offset, MSIZE(struct test, b));
offset = MSIZE(struct test, b);
memcpy(udest offsetof(struct test, c), usrc offset, MSIZE(struct test, c));
}
CodePudding user response:
You should build symetric serialize and deSerialize functions:
// Serialize a struct test into a buffer of size sizeof(a) sizeof(b) sizeof(c)
void serialize(char * buffer, struct test *arg) {
memcopy(buffer, &arg.a, sizeof(arg.a));
buffer = sizeof(arg.a);
memcopy(buffer, &arg.b, sizeof(arg.b));
buffer = sizeof(arg.b);
memcopy(buffer, &arg.c, sizeof(arg.c));
}
// Deserialize a buffer into a struct test
void deSerialize(struct test *arg, char *buffer) {
memcopy(&arg.a, buffer, sizeof(arg.a));
buffer = sizeof(arg.a);
memcopy(&arg.b, buffer, sizeof(arg.b));
buffer = sizeof(arg.b);
memcopy(&arg.c, buffer, sizeof(arg.c));
}
But beware, above code does not pay attention to size or endianness of integer types and blindly assumes that they are the same on sender and receiver...
