NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

lib/40319: fts_close() spuriously closes fd 0



>Number:         40319
>Category:       lib
>Synopsis:       fts_close() spuriously closes fd 0
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Jan 03 00:50:00 +0000 2009
>Originator:     Ben Harris
>Release:        4.0.1
>Organization:
>Environment:
NetBSD aquila.bjh21.me.uk 5.0_BETA NetBSD 5.0_BETA (GENERIC.MP) #0: Wed Dec 31 
03:56:29 UTC 2008  
builds%b6.netbsd.org@localhost:/home/builds/ab/netbsd-5/sparc64/200812300000Z-obj/home/builds/ab/netbsd-5/src/sys/arch/sparc64/compile/GENERIC.MP
 sparc64

>Description:
NB: problem system is running a 4.0.1 userland on a 5.0_BETA kernel.  I
don't think this matters, though.

The problem is a simple one: if fts_open() is called with an "options"
argument that includes FTS_LOGICAL, then an immediate call of fts_close()
will close file descriptor 0 (standard input).

>How-To-Repeat:
Compile and run this program:

#include <sys/stat.h>

#include <err.h>
#include <fts.h>
#include <stdio.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
        FTS *ftsp;
        char *path_argv[2];
        struct stat st;

        path_argv[0] = "/";
        path_argv[1] = NULL;
        if ((ftsp = fts_open(path_argv, FTS_LOGICAL, NULL)) == NULL)
                err(1, "fts_open");
        if (fts_close(ftsp) != 0) err(1, "fts_close");
        if (fstat(STDIN_FILENO, &st) != 0) err(1, "stdin");
        return 0;
}

On my system, this happens:

aquila:~$ cc -o fts_close_bug{,.c}
aquila:~$ ./fts_close_bug 
fts_close_bug: stdin: Bad file descriptor

>Fix:
I think the problem lies in the use of ISSET(FTS_SYMFOLLOW) in fts.c.
ISSET tests the fts_options field, but the FTS_SYMFOLLOW flag is in
fts_flags.  The value of FTS_SYMFOLLOW is the same as that of FTS_LOGICAL,
so if the latter is set, fts_close treats fts_cur->fts_symfd as being valid and
closes it, hence causing the problem.  The obvious fix is as follows,
but I don't know the fts code at all well and I've not tested this since
I don't yet have a running -current system to test it on.

--- fts.c       02 Jan 2009 16:24:24 +0000      1.34
+++ fts.c       03 Jan 2009 00:43:27 +0000      
@@ -256,7 +256,7 @@
         * list which has a valid parent pointer.
         */
        if (sp->fts_cur) {
-               if (ISSET(FTS_SYMFOLLOW))
+               if (sp->fts_cur->fts_flags & FTS_SYMFOLLOW)
                        (void)close(sp->fts_cur->fts_symfd);
                for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
                        freep = p;




Home | Main Index | Thread Index | Old Index