]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
tree-wide: check POLLNVAL everywhere
authorLennart Poettering <lennart@poettering.net>
Tue, 9 Jun 2020 11:40:25 +0000 (13:40 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 10 Jun 2020 06:57:31 +0000 (08:57 +0200)
poll() sets POLLNVAL inside of the poll structures if an invalid fd is
passed. So far we generally didn't check for that, thus not taking
notice of the error. Given that this specific kind of error is generally
indication of a programming error, and given that our code is embedded
into our projects via NSS or because people link against our library,
let's explicitly check for this and convert it to EBADF.

(I ran into a busy loop because of this missing check when some of my
test code accidentally closed an fd it shouldn't close, so this is a
real thing)

17 files changed:
src/basic/io-util.c
src/basic/socket-util.c
src/journal/journalctl.c
src/libsystemd/sd-bus/bus-socket.c
src/libsystemd/sd-bus/sd-bus.c
src/libsystemd/sd-daemon/sd-daemon.c
src/libsystemd/sd-netlink/sd-netlink.c
src/libudev/libudev-monitor.c
src/shared/ask-password-api.c
src/shared/barrier.c
src/shared/utmp-wtmp.c
src/shared/varlink.c
src/sleep/sleep.c
src/stdio-bridge/stdio-bridge.c
src/tty-ask-password-agent/tty-ask-password-agent.c
src/udev/udevadm-settle.c
src/userdb/userwork.c

index c906fc074171921fa3ff7ad6db0e05aab3db2595..4b3d1c814f5045bdebdbc0cfe9d738113c1afde0 100644 (file)
@@ -33,10 +33,13 @@ int flush_fd(int fd) {
                                 continue;
 
                         return -errno;
-
-                } else if (r == 0)
+                }
+                if (r == 0)
                         return count;
 
+                if (pollfd.revents & POLLNVAL)
+                        return -EBADF;
+
                 l = read(fd, buf, sizeof(buf));
                 if (l < 0) {
 
@@ -169,6 +172,9 @@ int pipe_eof(int fd) {
         if (r == 0)
                 return 0;
 
+        if (pollfd.revents & POLLNVAL)
+                return -EBADF;
+
         return pollfd.revents & POLLHUP;
 }
 
@@ -188,6 +194,9 @@ int fd_wait_for_event(int fd, int event, usec_t t) {
         if (r == 0)
                 return 0;
 
+        if (pollfd.revents & POLLNVAL)
+                return -EBADF;
+
         return pollfd.revents;
 }
 
index 05dd7e70014fc836052979113e4ad90ce81854ee..2c990047fc6b51e3910c8218b582fc2a3e3b31ea 100644 (file)
@@ -1002,6 +1002,9 @@ int flush_accept(int fd) {
                 if (r == 0)
                         return 0;
 
+                if (pollfd.revents & POLLNVAL)
+                        return -EBADF;
+
                 if (iteration >= MAX_FLUSH_ITERATIONS)
                         return log_debug_errno(SYNTHETIC_ERRNO(EBUSY),
                                                "Failed to flush connections within " STRINGIFY(MAX_FLUSH_ITERATIONS) " iterations.");
index a082995498f993e07b269a0fb26291ed22e9e5b9..859f4bbd44a9b9a26c722b3242b4c9f8f13ffc3f 100644 (file)
@@ -2093,10 +2093,13 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
                 return log_error_errno(errno, "Couldn't wait for journal event: %m");
         }
 
-        if (pollfds[1].revents & (POLLHUP|POLLERR)) /* STDOUT has been closed? */
+        if (pollfds[1].revents & (POLLHUP|POLLERR|POLLNVAL)) /* STDOUT has been closed? */
                 return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED),
                                        "Standard output has been closed.");
 
+        if (pollfds[0].revents & POLLNVAL)
+                return log_debug_errno(SYNTHETIC_ERRNO(EBADF), "Change fd closed?");
+
         r = sd_journal_process(j);
         if (r < 0)
                 return log_error_errno(r, "Failed to process journal events: %m");
index acc313d164bf59fc149e757b79ef1b7e81a6eb49..778f80377f811d358995f64c93a97fe924e585cd 100644 (file)
@@ -1275,6 +1275,8 @@ int bus_socket_process_opening(sd_bus *b) {
         r = poll(&p, 1, 0);
         if (r < 0)
                 return -errno;
+        if (p.revents & POLLNVAL)
+                return -EBADF;
 
         if (!(p.revents & (POLLOUT|POLLERR|POLLHUP)))
                 return 0;
index cd1a79a256dfadfeeca3bd28574c66bbb334eb0a..9de5e454a6b1f41c585b6cbda8c3e3809d030aab 100644 (file)
@@ -3121,8 +3121,15 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
         r = ppoll(p, n, m == USEC_INFINITY ? NULL : timespec_store(&ts, m), NULL);
         if (r < 0)
                 return -errno;
+        if (r == 0)
+                return 0;
+
+        if (p[0].revents & POLLNVAL)
+                return -EBADF;
+        if (n >= 2 && (p[1].revents & POLLNVAL))
+                return -EBADF;
 
-        return r > 0 ? 1 : 0;
+        return 1;
 }
 
 _public_ int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec) {
index 587a1f2595bfe19da4248985aa0d1a75a319c18d..0bc0fc16ae5c718e4e6b42cdf041f49c6fa5aa69 100644 (file)
@@ -577,6 +577,8 @@ _public_ int sd_notify_barrier(int unset_environment, uint64_t timeout) {
                 return -errno;
         if (r == 0)
                 return -ETIMEDOUT;
+        if (pfd.revents & POLLNVAL)
+                return -EBADF;
 
         return 1;
 }
index 5b7081089e4a92dbb6c753bdf55cfdea30899402..ddeb4a79924d91f92d19f9311bfaf1828379ac23 100644 (file)
@@ -462,7 +462,6 @@ static usec_t calc_elapse(uint64_t usec) {
 }
 
 static int rtnl_poll(sd_netlink *rtnl, bool need_more, uint64_t timeout_usec) {
-        struct pollfd p[1] = {};
         struct timespec ts;
         usec_t m = USEC_INFINITY;
         int r, e;
@@ -495,14 +494,21 @@ static int rtnl_poll(sd_netlink *rtnl, bool need_more, uint64_t timeout_usec) {
         if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
                 m = timeout_usec;
 
-        p[0].fd = rtnl->fd;
-        p[0].events = e;
+        struct pollfd p = {
+                .fd = rtnl->fd,
+                .events = e,
+        };
 
-        r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
+        r = ppoll(&p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
         if (r < 0)
                 return -errno;
+        if (r == 0)
+                return 0;
 
-        return r > 0 ? 1 : 0;
+        if (p.revents & POLLNVAL)
+                return -EBADF;
+
+        return 1;
 }
 
 int sd_netlink_wait(sd_netlink *nl, uint64_t timeout_usec) {
index 5f780e0be956e8ec7a7f2d70d0350b5081175a05..bf23021b53016d65df1aa265cd26c2d09e597f98 100644 (file)
@@ -216,8 +216,11 @@ static int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_
                                         continue;
 
                                 return -errno;
-                        } else if (r == 0)
+                        }
+                        if (r == 0)
                                 return -EAGAIN;
+                        if (pfd.revents & POLLNVAL)
+                                return -EBADF;
 
                         /* receive next message */
                         break;
index 4c5781a11ad5830ac4c81760ce5225e0bc777b47..3d0b9391069507049c9fcec873a5a19eafaf2e92 100644 (file)
@@ -305,6 +305,12 @@ int ask_password_plymouth(
                         goto finish;
                 }
 
+                if (pollfd[POLL_SOCKET].revents & POLLNVAL ||
+                    (notify >= 0 && pollfd[POLL_INOTIFY].revents & POLLNVAL)) {
+                        r = -EBADF;
+                        goto finish;
+                }
+
                 if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
                         (void) flush_fd(notify);
 
@@ -541,6 +547,12 @@ int ask_password_tty(
                         goto finish;
                 }
 
+                if ((pollfd[POLL_TTY].revents & POLLNVAL) ||
+                    (notify >= 0 && (pollfd[POLL_INOTIFY].revents & POLLNVAL))) {
+                        r = -EBADF;
+                        goto finish;
+                }
+
                 if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyname) {
                         (void) flush_fd(notify);
 
@@ -888,6 +900,13 @@ int ask_password_agent(
                         goto finish;
                 }
 
+                if (pollfd[FD_SOCKET].revents & POLLNVAL ||
+                    pollfd[FD_SIGNAL].revents & POLLNVAL ||
+                    (notify >= 0 && pollfd[FD_INOTIFY].revents & POLLNVAL)) {
+                        r = -EBADF;
+                        goto finish;
+                }
+
                 if (pollfd[FD_SIGNAL].revents & POLLIN) {
                         r = -EINTR;
                         goto finish;
index bb5869dad405166f0adc5af8f7069d0a69e8b024..80b597b5cadda9b94bea9daa463d7d04244d25ca 100644 (file)
@@ -218,10 +218,14 @@ static bool barrier_read(Barrier *b, int64_t comp) {
                 uint64_t buf;
                 int r;
 
-                r = poll(pfd, 2, -1);
-                if (r < 0 && IN_SET(errno, EAGAIN, EINTR))
-                        continue;
-                else if (r < 0)
+                r = poll(pfd, ELEMENTSOF(pfd), -1);
+                if (r < 0) {
+                        if (IN_SET(errno, EAGAIN, EINTR))
+                                continue;
+                        goto error;
+                }
+                if (pfd[0].revents & POLLNVAL ||
+                    pfd[1].revents & POLLNVAL)
                         goto error;
 
                 if (pfd[1].revents) {
index fa4f32f3538b29c40a16254fbf6310519fb2e7ae..7d0d90247cc9c0eb0fbe04715fa15010d5af2ee6 100644 (file)
@@ -334,9 +334,10 @@ static int write_to_terminal(const char *tty, const char *message) {
                 k = poll(&pollfd, 1, (end - t) / USEC_PER_MSEC);
                 if (k < 0)
                         return -errno;
-
                 if (k == 0)
                         return -ETIME;
+                if (pollfd.revents & POLLNVAL)
+                        return -EBADF;
 
                 n = write(fd, p, left);
                 if (n < 0) {
index ac111555e9ad829553a28afc2e6953b3dee8ffca..c0b5874225400bb22432d38b6eef8bf680e43159 100644 (file)
@@ -1048,10 +1048,14 @@ int varlink_wait(Varlink *v, usec_t timeout) {
                   NULL);
         if (r < 0)
                 return -errno;
+        if (r == 0)
+                return 0;
 
-        handle_revents(v, pfd.revents);
+        if (pfd.revents & POLLNVAL)
+                return -EBADF;
 
-        return r > 0 ? 1 : 0;
+        handle_revents(v, pfd.revents);
+        return 1;
 }
 
 int varlink_get_fd(Varlink *v) {
@@ -1139,9 +1143,14 @@ int varlink_flush(Varlink *v) {
                         .events = POLLOUT,
                 };
 
-                if (poll(&pfd, 1, -1) < 0)
+                r = poll(&pfd, 1, -1);
+                if (r < 0)
                         return -errno;
 
+                assert(r > 0);
+                if (pfd.revents & POLLNVAL)
+                        return -EBADF;
+
                 handle_revents(v, pfd.revents);
         }
 
index fbfddc0262fc161938a4868341ac3d6da4629d1f..4f9c23099a98dfdc5337fdde34e1bf9d1cfa1a34 100644 (file)
@@ -271,6 +271,9 @@ static int execute_s2h(const SleepConfig *sleep_config) {
 
         tfd = safe_close(tfd);
 
+        if (FLAGS_SET(fds.revents, POLLNVAL))
+                return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Invalid timer fd to sleep on?");
+
         if (!FLAGS_SET(fds.revents, POLLIN)) /* We woke up before the alarm time, we are done. */
                 return 0;
 
index 52b9ce455557db838daa17cff58afe980694c410..ca145aebf932d2ad0ef8a37266dd8f7bec3c3ef2 100644 (file)
@@ -238,17 +238,19 @@ static int run(int argc, char *argv[]) {
                         ts = timespec_store(&_ts, t);
                 }
 
-                {
-                        struct pollfd p[3] = {
-                                {.fd = fd,            .events = events_a           },
-                                {.fd = STDIN_FILENO,  .events = events_b & POLLIN  },
-                                {.fd = STDOUT_FILENO, .events = events_b & POLLOUT },
-                        };
-
-                        r = ppoll(p, ELEMENTSOF(p), ts, NULL);
-                }
+                struct pollfd p[3] = {
+                        { .fd = fd,            .events = events_a           },
+                        { .fd = STDIN_FILENO,  .events = events_b & POLLIN  },
+                        { .fd = STDOUT_FILENO, .events = events_b & POLLOUT },
+                };
+
+                r = ppoll(p, ELEMENTSOF(p), ts, NULL);
                 if (r < 0)
                         return log_error_errno(errno, "ppoll() failed: %m");
+                if (p[0].revents & POLLNVAL ||
+                    p[1].revents & POLLNVAL ||
+                    p[2].revents & POLLNVAL)
+                        return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Invalid file descriptor to poll on?");
         }
 
         return 0;
index eb8471911130cb55e962d26505643feca5945d3c..4371da4785018969eb03b21d1c6f0e7f5c66457d 100644 (file)
@@ -395,6 +395,10 @@ static int process_and_watch_password_files(bool watch) {
                         return -errno;
                 }
 
+                if (pollfd[FD_SIGNAL].revents & POLLNVAL ||
+                    pollfd[FD_INOTIFY].revents & POLLNVAL)
+                        return -EBADF;
+
                 if (pollfd[FD_INOTIFY].revents != 0)
                         (void) flush_fd(notify);
 
index 7d7044eac3c019dc5cb58394782321d560ab3d79..1fa267c831cb92ab728fcaec9a186a6d6624444d 100644 (file)
@@ -202,7 +202,12 @@ int settle_main(int argc, char *argv[], void *userdata) {
                         return -ETIMEDOUT;
 
                 /* wake up when queue becomes empty */
-                if (poll(&pfd, 1, MSEC_PER_SEC) > 0 && pfd.revents & POLLIN) {
+                r = poll(&pfd, 1, MSEC_PER_SEC);
+                if (r < 0)
+                        return -errno;
+                if (pfd.revents & POLLNVAL)
+                        return -EBADF;
+                if (r > 0 && pfd.revents & POLLIN) {
                         r = udev_queue_flush(queue);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to flush queue: %m");
index ac04af0ca8d216e674cfaf437ccc8bed81cd42ff..4a8c98384d4d9aed2f47725547f5996a3c94b700 100644 (file)
@@ -757,6 +757,8 @@ static int run(int argc, char *argv[]) {
 
                         if (poll(&pfd, 1, 0) < 0)
                                 return log_error_errno(errno, "Failed to test for POLLIN on listening socket: %m");
+                        if (FLAGS_SET(pfd.revents, POLLNVAL))
+                                return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Listening socket dead?");
 
                         if (FLAGS_SET(pfd.revents, POLLIN)) {
                                 pid_t parent;