Discussion:
Prevent file descriptor inheritance
(too old to reply)
R. Diez
2018-08-08 06:40:19 UTC
Permalink
Hi all:

Is there any way to prevent file descriptor inheritance? I mean the
"close on exec" flag O_CLOEXEC or FD_CLOEXEC.

I wonder about the security implications. If a shell script opens a
"secret" file, and runs an external command, that command will have
direct access to the file.

Thanks in advance,
rdiez
Eric Blake
2018-08-08 12:39:58 UTC
Permalink
Post by R. Diez
Is there any way to prevent file descriptor inheritance? I mean the
"close on exec" flag O_CLOEXEC or FD_CLOEXEC.
I wonder about the security implications. If a shell script opens a
"secret" file, and runs an external command, that command will have
direct access to the file.
How did you open the "secret" file? If you are managing the fd
yourself, it's simply a matter of closing it yourself before starting
any command where you don't want it leaked, such as:

exec 3< mysecret
command_allowed_to_use_it_via_stdin <&3
command_forbidden_to_use 3<-

Yeah, it's a bit of a pain that you can't specify O_CLOEXEC, but have to
track things yourself. On the other hand, O_CLOEXEC was added because of
multithreaded apps (where you absolutely need an atomic way to ensure an
fd opened in your thread of control is not leaked by a fork()/exec() in
a parallel thread of control). But the shell is single-threaded, and
therefore you don't have the risk of any other thread fork()ing (and
thus leaking your fd) outside of your thread of control. So you are
always able to manually manipulate fds without worrying about the race
that O_CLOEXEC was meant to solve.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org
R. Diez
2018-08-08 13:28:28 UTC
Permalink
Post by Eric Blake
How did you open the "secret" file? If you are managing
the fd yourself, it's simply a matter of closing it
yourself before starting any command where you don't
[...]
I am just planning the script, I have not written it yet.

Say I am using the file in a loop. If I close the file descriptor every
time before I run an external tool, I have to reopen the file and seek
to the last read position. Not very convenient.

OK, you can also stop file descriptor inheritance at every command, but
this is not practical. After all, you may want to consider all external
commands suspect, so you would have to do that for every command after
opening your file.

I understand that Bash has no threading problems. But it would still be
nice to be able to set FD_CLOEXEC manually after opening a file descriptor.

If Bash is managing the file itself, I wonder whether it should always
open it with O_CLOEXEC, just in case. Or maybe just have an option to do
that if you wish.

Leaking all file descriptors by default could be considered a security
risk. I would at least mention it explicitly in the man page, because
most people would not think of that when opening a file.

Best regards,
rdiez
Greg Wooledge
2018-08-08 13:32:40 UTC
Permalink
Post by R. Diez
I am just planning the script, I have not written it yet.
Say I am using the file in a loop. If I close the file descriptor every time
before I run an external tool, I have to reopen the file and seek to the
last read position. Not very convenient.
It would help to know a bit more about this file. Can't you simply
read the contents from it, and then close it? Is there a reason you
need to keep it open for a long time, but still want to prevent child
processes from gaining access?
Eric Blake
2018-08-08 15:06:37 UTC
Permalink
Post by R. Diez
Say I am using the file in a loop. If I close the file descriptor every
time before I run an external tool, I have to reopen the file and seek
to the last read position. Not very convenient.
Not true. You can close it on a per-command basis, while it still
remains open in the loop. That's what the 3<- file redirection operator
does when attached to a single command, rather than to exec.
Post by R. Diez
OK, you can also stop file descriptor inheritance at every command, but
this is not practical. After all, you may want to consider all external
commands suspect, so you would have to do that for every command after
opening your file.
Or do that on a group of commands. Something like:

exec 3< mysecret
while read ...
do
{
process the just-read line
} 3<-
done <3
exec 3<-
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org
Loading...