Skip to content

Commit

Permalink
Prevent offset wrapping in fd_pread (nodejs#258)
Browse files Browse the repository at this point in the history
This commit inserts a bounds check in `fd_pread` for the `offset`
parameter.  This is necessary because an implicit unsigned-to-signed
integer conversion is performed when `uv_fs_read` is called.  Such a
conversion results in implementation-defined behavior.  One such
behavior is the offset wrapping.

fixes nodejs#257
  • Loading branch information
yagehu authored Apr 18, 2024
1 parent 1595ce3 commit d420a05
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/uvwasi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1158,7 +1158,7 @@ uvwasi_errno_t uvwasi_fd_pread(uvwasi_t* uvwasi,
offset,
nread);

if (uvwasi == NULL || iovs == NULL || nread == NULL)
if (uvwasi == NULL || iovs == NULL || nread == NULL || offset > INT64_MAX)
return UVWASI_EINVAL;

err = uvwasi_fd_table_get(uvwasi->fds,
Expand Down
84 changes: 84 additions & 0 deletions test/test-fd-pread-large-offset.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "uvwasi.h"
#include "uv.h"
#include "test-common.h"

#define TEST_TMP_DIR "./out/tmp"

int main(void) {
const char* path = "file.txt";
uvwasi_t uvwasi;
uvwasi_iovec_t* iovs;
uvwasi_fd_t fd;
uvwasi_filesize_t large_offset = (uint64_t) INT64_MAX + 1;
uvwasi_options_t init_options;
uvwasi_rights_t fs_rights_base;
uvwasi_size_t nread;
uvwasi_size_t iovs_len = 1;
uvwasi_errno_t err;
uv_fs_t req;
int r;

setup_test_environment();

r = uv_fs_mkdir(NULL, &req, TEST_TMP_DIR, 0777, NULL);
uv_fs_req_cleanup(&req);
assert(r == 0 || r == UV_EEXIST);

uvwasi_options_init(&init_options);
init_options.preopenc = 1;
init_options.preopens = calloc(1, sizeof(uvwasi_preopen_t));
init_options.preopens[0].mapped_path = "/var";
init_options.preopens[0].real_path = TEST_TMP_DIR;

err = uvwasi_init(&uvwasi, &init_options);
assert(err == 0);

// Create a file.
fs_rights_base = UVWASI_RIGHT_FD_DATASYNC |
UVWASI_RIGHT_FD_FILESTAT_GET |
UVWASI_RIGHT_FD_FILESTAT_SET_SIZE |
UVWASI_RIGHT_FD_READ |
UVWASI_RIGHT_FD_SEEK |
UVWASI_RIGHT_FD_SYNC |
UVWASI_RIGHT_FD_TELL |
UVWASI_RIGHT_FD_WRITE |
UVWASI_RIGHT_PATH_UNLINK_FILE;
err = uvwasi_path_open(&uvwasi,
3,
1,
path,
strlen(path) + 1,
UVWASI_O_CREAT,
fs_rights_base,
0,
0,
&fd);
assert(err == 0);

iovs = calloc(iovs_len, sizeof(uvwasi_iovec_t));
assert(iovs != NULL);

for (int i = 0; i < iovs_len; i++) {
iovs[i].buf_len = 1;
iovs[i].buf = malloc(1);
}

err = uvwasi_fd_pread(&uvwasi, fd, iovs, iovs_len, large_offset, &nread);
assert(err == UVWASI_EINVAL);

uvwasi_destroy(&uvwasi);

for (int i = 0; i < iovs_len; i++) {
free((void *) iovs[i].buf);
}

free(iovs);
free(init_options.preopens);

return 0;
}

0 comments on commit d420a05

Please sign in to comment.