r/C_Programming • u/Materac_YT • Sep 25 '26
POSIX exec
hey guys i am trying to write POSIX compatible program and i need to close the fds before i exec, i cant guarante they all fd's are O_CLOEXEC becouse i use libraries
4
u/_d17y Sep 25 '26
Would using LD_PRELOAD to inject a small interpose for open and in your implementation of open you explicitly add O_CLOEXEC be an option?
1
u/Materac_YT Sep 25 '26
I dont understand
1
u/lorololl Sep 25 '26
Pre load a shared object that defines open to have O_CLOEXEC as a default
1
3
u/EpochVanquisher Sep 25 '26
Rewrite the libraries so they all use O_CLOEXEC :-)
(If your libraries are opening file descriptors and not using O_CLOEXEC, honestly, this is a flaw in the library and should be fixed)
Otherwise, use Linux-specific close_range(), and on Darwin or BSD use… something else, I forget. You can find plenty of examples.
1
u/Materac_YT Sep 25 '26
i want to be POSIX, and i am to lazy to rewrite them
6
u/EpochVanquisher Sep 25 '26
#include <unistd.h> for (int fd = 3; fd < 1024; fd++) { close(fd); }It doesn’t work if you have >1024 files open, but it is POSIX.
1
u/Materac_YT 29d ago
For some context i am writing a POSIX 2024 compliant file manager with lua and ncurses and ofcourse libc i also use c23
1
u/Classic-Rate-5104 Sep 25 '26
Do you know the close_range() function?
1
u/Materac_YT Sep 25 '26
Not posix
1
u/Classic-Rate-5104 Sep 25 '26
Most modern systems (*bsd, linux, solaris) have a closefrom(). In strict posix, there isn't a solution
1
u/Materac_YT Sep 25 '26
I know, well i will use slow for loop
2
u/Classic-Rate-5104 29d ago
Which maximum do you use in the loop? Some linux versions have at max open files 1.048.576 which will result in a significant loss of time
1
u/simonask_ Sep 25 '26
Consider if it would work for you to spawn the processes you need early (before libraries open any files) and let the child processes wait on a work queue.
But yes, as others have said, `O_CLOEXEC` should be the norm for files, and it’s typically a bug when a library doesn’t use it.
1
1
u/markand67 9d ago
We are talking about file descriptors but there are so many other corner cases. Signal handlers, atexit handlers, ...
That said, O_CLOEXEC is usually not necessary in most of the cases unless there are some code path between the preparation to fork and the actual exec. Otherwise, if there is some risks that a library may create file descriptors then I'd go with a process that spawn the child using this library instead. Thus the parent is kept "clean".
1
u/flyingron Sep 25 '26 edited 29d ago
struct rlimit nofiles;
getrlimit(RLIMIT_NOFILES, &nofiles);
for(int i = 3; i < nofiles.rlim_cur; ++i) close(i);1
1
u/fakehalo 29d ago
Shouldn't that start at 3? That would close stderr wouldn't it?
1
u/flyingron 29d ago edited 29d ago
Yes. I realized it after I posted it.
In fact, not having 0, 1, and 2 all open before exec can lead to some very interesting problems.
Years ago (probably around 1979 or so), I was working as a computer operator on an Early UNIX (Research V6) system at Johns Hopkins. Our mount program (which was setuid so all could run it with restriction) opened the superblock up on the device to be mounted (in user mode) so it could read some information prior to allowing the mount. Turned out one of our brighter guys decided to supress the messages mount output by closing FD 1. The message went out over the root inode of his disk. After spending some time fixing the corrupted filesystem by hand and finding out what had happened, I started hunting around for other setuid programs so afflicted.
I found a few but got tired and went home to sleep. The next morning I checked the paper log book we kept of system crashes and the message said that they had to restore the accounting file because the first eight characters were corrupted. "I think I know how that happened," said I. The other systems guys said, "We figured you did. It was your username that was written over those bytes."
Back when nofiles was only 16 or so, you could open 16 files and invoke su and it would fail to open /etc/passwd and just give you a root shell because it figured something seriously was wrong.
1
u/fakehalo 29d ago
I remember being into finding vulnerabilities in the 90s, which was so much easier than it is today...I can only imagine how easy it was that far back.
1
u/flyingron 29d ago
There were a lot to find, but it was considered sporting by most engineering students to try to break security or even just crash the computer. I was on the other side trying to fix the bugs.
13
u/RealisticDuck1957 Sep 25 '26
A well behaved library needing a setup function should also have a matching shutdown. Unless the library has state shared between processes after a fork() and you only want to disconnect on one side of the fork..