Skip to content
This repository has been archived by the owner on Jan 20, 2022. It is now read-only.

Commit

Permalink
[LibOS] Fix poll() crashing on pseudo-files
Browse files Browse the repository at this point in the history
The code assumed that all handles (other than TYPE_FILE and TYPE_DEV)
had an associated PAL handle, which caused a crash when polling files
from /proc. This change adds support for polling TYPE_STR, and also adds
a check for PAL handle in all cases.
  • Loading branch information
pwmarcz committed Jul 2, 2021
1 parent c25a0f4 commit eeb160e
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 41 deletions.
1 change: 1 addition & 0 deletions LibOS/shim/include/shim_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -695,5 +695,6 @@ ssize_t str_write(struct shim_handle* hdl, const void* buf, size_t count);
off_t str_seek(struct shim_handle* hdl, off_t offset, int whence);
int str_flush(struct shim_handle* hdl);
int str_truncate(struct shim_handle* hdl, off_t len);
off_t str_poll(struct shim_handle* hdl, int poll_type);

#endif /* _SHIM_FS_H_ */
11 changes: 6 additions & 5 deletions LibOS/shim/src/fs/shim_fs_pseudo.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,25 +442,26 @@ static int pseudo_close(struct shim_handle* hdl) {
}
}

/* TODO: add support for polling TYPE_STR handles; currently `shim_do_poll` doesn't call this for
* anything else than TYPE_STR and TYPE_DEV */
static off_t pseudo_poll(struct shim_handle* hdl, int poll_type) {
if (poll_type == FS_POLL_SZ)
return 0;

assert(hdl->dentry);
struct pseudo_node* node = pseudo_find(hdl->dentry);
if (!node)
return -ENOENT;
switch (node->type) {
case PSEUDO_DEV: {
if (poll_type == FS_POLL_SZ)
return 0;

off_t ret = 0;
if ((poll_type & FS_POLL_RD) && node->dev.dev_ops.read)
ret |= FS_POLL_RD;
if ((poll_type & FS_POLL_WR) && node->dev.dev_ops.write)
ret |= FS_POLL_WR;
return ret;
}
case PSEUDO_STR:
return str_poll(hdl, poll_type);

default:
return -ENOSYS;
}
Expand Down
25 changes: 25 additions & 0 deletions LibOS/shim/src/fs/str/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,38 @@ int str_truncate(struct shim_handle* hdl, off_t len) {
return ret;
}

off_t str_poll(struct shim_handle* hdl, int poll_type) {
assert(hdl->type == TYPE_STR);

struct shim_str_handle* strhdl = &hdl->info.str;
struct shim_str_data* data = strhdl->data;
assert(data);

if (poll_type == FS_POLL_SZ)
return data->len;

off_t ret = 0;
if (poll_type & FS_POLL_RD) {
if (data->len > 0) {
assert(data->str);
if (!strhdl->ptr || strhdl->ptr < (data->str + data->len))
ret |= FS_POLL_RD;
}
}
if (poll_type & FS_POLL_WR)
ret |= FS_POLL_WR;

return ret;
}

struct shim_fs_ops str_fs_ops = {
.close = &str_close,
.read = &str_read,
.write = &str_write,
.seek = &str_seek,
.flush = &str_flush,
.truncate = &str_truncate,
.poll = &str_poll,
};

struct shim_d_ops str_d_ops = {
Expand Down
16 changes: 13 additions & 3 deletions LibOS/shim/src/sys/shim_poll.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,12 @@ static long _shim_do_poll(struct pollfd* fds, nfds_t nfds, int timeout_ms) {
continue;
}

if (hdl->type == TYPE_FILE || hdl->type == TYPE_DEV) {
/* Files and devs are special cases: their poll is emulated at LibOS level; do not
* include them in handles-to-poll array but instead use handle-specific callback. */
if (hdl->type == TYPE_FILE || hdl->type == TYPE_DEV || hdl->type == TYPE_STR) {
/* Files, devs and strings are special cases: their poll is emulated at LibOS level; do
* not include them in handles-to-poll array but instead use handle-specific
* callback.
*
* TODO: we probably should use the poll() callback in all cases. */
int shim_events = 0;
if ((fds[i].events & (POLLIN | POLLRDNORM)) && (hdl->acc_mode & MAY_READ))
shim_events |= FS_POLL_RD;
Expand All @@ -119,6 +122,13 @@ static long _shim_do_poll(struct pollfd* fds, nfds_t nfds, int timeout_ms) {
if (shim_revents & FS_POLL_WR)
fds[i].revents |= fds[i].events & (POLLOUT | POLLWRNORM);

if (fds[i].revents)
nrevents++;
continue;
}

if (!hdl->pal_handle) {
fds[i].revents = POLLNVAL;
nrevents++;
continue;
}
Expand Down
132 changes: 102 additions & 30 deletions LibOS/shim/test/regression/poll.c
Original file line number Diff line number Diff line change
@@ -1,44 +1,116 @@
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/* Copyright (C) 2021 Intel Corporation
* Paweł Marczewski <pawel@invisiblethingslab.com>
*/

/* Simple sanity check for poll() on various file types. */

#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main(void) {
static void check_poll(int fd, short events, int revents) {
struct pollfd fds[] = {
{.fd = fd, .events = events, .revents = 0},
};

int ret = poll(fds, /*nfds=*/1, /*timeout=*/0);
fprintf(stderr, "poll {events = 0x%x} = %d", events, ret);
if (ret == 1)
fprintf(stderr, "; {revents = 0x%x}", (int)fds[0].revents);
fprintf(stderr, "\n");
fflush(stderr);
if (ret < 0)
err(1, "poll");

int expected = revents ? 1 : 0;
if (ret != expected)
errx(1, "expected poll to return %d\n", expected);

if (ret == 1 && fds[0].revents != revents)
errx(1, "expected revents to be 0x%x", revents);
}

static void write_byte(int fd, char c) {
ssize_t n;
do {
char c = 0;
n = write(fd, &c, sizeof(c));
} while (n == -1 && errno == EINTR);
if (n == -1)
err(1, "write");
if (n != 1)
errx(1, "write returned %ld", n);
}

static void test_pipe(void) {
printf("testing poll() on pipe...\n");
int ret;
int fd[2];
char string[] = "Hello, world!\n";

ret = pipe(fd);
if (ret < 0) {
perror("pipe creation failed");
return 1;
}
int fds[2];
ret = pipe(fds);
if (ret < 0)
err(1, "pipe");

struct pollfd outfds[] = {
{.fd = fd[1], .events = POLLOUT},
};
ret = poll(outfds, 1, -1);
if (ret <= 0) {
perror("poll with POLLOUT failed");
return 1;
}
printf("poll(POLLOUT) returned %d file descriptors\n", ret);
check_poll(fds[1], POLLOUT, POLLOUT);
check_poll(fds[0], POLLIN, 0);

struct pollfd infds[] = {
{.fd = fd[0], .events = POLLIN},
};
size_t size = strlen(string) + 1;
if (write(fd[1], string, size) != size) {
perror("write error");
return 1;
}
ret = poll(infds, 1, -1);
if (ret <= 0) {
perror("poll with POLLIN failed");
return 1;
write_byte(fds[1], 0);

check_poll(fds[0], POLLIN, POLLIN);

if (close(fds[0]) < 0 || close(fds[1]) < 0)
err(1, "close");
}

static void test_file(const char* path, int flags, int events1, int revents1, int events2,
int revents2) {
printf("testing poll() on %s...\n", path);

int fd = open(path, flags, 0600);
if (fd < 0)
err(1, "open");

if (events1)
check_poll(fd, events1, revents1);

if (events2)
check_poll(fd, events2, revents2);

if (close(fd) < 0)
err(1, "close");

if (flags & O_CREAT) {
if (unlink(path) < 0)
err(1, "unlink");
}
printf("poll(POLLIN) returned %d file descriptors\n", ret);
}

int main(int argc, char** argv) {
setbuf(stdout, NULL);
setbuf(stderr, NULL);

test_pipe();

/* Emulated device */
test_file("/dev/null", O_RDWR, POLLIN, POLLIN, POLLOUT, POLLOUT);

/* File in /proc/ */
test_file("/proc/meminfo", O_RDONLY, POLLIN, POLLIN, 0, 0);

/* Host file */
test_file(argv[0], O_RDONLY, POLLIN, POLLIN, 0, 0);

/* Host file (empty) */
test_file("tmp/host_file", O_RDWR | O_CREAT | O_TRUNC, POLLIN, 0, POLLOUT, POLLOUT);

printf("TEST OK\n");
return 0;
}
9 changes: 6 additions & 3 deletions LibOS/shim/test/regression/test_libos.py
Original file line number Diff line number Diff line change
Expand Up @@ -816,9 +816,12 @@ def test_011_epoll_epollet(self):
self.assertIn('TEST OK', stdout)

def test_020_poll(self):
stdout, _ = self.run_binary(['poll'])
self.assertIn('poll(POLLOUT) returned 1 file descriptors', stdout)
self.assertIn('poll(POLLIN) returned 1 file descriptors', stdout)
try:
stdout, _ = self.run_binary(['poll'])
finally:
if os.path.exists("tmp/host_file"):
os.remove("tmp/host_file")
self.assertIn('TEST OK', stdout)

def test_021_poll_many_types(self):
stdout, _ = self.run_binary(['poll_many_types'])
Expand Down

0 comments on commit eeb160e

Please sign in to comment.