]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
utils: fix lxc_p{close,open}()
authorChristian Brauner <christian.brauner@ubuntu.com>
Fri, 16 Feb 2018 19:02:44 +0000 (20:02 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Sat, 17 Feb 2018 12:49:33 +0000 (13:49 +0100)
If a file descriptor fd is opened by fdopen() and associated with a stream f
will **not** have been dup()ed. This means that fclose(f) will also close the
fd. So never call close(fd) after fdopen(fd) succeeded.
This fixes a double close() Stéphane and I observed when debugging on aarch64
and armf.

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

index a9c73f24ed4de558686243bb0a73a9877ab00c0c..10e14b7f3548df259ce5f620a48647dbc784395c 100644 (file)
@@ -509,10 +509,14 @@ struct lxc_popen_FILE *lxc_popen(const char *command)
        fp = malloc(sizeof(*fp));
        if (!fp)
                goto on_error;
+       memset(fp, 0, sizeof(*fp));
 
        fp->child_pid = child_pid;
        fp->pipe = pipe_fds[0];
 
+       /* From now on, closing fp->f will also close fp->pipe. So only ever
+        * call fclose(fp->f).
+        */
        fp->f = fdopen(pipe_fds[0], "r");
        if (!fp->f)
                goto on_error;
@@ -520,15 +524,22 @@ struct lxc_popen_FILE *lxc_popen(const char *command)
        return fp;
 
 on_error:
-       if (fp)
-               free(fp);
-
-       if (pipe_fds[0] >= 0)
+       /* We can only close pipe_fds[0] if fdopen() didn't succeed or wasn't
+        * called yet. Otherwise the fd belongs to the file opened by fdopen()
+        * since it isn't dup()ed.
+        */
+       if (fp && !fp->f && pipe_fds[0] >= 0)
                close(pipe_fds[0]);
 
        if (pipe_fds[1] >= 0)
                close(pipe_fds[1]);
 
+       if (fp && fp->f)
+               fclose(fp->f);
+
+       if (fp)
+               free(fp);
+
        return NULL;
 }
 
@@ -544,7 +555,6 @@ int lxc_pclose(struct lxc_popen_FILE *fp)
                wait_pid = waitpid(fp->child_pid, &wstatus, 0);
        } while (wait_pid < 0 && errno == EINTR);
 
-       close(fp->pipe);
        fclose(fp->f);
        free(fp);