Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updates to serdes APIs #126

Merged
merged 4 commits into from
May 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 35 additions & 17 deletions include/wasi_serdes.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,26 @@ BASIC_TYPE_UVWASI(whence_t)

/* WASI structure read/write functions. */

#define STRUCT(name) \
#define STRUCT(name) \
void uvwasi_serdes_write_##name(void* ptr, \
size_t offset, \
const uvwasi_##name* value); \
void uvwasi_serdes_read_##name(const void* ptr, \
size_t offset, \
uvwasi_##name* value); \
uvwasi_##name* value);

/* iovs currently only need to be read from WASM memory. */
#define IOVS_STRUCT(name) \
uvwasi_errno_t uvwasi_serdes_read_##name(const void* ptr, \
size_t end, \
size_t offset, \
uvwasi_##name* value);

#define UVWASI_SERDES_SIZE_ciovec_t 8
IOVS_STRUCT(ciovec_t)

#define UVWASI_SERDES_SIZE_iovec_t 8
IOVS_STRUCT(iovec_t)

#define UVWASI_SERDES_SIZE_fdstat_t 24
STRUCT(fdstat_t)
Expand All @@ -108,20 +121,25 @@ STRUCT(event_t)
STRUCT(subscription_t)

#undef STRUCT

/* Helper macros for bound checking. */

#define UVWASI_SERDES_CHECK_BOUNDS(offset, end, type) \
((offset) >= 0 && \
(end) > (offset) && \
(UVWASI_SERDES_SIZE_##type <= (end) - (offset))) \

#define UVWASI_SERDES_CHECK_ARRAY_BOUNDS(offset, end, type, count) \
((offset) >= 0 && \
(end) > (offset) && \
(count) >= 0 && \
((count) * UVWASI_SERDES_SIZE_##type) / UVWASI_SERDES_SIZE_##type == \
(count) && \
((count) * UVWASI_SERDES_SIZE_##type <= (end) - (offset))) \
#undef IOVS_STRUCT

uvwasi_errno_t uvwasi_serdes_readv_ciovec_t(const void* ptr,
size_t end,
size_t offset,
uvwasi_ciovec_t* iovs,
uvwasi_size_t iovs_len);

uvwasi_errno_t uvwasi_serdes_readv_iovec_t(const void* ptr,
size_t end,
size_t offset,
uvwasi_iovec_t* iovs,
uvwasi_size_t iovs_len);

/* Helper functions for memory bounds checking. */
int uvwasi_serdes_check_bounds(size_t offset, size_t end, size_t size);
int uvwasi_serdes_check_array_bounds(size_t offset,
size_t end,
size_t size,
size_t count);

#endif /* __UVWASI_SERDES_H__ */
87 changes: 87 additions & 0 deletions src/wasi_serdes.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,90 @@ uint8_t uvwasi_serdes_read_uint8_t(const void* ptr, size_t offset) {

ALL_TYPES(WRITE_STRUCT, WRITE_FIELD, WRITE_ALIAS)
ALL_TYPES(READ_STRUCT, READ_FIELD, READ_ALIAS)


uvwasi_errno_t uvwasi_serdes_read_ciovec_t(const void* ptr,
size_t end,
size_t offset,
uvwasi_ciovec_t* value) {
uint32_t buf_ptr;

buf_ptr = uvwasi_serdes_read_uint32_t(ptr, offset);
value->buf_len = uvwasi_serdes_read_size_t(ptr, offset + 4);

if (!uvwasi_serdes_check_bounds(buf_ptr, end, value->buf_len))
return UVWASI_EOVERFLOW;

value->buf = ((uint8_t*) ptr + buf_ptr);
return UVWASI_ESUCCESS;
}


uvwasi_errno_t uvwasi_serdes_read_iovec_t(const void* ptr,
size_t end,
size_t offset,
uvwasi_iovec_t* value) {
uint32_t buf_ptr;

buf_ptr = uvwasi_serdes_read_uint32_t(ptr, offset);
value->buf_len = uvwasi_serdes_read_size_t(ptr, offset + 4);

if (!uvwasi_serdes_check_bounds(buf_ptr, end, value->buf_len))
return UVWASI_EOVERFLOW;

value->buf = ((uint8_t*) ptr + buf_ptr);
return UVWASI_ESUCCESS;
}


uvwasi_errno_t uvwasi_serdes_readv_ciovec_t(const void* ptr,
size_t end,
size_t offset,
uvwasi_ciovec_t* iovs,
uvwasi_size_t iovs_len) {
uvwasi_errno_t err;
uvwasi_size_t i;

for (i = 0; i < iovs_len; i++) {
err = uvwasi_serdes_read_ciovec_t(ptr, end, offset, &iovs[i]);
if (err != UVWASI_ESUCCESS)
return err;
offset += UVWASI_SERDES_SIZE_ciovec_t;
}

return UVWASI_ESUCCESS;
}


uvwasi_errno_t uvwasi_serdes_readv_iovec_t(const void* ptr,
size_t end,
size_t offset,
uvwasi_iovec_t* iovs,
uvwasi_size_t iovs_len) {
uvwasi_errno_t err;
uvwasi_size_t i;

for (i = 0; i < iovs_len; i++) {
err = uvwasi_serdes_read_iovec_t(ptr, end, offset, &iovs[i]);
if (err != UVWASI_ESUCCESS)
return err;
offset += UVWASI_SERDES_SIZE_iovec_t;
}

return UVWASI_ESUCCESS;
}


int uvwasi_serdes_check_bounds(size_t offset, size_t end, size_t size) {
return end > offset && size <= (end - offset);
}


int uvwasi_serdes_check_array_bounds(size_t offset,
size_t end,
size_t size,
size_t count) {
return end > offset &&
((count * size) / size == count) &&
(count * size <= end - offset);
}
72 changes: 38 additions & 34 deletions test/test-serdes.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,43 +44,47 @@ void check_canaries(const char* ptr, size_t size) {
}

void test_bound_checks(void) {
/* Regardless of the type, the macro should catch negative offsets
and sizes. */
assert(!UVWASI_SERDES_CHECK_BOUNDS(-500, 1000, uint8_t));
assert(!UVWASI_SERDES_CHECK_BOUNDS(-500, -100, uint16_t));
assert(!UVWASI_SERDES_CHECK_BOUNDS(5000, 1000, uint32_t));
assert(!UVWASI_SERDES_CHECK_BOUNDS(-500, 1000, uint64_t));
assert(!UVWASI_SERDES_CHECK_BOUNDS(-500, -100, event_t));
assert(!UVWASI_SERDES_CHECK_BOUNDS(5000, 1000, fdstat_t));
assert(!UVWASI_SERDES_CHECK_ARRAY_BOUNDS(0, 1000, filestat_t, -1));
/* This causes an integer overflow, which should be detected correctly. */
assert(!UVWASI_SERDES_CHECK_ARRAY_BOUNDS(0, 0xffffffffffffffffllu,
subscription_t,
assert(!uvwasi_serdes_check_array_bounds(0,
0xffffffffffffffffllu,
UVWASI_SERDES_SIZE_subscription_t,
0xffffffffffffffffllu));

assert(UVWASI_SERDES_CHECK_BOUNDS(19, 20, uint8_t));
assert(!UVWASI_SERDES_CHECK_BOUNDS(20, 20, uint8_t));
assert(UVWASI_SERDES_CHECK_BOUNDS(18, 20, uint16_t));
assert(!UVWASI_SERDES_CHECK_BOUNDS(19, 20, uint16_t));
assert(UVWASI_SERDES_CHECK_BOUNDS(16, 20, uint32_t));
assert(!UVWASI_SERDES_CHECK_BOUNDS(17, 20, uint32_t));
assert(UVWASI_SERDES_CHECK_BOUNDS(12, 20, uint64_t));
assert(!UVWASI_SERDES_CHECK_BOUNDS(13, 20, uint64_t));
assert(UVWASI_SERDES_CHECK_BOUNDS(0, 24, fdstat_t));
assert(!UVWASI_SERDES_CHECK_BOUNDS(1, 24, fdstat_t));
assert(UVWASI_SERDES_CHECK_BOUNDS(0, 64, filestat_t));
assert(!UVWASI_SERDES_CHECK_BOUNDS(1, 64, filestat_t));
assert(UVWASI_SERDES_CHECK_BOUNDS(0, 8, prestat_t));
assert(!UVWASI_SERDES_CHECK_BOUNDS(1, 8, prestat_t));
assert(UVWASI_SERDES_CHECK_BOUNDS(0, 32, event_t));
assert(!UVWASI_SERDES_CHECK_BOUNDS(1, 32, event_t));
assert(UVWASI_SERDES_CHECK_BOUNDS(0, 48, subscription_t));
assert(!UVWASI_SERDES_CHECK_BOUNDS(1, 48, subscription_t));

assert(UVWASI_SERDES_CHECK_ARRAY_BOUNDS(0, 480, subscription_t, 10));
assert(!UVWASI_SERDES_CHECK_ARRAY_BOUNDS(1, 480, subscription_t, 10));
assert(UVWASI_SERDES_CHECK_ARRAY_BOUNDS(0, 8000, inode_t, 1000));
assert(!UVWASI_SERDES_CHECK_ARRAY_BOUNDS(1, 8000, inode_t, 1000));
assert(uvwasi_serdes_check_bounds(19, 20, UVWASI_SERDES_SIZE_uint8_t));
assert(!uvwasi_serdes_check_bounds(20, 20, UVWASI_SERDES_SIZE_uint8_t));
assert(uvwasi_serdes_check_bounds(18, 20, UVWASI_SERDES_SIZE_uint16_t));
assert(!uvwasi_serdes_check_bounds(19, 20, UVWASI_SERDES_SIZE_uint16_t));
assert(uvwasi_serdes_check_bounds(16, 20, UVWASI_SERDES_SIZE_uint32_t));
assert(!uvwasi_serdes_check_bounds(17, 20, UVWASI_SERDES_SIZE_uint32_t));
assert(uvwasi_serdes_check_bounds(12, 20, UVWASI_SERDES_SIZE_uint64_t));
assert(!uvwasi_serdes_check_bounds(13, 20, UVWASI_SERDES_SIZE_uint64_t));
assert(uvwasi_serdes_check_bounds(0, 24, UVWASI_SERDES_SIZE_fdstat_t));
assert(!uvwasi_serdes_check_bounds(1, 24, UVWASI_SERDES_SIZE_fdstat_t));
assert(uvwasi_serdes_check_bounds(0, 64, UVWASI_SERDES_SIZE_filestat_t));
assert(!uvwasi_serdes_check_bounds(1, 64, UVWASI_SERDES_SIZE_filestat_t));
assert(uvwasi_serdes_check_bounds(0, 8, UVWASI_SERDES_SIZE_prestat_t));
assert(!uvwasi_serdes_check_bounds(1, 8, UVWASI_SERDES_SIZE_prestat_t));
assert(uvwasi_serdes_check_bounds(0, 32, UVWASI_SERDES_SIZE_event_t));
assert(!uvwasi_serdes_check_bounds(1, 32, UVWASI_SERDES_SIZE_event_t));
assert(uvwasi_serdes_check_bounds(0, 48, UVWASI_SERDES_SIZE_subscription_t));
assert(!uvwasi_serdes_check_bounds(1, 48, UVWASI_SERDES_SIZE_subscription_t));

assert(uvwasi_serdes_check_array_bounds(0,
480,
UVWASI_SERDES_SIZE_subscription_t,
10));
assert(!uvwasi_serdes_check_array_bounds(1,
480,
UVWASI_SERDES_SIZE_subscription_t,
10));
assert(uvwasi_serdes_check_array_bounds(0,
8000,
UVWASI_SERDES_SIZE_inode_t,
1000));
assert(!uvwasi_serdes_check_array_bounds(1,
8000,
UVWASI_SERDES_SIZE_inode_t,
1000));
}

void test_basic_types(void) {
Expand Down