This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: os.closerange() can be no-op in a seccomp sandbox
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.11, Python 3.10
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: izbyshev Nosy List: gregory.p.smith, izbyshev, kevans, kevans91, miss-islington
Priority: normal Keywords: 3.10regression, patch

Created on 2022-04-08 14:29 by izbyshev, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 32418 merged izbyshev, 2022-04-08 15:05
PR 32420 merged miss-islington, 2022-04-08 17:40
Messages (6)
msg416986 - (view) Author: Alexey Izbyshev (izbyshev) * (Python triager) Date: 2022-04-08 14:29
After #40422 _Py_closerange() assumes that close_range() closes all file descriptors even if it returns an error (other than ENOSYS):

    if (close_range(first, last, 0) == 0 || errno != ENOSYS) {
        /* Any errors encountered while closing file descriptors are ignored;
         * ENOSYS means no kernel support, though,
         * so we'll fallback to the other methods. */
    }
    else
    /* fallbacks */


This assumption can be wrong on Linux if a seccomp sandbox denies the underlying syscall, pretending that it returns EPERM or EACCES. In this case _Py_closerange() won't close any descriptors at all, which in the worst case can be a security issue.

I propose to fix this by falling back to other methods in case of *any* close_range() error. Note that fallbacks will not be triggered on any problems with closing individual file descriptors because close_range() is documented to ignore such errors on both Linux[1] and FreeBSD[2].

[1] https://man7.org/linux/man-pages/man2/close_range.2.html
[2] https://www.freebsd.org/cgi/man.cgi?query=close_range&sektion=2
msg416988 - (view) Author: Kyle Evans (kevans) Date: 2022-04-08 14:49
Sure, sounds good to me. The original theory (IIRC, I've slept many times since then :-)) was that we already know first/last are valid and there are no other defined errors, so 'other errors' must be because close_range has started percolating up something from closing individual files.

It's been years now and that hasn't happened, even with more recent flag additions. I think it's safe to say it won't, and such a fallback upon error won't put us back into a bogus pre-close_range situation where we're needlessly close()ing a bunch of closed fds.
msg416991 - (view) Author: Alexey Izbyshev (izbyshev) * (Python triager) Date: 2022-04-08 15:25
> It's been years now and that hasn't happened, even with more recent flag additions. I think it's safe to say it won't, and such a fallback upon error won't put us back into a bogus pre-close_range situation where we're needlessly close()ing a bunch of closed fds.

Yes, I also find it unlikely that close_range() will start reporting an error if it fails to close some fd, especially if not given some new flag. Such error reporting doesn't seem very useful to userspace because there is no way to associate the error with the fd.

But even if such change happens, it will be just a performance regression, not a potential correctness/security issue.
msg416995 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2022-04-08 17:40
New changeset 1c8b3b5d66a629258f1db16939b996264a8b9c37 by Alexey Izbyshev in branch 'main':
bpo-47260: Fix os.closerange() potentially being a no-op in a seccomp sandbox (GH-32418)
https://github.com/python/cpython/commit/1c8b3b5d66a629258f1db16939b996264a8b9c37
msg416996 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2022-04-08 17:43
Good catch.
msg416998 - (view) Author: miss-islington (miss-islington) Date: 2022-04-08 18:10
New changeset 89697f7374ea947ebe8e36131e2d3e21fff6fa1d by Miss Islington (bot) in branch '3.10':
bpo-47260: Fix os.closerange() potentially being a no-op in a seccomp sandbox (GH-32418)
https://github.com/python/cpython/commit/89697f7374ea947ebe8e36131e2d3e21fff6fa1d
History
Date User Action Args
2022-04-11 14:59:58adminsetgithub: 91416
2022-04-08 18:10:43miss-islingtonsetmessages: + msg416998
2022-04-08 17:43:44gregory.p.smithsetstatus: open -> closed
resolution: fixed
messages: + msg416996

stage: patch review -> resolved
2022-04-08 17:40:56gregory.p.smithsetmessages: + msg416995
2022-04-08 17:40:53miss-islingtonsetnosy: + miss-islington
pull_requests: + pull_request30445
2022-04-08 15:26:27izbyshevsetkeywords: + patch
stage: patch review
2022-04-08 15:25:58izbyshevsetkeywords: - patch

messages: + msg416991
stage: patch review -> (no value)
2022-04-08 15:05:20izbyshevsetkeywords: + patch
stage: patch review
pull_requests: + pull_request30443
2022-04-08 14:49:16kevanssetmessages: + msg416988
2022-04-08 14:29:30izbyshevcreate