Home > OS >  Unpacking Serialized Structure Data in C
Unpacking Serialized Structure Data in C

Time:02-01

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);
}

(The CERT® C Coding Standard)

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...

  •  Tags:  
  • Related