chiark / gitweb /
selinux: fix potential double free crash in child process
[elogind.git] / src / journal-remote / journal-remote.c
index ad87783510cff94a02d8f5c42ba5c005322c5c3f..eb092ce02045439ac267e2227fbfea2dfdd15e76 100644 (file)
@@ -295,6 +295,8 @@ static int dispatch_raw_source_event(sd_event_source *event,
                                      int fd,
                                      uint32_t revents,
                                      void *userdata);
+static int dispatch_blocking_source_event(sd_event_source *event,
+                                          void *userdata);
 static int dispatch_raw_connection_event(sd_event_source *event,
                                          int fd,
                                          uint32_t revents,
@@ -309,6 +311,8 @@ static int get_source_for_fd(RemoteServer *s,
         Writer *writer;
         int r;
 
+        /* This takes ownership of name, but only on success. */
+
         assert(fd >= 0);
         assert(source);
 
@@ -358,6 +362,8 @@ static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
         RemoteSource *source;
         int r;
 
+        /* This takes ownership of name, even on failure, if own_name is true. */
+
         assert(s);
         assert(fd >= 0);
         assert(name);
@@ -372,12 +378,20 @@ static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
         if (r < 0) {
                 log_error("Failed to create source for fd:%d (%s): %s",
                           fd, name, strerror(-r));
+                free(name);
                 return r;
         }
 
         r = sd_event_add_io(s->events, &source->event,
                             fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
                             dispatch_raw_source_event, s);
+        if (r == -EPERM) {
+                log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
+                r = sd_event_add_defer(s->events, &source->event,
+                                       dispatch_blocking_source_event, source);
+                if (r == 0)
+                        sd_event_source_set_enabled(source->event, SD_EVENT_ON);
+        }
         if (r < 0) {
                 log_error("Failed to register event source for fd:%d: %s",
                           fd, strerror(-r));
@@ -858,8 +872,6 @@ static int remoteserver_init(RemoteServer *s,
                         log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
 
                         r = add_source(s, fd, hostname, true);
-                        if (r < 0)
-                                free(hostname);
                 } else {
                         log_error("Unknown socket passed on fd:%d", fd);
 
@@ -1029,6 +1041,13 @@ static int dispatch_raw_source_event(sd_event_source *event,
                 return 1;
 }
 
+static int dispatch_blocking_source_event(sd_event_source *event,
+                                          void *userdata) {
+        RemoteSource *source = userdata;
+
+        return dispatch_raw_source_event(event, source->fd, EPOLLIN, server);
+}
+
 static int accept_connection(const char* type, int fd,
                              SocketAddress *addr, char **hostname) {
         int fd2, r;
@@ -1082,7 +1101,7 @@ static int dispatch_raw_connection_event(sd_event_source *event,
                                          uint32_t revents,
                                          void *userdata) {
         RemoteServer *s = userdata;
-        int fd2, r;
+        int fd2;
         SocketAddress addr = {
                 .size = sizeof(union sockaddr_union),
                 .type = SOCK_STREAM,
@@ -1093,10 +1112,7 @@ static int dispatch_raw_connection_event(sd_event_source *event,
         if (fd2 < 0)
                 return fd2;
 
-        r = add_source(s, fd2, hostname, true);
-        if (r < 0)
-                free(hostname);
-        return r;
+        return add_source(s, fd2, hostname, true);
 }
 
 /**********************************************************************