unix: reject non-tty fds in uv_tty_init()

Reject file descriptors that correspond to regular files or char/block
devices.  Such file descriptors are incompatible with epoll and trigger
a run-time assert.

Fixes: https://github.com/libuv/libuv/issues/255
PR-URL: https://github.com/libuv/libuv/pull/259
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
This commit is contained in:
Ben Noordhuis 2015-03-11 16:05:56 +01:00
parent 1df46fe478
commit fc9e66e555
4 changed files with 58 additions and 1 deletions

View File

@ -66,6 +66,10 @@ API
If opening ``/dev/tty`` fails, libuv falls back to blocking writes for
non-readable TTY streams.
.. versionchanged:: 1.5.0: trying to initialize a TTY stream with a file
descriptor that refers to a file returns `UV_EINVAL`
on UNIX.
.. c:function:: int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode)
.. versionchanged:: 1.2.0: the mode is specified as a

View File

@ -35,10 +35,19 @@ static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
uv_handle_type type;
int flags;
int newfd;
int r;
/* File descriptors that refer to files cannot be monitored with epoll.
* That restriction also applies to character devices like /dev/random
* (but obviously not /dev/tty.)
*/
type = uv_guess_handle(fd);
if (type == UV_FILE || type == UV_UNKNOWN_HANDLE)
return -EINVAL;
flags = 0;
newfd = -1;
@ -54,7 +63,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
* different struct file, hence changing its properties doesn't affect
* other processes.
*/
if (isatty(fd)) {
if (type == UV_TTY) {
r = uv__open_cloexec("/dev/tty", O_RDWR);
if (r < 0) {

View File

@ -43,6 +43,7 @@ TEST_DECLARE (semaphore_1)
TEST_DECLARE (semaphore_2)
TEST_DECLARE (semaphore_3)
TEST_DECLARE (tty)
TEST_DECLARE (tty_file)
TEST_DECLARE (stdio_over_pipes)
TEST_DECLARE (ip6_pton)
TEST_DECLARE (ipc_listen_before_write)
@ -343,6 +344,7 @@ TASK_LIST_START
#endif
TEST_ENTRY (pipe_set_non_blocking)
TEST_ENTRY (tty)
TEST_ENTRY (tty_file)
TEST_ENTRY (stdio_over_pipes)
TEST_ENTRY (ip6_pton)
TEST_ENTRY (ipc_listen_before_write)

View File

@ -135,3 +135,45 @@ TEST_IMPL(tty) {
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(tty_file) {
#ifndef _WIN32
uv_loop_t loop;
uv_tty_t tty;
int fd;
ASSERT(0 == uv_loop_init(&loop));
fd = open("test/fixtures/empty_file", O_RDONLY);
if (fd != -1) {
ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1));
ASSERT(0 == close(fd));
}
fd = open("/dev/random", O_RDONLY);
if (fd != -1) {
ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1));
ASSERT(0 == close(fd));
}
fd = open("/dev/zero", O_RDONLY);
if (fd != -1) {
ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1));
ASSERT(0 == close(fd));
}
fd = open("/dev/tty", O_RDONLY);
if (fd != -1) {
ASSERT(0 == uv_tty_init(&loop, &tty, fd, 1));
ASSERT(0 == close(fd));
}
uv_close((uv_handle_t*) &tty, NULL);
ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
ASSERT(0 == uv_loop_close(&loop));
MAKE_VALGRIND_HAPPY();
#endif
return 0;
}