Mercurial > hg > octave-lyh > gnulib-hg
changeset 13784:69ee8a8d4ebd
fdopendir: fix a bug on systems lacking openat and /proc support
OpenBSD 4.7 is one such system. The most noticeable effect was
failure of any application making nontrivial use of fts: rm, du,
chown, chmod etc. E.g., "mkdir -p a/b; ./rm -rf a" would fail with
./rm: traversal failed: `a': Bad file descriptor
Debugging that, you see that even though FD 6 was closed just
prior to the opendir call in fd_clone_opendir, its resulting
dir->dd_fd was 8, rather than the expected value of 6:
Breakpoint 3, fdopendir_with_dup (fd=6, older_dupfd=-1) at fdopendir.c:93
93 close (fd);
(gdb) n
94 dir = fd_clone_opendir (dupfd);
(gdb) n
95 saved_errno = errno;
(gdb) p dir->dd_fd
$11 = 8
Notice how it closes FD 6, then gets a DIR* pointer using FD 8.
The problem is that on OpenBSD, fd_clone_opendir has to resort
to using the old-style save/restore CWD mechanism, due to its
lack of openat/proc support, and *that* would steal the FD (6)
that opendir was supposed to use.
The fix is to squirrel away the desired FD so that save_cwd uses a
different one, and then free the dest FD right before calling opendir.
That guarantees opendir will use the required file descriptor.
* lib/fdopendir.c (fd_clone_opendir): Handle the above.
author | Jim Meyering <meyering@redhat.com> |
---|---|
date | Fri, 08 Oct 2010 18:42:59 +0200 |
parents | 47adc262f2b7 |
children | ff58e398c6aa |
files | ChangeLog lib/fdopendir.c |
diffstat | 2 files changed, 46 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +2010-10-08 Jim Meyering <meyering@redhat.com> + + fdopendir: fix a bug on systems lacking openat and /proc support + OpenBSD 4.7 is one such system. The most noticeable effect was + failure of any application making nontrivial use of fts: rm, du, + chown, chmod etc. E.g., "mkdir -p a/b; ./rm -rf a" would fail with + ./rm: traversal failed: `a': Bad file descriptor + Debugging that, you see that even though FD 6 was closed just + prior to the opendir call in fd_clone_opendir, its resulting + dir->dd_fd was 8, rather than the expected value of 6: + + Breakpoint 3, fdopendir_with_dup (fd=6, older_dupfd=-1) at fdopendir.c:93 + 93 close (fd); + (gdb) n + 94 dir = fd_clone_opendir (dupfd); + (gdb) n + 95 saved_errno = errno; + (gdb) p dir->dd_fd + $11 = 8 + + Notice how it closes FD 6, then gets a DIR* pointer using FD 8. + The problem is that on OpenBSD, fd_clone_opendir has to resort + to using the old-style save/restore CWD mechanism, due to its + lack of openat/proc support, and *that* would steal the FD (6) + that opendir was supposed to use. + + The fix is to squirrel away the desired FD so that save_cwd uses a + different one, and then free the dest FD right before calling opendir. + That guarantees opendir will use the required file descriptor. + + * lib/fdopendir.c (fd_clone_opendir): Handle the above. + 2010-10-08 Bruno Haible <bruno@clisp.org> sys_select: Avoid warning due to undeclared memset() on OpenBSD 4.5.
--- a/lib/fdopendir.c +++ b/lib/fdopendir.c @@ -140,10 +140,23 @@ dir = opendir (name); saved_errno = errno; # else /* !REPLACE_FCHDIR */ + + /* Occupy the destination FD slot, so that save_cwd cannot hijack it. */ + int fd_reserve = dup (fd); + if (fd_reserve < 0) + { + saved_errno = errno; + dir = NULL; + goto fail; + } + struct saved_cwd saved_cwd; if (save_cwd (&saved_cwd) != 0) openat_save_fail (errno); + /* Liberate the target file descriptor, so that opendir uses it. */ + close (fd_reserve); + if (fchdir (fd) != 0) { dir = NULL; @@ -162,6 +175,7 @@ # endif /* !REPLACE_FCHDIR */ } + fail: if (proc_file != buf) free (proc_file); errno = saved_errno;