Re: Symlinks and Cryogenic Sleep

From: Marc Heuse (marcat_private)
Date: Tue Jan 04 2000 - 11:20:07 PST

  • Next message: Nick Phillips: "JS problem in NS4.5 - known?"

    Hi,
    
    >when you're dealing with files in /tmp that are supposed to be re-opened
    >(rather than opened once and then discarded) there's an established
    >way to do it which goes like this:
    >
    >        if (lstat(fname, &stb1) >= 0 && S_ISREG(stb1.st_mode)) {
    >                fd = open(fname, O_RDWR);
    >                if (fd < 0 || fstat(fd, &stb2) < 0
    >                 || ino_or_dev_mismatch(&stb1, &stb2))
    >                        raise_big_stink()
    >        } else {
    >                /* do the O_EXCL thing */
    >        }
    >
    >Accepted wisdom has it that this protects you from symlink attacks.
    
    yes, but not from hardlink attacks
    
    >When trying to explain this to someone, I noticed that this is not quite
    >what it does. It protects your application against symlinks to files
    >that exist *before the call to lstat*.
    >This sounds like I'm nitpicking, and my first reaction also was to try
    >to find some convincing handwaving argument to dispel my concerns.
    
    no, thats right, there is still a small race condition.
    Thats the reason why O_NOFOLLOW was added to the kernel (bsd and linux >= 2.1.126)
    
    > -      All symlink attacks can be improved by running them on an
    >        NFS mounted directory (easy for applications that heed
    >        the TMPDIR environment variable). In terms of file system
    >        race conditions, NFS acts as a kind of slo-mo glue.
    
    however, who is mounting /tmp via NFS? rare (can be found sometimes, yes)
    And it's always a good idea to make /tmp a partition of it's own.
    (and Theo de Raadt even goes that far to set quotas on /tmp ... ;-)
    
    > -      It's not that hard to detect whether the targetted application is
    >        in the critical section of code. On Linux, it's very easy because
    >        /proc/$pid/stat will give you the instruction pointer. On other OSes
    
    wasn't that fixed? Thomas (thomasat_private) found that vulnerability and
    reported it. As far as I know it's fixed (hmm, but I'm not sure).
    
    >Comments? Suggestions?
    
    hmm, I'd propose the following function to protect against the hard/symlink
    attacks (add syslog/warnings wherever you want to). Comments welcome.
    
    #ifndef O_NOFOLLOW
    # define O_NOFOLLOW 0  // was introduced in kernel 2.1.126, needs glibc > 2.0.100
    #endif
    
    int safe_reopen (char *file, int modes) {
        struct stat st;
        struct stat st2;
        int fd;
    
        if (lstat(TMPFILE, &st) < 0) { // does not exit -> safe creation
            if ((fd=open(TMPFILE, modes | O_EXCL | O_CREAT, 0600)) < 0)
                return -1;
        } else { // it exists - allow only regular file which are not hardlinked
    	if ((! S_ISREG(st.st_mode)) || st.st_nlink != 1)
    	    return -1; // OK, lets open
    	if ((fd=open(TMPFILE, modes | O_NOFOLLOW)) < 0)
    	    return -1;
    	fstat(fd, &st2); // recheck that it's the same file ...
    	if (st2.st_ino != st.st_ino || st2.st_uid != st.st_uid || st2.st_nlink != 1) {
    	    close(fd);
    	    return -1;
    	}
        }
        return fd;
    }
    
    
    Greets,
    	Marc
    --
       Marc Heuse, SuSE GmbH, Schanzaeckerstr. 10, 90443 Nuernberg
       E@mail: marcat_private  Function: Security Support & Auditing
       "lynx -source http://www.suse.de/~marc/marc.pgp | pgp -fka"
    Key fingerprint = B5 07 B6 4E 9C EF 27 EE  16 D9 70 D4 87 B5 63 6C
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 15:26:34 PDT