Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

load_file_data: do not close fd on error to avoid double-close #558

Merged
merged 1 commit into from
Mar 2, 2023
Merged

load_file_data: do not close fd on error to avoid double-close #558

merged 1 commit into from
Mar 2, 2023

Conversation

cgzones
Copy link
Contributor

@cgzones cgzones commented Feb 28, 2023

load_file_at() is affected in the error case, since all other current callers call die_with_error() before closing the passed file descriptor.

Found by GCC analyzer:

./utils.c: In function ‘load_file_at’:
./utils.c:630:3: warning: double ‘close’ of file descriptor ‘fd’ [CWE-1341] [-Wanalyzer-fd-double-close]
630 |   close (fd);
    |   ^~~~~~~~~~
‘load_file_at’: events 1-4
    |
    |  616 | load_file_at (int         dirfd,
    |      | ^~~~~~~~~~~~
    |      | |
    |      | (1) entry to ‘load_file_at’
    |......
    |  624 |   if (fd == -1)
    |      |      ~
    |      |      |
    |      |      (2) following ‘false’ branch (when ‘fd != -1’)...
    |......
    |  627 |   data = load_file_data (fd, NULL);
    |      |   ~~~~   ~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |   |      |
    |      |   |      (4) calling ‘load_file_data’ from ‘load_file_at’
    |      |   (3) ...to here
    |
    +--> ‘load_file_data’: events 5-6
        |
        |  568 | load_file_data (int     fd,
        |      | ^~~~~~~~~~~~~~
        |      | |
        |      | (5) entry to ‘load_file_data’
        |......
        |  579 |   data = xmalloc (data_len);
        |      |          ~~~~~~~~~~~~~~~~~~
        |      |          |
        |      |          (6) calling ‘xmalloc’ from ‘load_file_data’
        |
        +--> ‘xmalloc’: events 7-9
                |
                |  119 | xmalloc (size_t size)
                |      | ^~~~~~~
                |      | |
                |      | (7) entry to ‘xmalloc’
                |......
                |  123 |   if (res == NULL)
                |      |      ~
                |      |      |
                |      |      (8) following ‘false’ branch (when ‘res’ is non-NULL)...
                |  124 |     die_oom ();
                |  125 |   return res;
                |      |   ~~~~~~
                |      |   |
                |      |   (9) ...to here
                |
        <------+
        |
        ‘load_file_data’: events 10-11
        |
        |  579 |   data = xmalloc (data_len);
        |      |          ^~~~~~~~~~~~~~~~~~
        |      |          |
        |      |          (10) returning to ‘load_file_data’ from ‘xmalloc’
        |......
        |  583 |       if (data_len == data_read + 1)
        |      |          ~
        |      |          |
        |      |          (11) following ‘false’ branch...
        |
        ‘load_file_data’: event 12
        |
        |cc1:
        | (12): ...to here
        |
        ‘load_file_data’: events 13-16
        |
        |  571 |   cleanup_free char *data = NULL;
        |      |                      ~
        |      |                      |
        |      |                      (16) inlined call to ‘cleanup_freep’ from ‘load_file_data’
        |......
        |  591 |       while (res < 0 && errno == EINTR);
        |      |                      ^
        |      |                      |
        |      |                      (13) following ‘false’ branch...
        |  592 |
        |  593 |       if (res < 0)
        |      |       ~~
        |      |       |
        |      |       (14) ...to here
        |......
        |  596 |           close (fd);
        |      |           ~~~~~~~~~~
        |      |           |
        |      |           (15) first ‘close’ here
        |
        +--> ‘cleanup_freep’: events 17-18
                |
                |./utils.h:141:6:
                |  141 |   if (*pp)
                |      |      ^
                |      |      |
                |      |      (17) following ‘true’ branch (when ‘data’ is non-NULL)...
                |  142 |     free (*pp);
                |      |     ~~~~
                |      |     |
                |      |     (18) ...to here
                |
    <-------------+
    |
‘load_file_at’: events 19-20
    |
    |./utils.c:627:10:
    |  627 |   data = load_file_data (fd, NULL);
    |      |          ^~~~~~~~~~~~~~~~~~~~~~~~~
    |      |          |
    |      |          (19) returning to ‘load_file_at’ from ‘load_file_data’
    |......
    |  630 |   close (fd);
    |      |   ~~~~~~~~~~
    |      |   |
    |      |   (20) second ‘close’ here; first ‘close’ was at (15)

@smcv
Copy link
Collaborator

smcv commented Feb 28, 2023

This doesn't seem like a practical problem: we don't open any other fds between the first close() and the second, and bubblewrap is single-threaded (so there is no other thread opening fds), so the second close() will deterministically fail with EBADF rather than closing an unintended fd.

@smcv
Copy link
Collaborator

smcv commented Feb 28, 2023

Please could you update the commit message to mention that this isn't a practical problem, and not include several pages of gcc output?

utils.c Outdated Show resolved Hide resolved
load_file_data() closes the passed file descriptor in case of an read(2)
failure.  The file descriptor is however owned by the caller and should
not be closed to avoid a double-close.
Since in this error branch NULL is always returned the only affected
caller is load_file_data(), as all other callers immediately abort via
die_with_error().  As bubblewrap is single-threaded the second close(2)
in load_file_data() will be well-defined and fail with EBADF, leading to
no unrelated file descriptor to be closed

Found by GCC analyzer:

    ./utils.c: In function ‘load_file_at’:
    ./utils.c:630:3: warning: double ‘close’ of file descriptor ‘fd’ [CWE-1341] [-Wanalyzer-fd-double-close]
    630 |   close (fd);
        |   ^~~~~~~~~~
    ...
            |  596 |           close (fd);
            |      |           ~~~~~~~~~~
            |      |           |
            |      |           (15) first ‘close’ here
    ...
        |  630 |   close (fd);
        |      |   ~~~~~~~~~~
        |      |   |
        |      |   (20) second ‘close’ here; first ‘close’ was at (15)

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
@smcv smcv merged commit da63f2b into containers:main Mar 2, 2023
@cgzones cgzones deleted the close branch March 6, 2023 15:34
smcv added a commit to smcv/flatpak that referenced this pull request Mar 27, 2024
* `--symlink` is now idempotent, meaning it succeeds if the
  symlink already exists and already has the desired target
  (containers/bubblewrap#549, flatpak#2387,
  flatpak#3477, flatpak#5255)
* Report a better error message if `mount(2)` fails with `ENOSPC`
  (containers/bubblewrap#615, ValveSoftware/steam-runtime#637)
* Fix a double-close on error reading from `--args`, `--seccomp` or
  `--add-seccomp-fd` argument (containers/bubblewrap#558)
* Improve memory allocation behaviour
  (containers/bubblewrap#556, containers/bubblewrap#624)
* Silence various compiler warnings (containers/bubblewrap#559)

Resolves: flatpak#2387
Resolves: flatpak#3477
Resolves: flatpak#5255
Signed-off-by: Simon McVittie <smcv@collabora.com>
smcv added a commit to flatpak/flatpak that referenced this pull request Mar 27, 2024
* `--symlink` is now idempotent, meaning it succeeds if the
  symlink already exists and already has the desired target
  (containers/bubblewrap#549, #2387,
  #3477, #5255)
* Report a better error message if `mount(2)` fails with `ENOSPC`
  (containers/bubblewrap#615, ValveSoftware/steam-runtime#637)
* Fix a double-close on error reading from `--args`, `--seccomp` or
  `--add-seccomp-fd` argument (containers/bubblewrap#558)
* Improve memory allocation behaviour
  (containers/bubblewrap#556, containers/bubblewrap#624)
* Silence various compiler warnings (containers/bubblewrap#559)

Resolves: #2387
Resolves: #3477
Resolves: #5255
Signed-off-by: Simon McVittie <smcv@collabora.com>
GeorgesStavracas pushed a commit to GeorgesStavracas/flatpak that referenced this pull request Apr 26, 2024
* `--symlink` is now idempotent, meaning it succeeds if the
  symlink already exists and already has the desired target
  (containers/bubblewrap#549, flatpak#2387,
  flatpak#3477, flatpak#5255)
* Report a better error message if `mount(2)` fails with `ENOSPC`
  (containers/bubblewrap#615, ValveSoftware/steam-runtime#637)
* Fix a double-close on error reading from `--args`, `--seccomp` or
  `--add-seccomp-fd` argument (containers/bubblewrap#558)
* Improve memory allocation behaviour
  (containers/bubblewrap#556, containers/bubblewrap#624)
* Silence various compiler warnings (containers/bubblewrap#559)

Resolves: flatpak#2387
Resolves: flatpak#3477
Resolves: flatpak#5255
Signed-off-by: Simon McVittie <smcv@collabora.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants