]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
seccomp: send process memory fd 2972/head
authorChristian Brauner <christian.brauner@ubuntu.com>
Thu, 2 May 2019 15:06:00 +0000 (17:06 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Thu, 2 May 2019 15:06:00 +0000 (17:06 +0200)
There's an inherent race when reading a process's memory. The easiest way is to
have liblxc get an fd and check that the race was one, send it to the caller
(They are free to ignore it if they don't use recvmsg()).

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/af_unix.c
src/lxc/af_unix.h
src/lxc/seccomp.c

index 7f0711ed224d990033ec50531917bb55f7a937f1..9e2f8587c8364b86558ef1fbe919f352f2130f1e 100644 (file)
@@ -199,6 +199,12 @@ again:
        return ret;
 }
 
+int lxc_unix_send_fds(int fd, int *sendfds, int num_sendfds, void *data,
+                     size_t size)
+{
+       return lxc_abstract_unix_send_fds(fd, sendfds, num_sendfds, data, size);
+}
+
 int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds,
                               void *data, size_t size)
 {
index 3ae5954983d811ec28aea5ef019a2c5dcfebcbd9..8a068d920fdd1a83ebb19dea5a2996fe44c3eb8f 100644 (file)
@@ -35,6 +35,8 @@ extern void lxc_abstract_unix_close(int fd);
 extern int lxc_abstract_unix_connect(const char *path);
 extern int lxc_abstract_unix_send_fds(int fd, int *sendfds, int num_sendfds,
                                      void *data, size_t size);
+extern int lxc_unix_send_fds(int fd, int *sendfds, int num_sendfds, void *data,
+                            size_t size);
 extern int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds,
                                      void *data, size_t size);
 extern int lxc_abstract_unix_send_credential(int fd, void *data, size_t size);
index f326c8d307ffa80dab190c824b2d03b4764b6140..bfbc19ac53c043bf03e3203b9eac6b10d6b7ecec 100644 (file)
@@ -1335,8 +1335,10 @@ int seccomp_notify_handler(int fd, uint32_t events, void *data,
 {
 
 #if HAVE_DECL_SECCOMP_NOTIF_GET_FD
+       __do_close_prot_errno int fd_mem = -EBADF;
        int reconnect_count, ret;
        ssize_t bytes;
+       char mem_path[6 + 21 + 5];
        struct lxc_handler *hdlr = data;
        struct lxc_conf *conf = hdlr->conf;
        struct seccomp_notif *req = conf->seccomp.notifier.req_buf;
@@ -1355,14 +1357,33 @@ int seccomp_notify_handler(int fd, uint32_t events, void *data,
                goto out;
        }
 
+       snprintf(mem_path, sizeof(mem_path), "/proc/%d/mem", req->pid);
+       fd_mem = open(mem_path, O_RDONLY | O_CLOEXEC);
+       if (fd_mem < 0) {
+               (void)seccomp_notify_default_answer(fd, req, resp, hdlr);
+               SYSERROR("Failed to open process memory for seccomp notify request");
+               goto out;
+       }
+
+       /*
+        * Make sure that the fd for /proc/<pid>/mem we just opened still
+        * refers to the correct process's memory.
+        */
+       ret = seccomp_notif_id_valid(fd, req->id);
+       if (ret < 0) {
+               (void)seccomp_notify_default_answer(fd, req, resp, hdlr);
+               SYSERROR("Invalid seccomp notify request id");
+               goto out;
+       }
+
        memcpy(&msg.req, req, sizeof(msg.req));
        msg.monitor_pid = hdlr->monitor_pid;
        msg.init_pid = hdlr->pid;
 
        reconnect_count = 0;
        do {
-               bytes = lxc_send_nointr(listener_proxy_fd, &msg, sizeof(msg),
-                                       MSG_NOSIGNAL);
+               bytes = lxc_unix_send_fds(listener_proxy_fd, &fd_mem, 1, &msg,
+                                         sizeof(msg));
                if (bytes != (ssize_t)sizeof(msg)) {
                        SYSERROR("Failed to forward message to seccomp proxy");
                        if (seccomp_notify_default_answer(fd, req, resp, hdlr))
@@ -1370,6 +1391,8 @@ int seccomp_notify_handler(int fd, uint32_t events, void *data,
                }
        } while (reconnect_count++);
 
+       close_prot_errno_disarm(fd_mem);
+
        reconnect_count = 0;
        do {
                bytes = lxc_recv_nointr(listener_proxy_fd, &msg, sizeof(msg), 0);