Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <0fcddca6-2081-4dbf-8f7a-de149b51d6d8@gmail.com>
Date: Sat, 13 Sep 2025 17:23:44 -0400
From: Demi Marie Obenour <demiobenour@...il.com>
To: Rich Felker <dalias@...c.org>
Cc: musl@...ts.openwall.com
Subject: Re: closefrom and close_range wrappers

On 9/13/25 08:48, Rich Felker wrote:
> On Fri, Sep 12, 2025 at 09:40:22PM -0400, Demi Marie Obenour wrote:
>> Would it make sense for musl to provide close_range and
>> closefrom?  The main uses of them are to close unwanted
>> FDs after a fork and before exec.  close_range() can also
>> be used to mark them close-on-exec instead.
>>
>> The main advantage of closefrom() is that it is portable
>> to more systems.  Closing file descriptors one doesn't own
>> is not an issue because the code that does own these FDs
>> will never get a chance to run.  In particular, calling any
>> stdio functions that use anything but stdin, stdout, and
>> stderr would be UB.  stdin, stdout, and stderr use FD 0, 1,
>> and 2, respectively, and those are almost always left open.
>>
>> Yes, this is all a consequence of fork()/exec() being an
>> extremely poor API, but I don't know of a better solution.
>> There are third-party libraries (including glib and wlroots)
>> that expect one to either use an API like this or emulate it
>> by scanning /proc/self/fd (yuck).  Yes, these libraries should
>> be atomically setting O_CLOEXEC, but their authors disagree
>> and maintaining downstream forks is not practical.
> 
> I need to look back at where we left this last time it was discussed.
> 
> As Laurent replied, per the standard (POSIX) these operations are
> fundamentally programming errors. Closing a fd that "doesn't belong to
> you" (that may be some implementation detail of the POSIX
> implementation or some part of the execution environment hosting your
> application) produces undefined behavior. Nonetheless, people do want
> to do it for various reasons and the existing ways of doing it without
> the syscall are "worse".

I think this is a case where practical realities should override
purity.  There is too many code that will fall back to iterating
over /proc/self/fd if closefrom() or close_range() isn't available.
Closing an FD that happens to be a libc implementation detail is
only possible if such an FD exists, which (to the best of my
knowledge) is not the case.

> One question that naturally arises whenever adding an interface like
> this is what we do on kernel versions that lack it. Do we fail it and
> leave the application to figure out what to do when it fails, or
> emulate it? If taking the failing option, there's not a whole lot of
> value over the caller just using syscall() directly, but maybe it
> makes sense. I think there are some macro constants needed to use
> the syscall that potentially make it difficult to do without libc
> exposing anything (possible conflicts pulling in kernel headers).
> 
> I'll try to find past discussion of this. If anyone else has it handy
> to cite, go ahead.
One advantage is that syscall() is much more error-prone and annoying
to use.
-- 
Sincerely,
Demi Marie Obenour (she/her/hers)
Download attachment "OpenPGP_0xB288B55FFF9C22C1.asc" of type "application/pgp-keys" (7141 bytes)

Download attachment "OpenPGP_signature.asc" of type "application/pgp-signature" (834 bytes)

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.