FW: FreeBSD Security Advisory: FreeBSD-SA-00:01.make

From: FreeBSD Security Officer (security-officerat_private)
Date: Wed Jan 19 2000 - 11:05:24 PST

  • Next message: Pavel Machek: "Re: Trusted process on an untrusted machine?"

    -----FW: <200001191905.MAA27712at_private>-----
    
    Date: Wed, 19 Jan 2000 12:05:24 -0700 (MST)
    Sender: owner-freebsd-securityat_private
    From: FreeBSD Security Officer <security-officerat_private>
    To: undisclosed-recipients:;
    Subject: FreeBSD Security Advisory: FreeBSD-SA-00:01.make
    
    -----BEGIN PGP SIGNED MESSAGE-----
    
    =============================================================================
    FreeBSD-SA-00:01                                            Security Advisory
                                                                    FreeBSD, Inc.
    
    Topic:          Insecure temporary file handling in make(1)
    
    Category:       core
    Module:         make
    Announced:      2000-01-19
    Affects:        All versions before the correction date.
    Corrected:      2000-01-16
    FreeBSD only:   NO
    
    Patches:
    ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-00:01/make.patch
    
    I.   Background
    
    The make(1) program is typically used to schedule building of source
    code. It has a switch ('-j') to allow parallel building by spawning
    multiple child processes.
    
    II.  Problem Description
    
    The -j option to make(1) uses temporary files in /tmp to communicate
    with its child processes by storing the shell command the child should
    execute. This is useful on multi-processor architectures for making
    use of all of the available CPUs, and is also widely used on
    uniprocessor systems to minimize the scheduling latency of the build
    process.
    
    However make(1) uses the temporary file in an insecure way, repeatedly
    deleting and reusing the same file name for the entire life of the
    program. This makes it vulnerable to a race condition wherein a
    malicious user could observe the name of the temporary file being
    used, and replace the contents of a later instance of the file with
    her desired commands after the legitimate commands have been written.
    
    This vulnerability was discovered as part of the FreeBSD Auditing
    Project, an ongoing effort to identify and correct security
    vulnerabilities in the FreeBSD operating system.
    
    All versions of NetBSD and OpenBSD are also believed to be vulnerable
    to this problem. Other systems using a BSD-derived make(1) binary may
    also be vulnerable.
    
    III. Impact
    
    Local users could execute arbitrary shell commands as part of the
    build process scheduled by "make -j" by another user.
    
    IV.  Workaround
    
    Avoid using the '-j' flag to make(1).
    
    V.   Solution
    
    Upgrade your system to one that is listed above as having the problem
    resolved, or patch your present system.
    
    To patch your present system: save the patch below into a file, and
    execute the following commands as root:
    
    cd /usr/src/usr.bin/make
    patch < /path/to/patch/file
    make all
    make install
    
    Patches for 3.4-STABLE and 4.0-CURRENT systems before the resolution date:
    
        Index: job.c
        ===================================================================
        RCS file: /home/ncvs/src/usr.bin/make/job.c,v
        retrieving revision 1.16
        diff -u -r1.16 job.c
        --- job.c   1999/09/11 13:08:01     1.16
        +++ job.c   2000/01/17 01:42:57
        @@ -163,14 +163,6 @@
         #define JOB_STOPPED        3       /* The job is stopped */
    
         /*
        - * tfile is the name of a file into which all shell commands are put. It is
        - * used over by removing it before the child shell is executed. The
    XXXXXXXXXX
        - * in the string are replaced by mkstemp(3).
        - */
        -static char     tfile[sizeof(TMPPAT)];
        -
        -
        -/*
          * Descriptions for various shells.
          */
         static Shell    shells[] = {
        @@ -993,7 +985,7 @@
            /*
             * If we are aborting and the job table is now empty, we finish.
             */
        -   (void) eunlink(tfile);
        +   (void) eunlink(job->tfile);
            Finish(errors);
             }
         }
        @@ -1668,6 +1660,7 @@
             Boolean          cmdsOK;     /* true if the nodes commands were all
    right */
             Boolean          local;      /* Set true if the job was run locally */
             Boolean          noExec;     /* Set true if we decide not to run the
    job */
        +    int              tfd;        /* File descriptor for temp file */
    
             if (previous != NULL) {
            previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE);
        @@ -1697,6 +1690,12 @@
             }
             job->flags |= flags;
    
        +    (void) strcpy(job->tfile, TMPPAT);
        +    if ((tfd = mkstemp(job->tfile)) == -1)
        +   Punt("cannot create temp file: %s", strerror(errno));
        +    else
        +   (void) close(tfd);
        +
             /*
              * Check the commands now so any attributes from .DEFAULT have a chance
              * to migrate to the node
        @@ -1722,9 +1721,9 @@
                DieHorribly();
            }
    
        -   job->cmdFILE = fopen(tfile, "w+");
        +   job->cmdFILE = fopen(job->tfile, "w+");
            if (job->cmdFILE == NULL) {
        -       Punt("Could not open %s", tfile);
        +       Punt("Could not open %s", job->tfile);
            }
            (void) fcntl(FILENO(job->cmdFILE), F_SETFD, 1);
            /*
        @@ -1830,7 +1829,7 @@
             * Unlink and close the command file if we opened one
             */
            if (job->cmdFILE != stdout) {
        -       (void) eunlink(tfile);
        +       (void) eunlink(job->tfile);
                if (job->cmdFILE != NULL)
                    (void) fclose(job->cmdFILE);
            } else {
        @@ -1859,7 +1858,7 @@
            }
             } else {
            (void) fflush(job->cmdFILE);
        -   (void) eunlink(tfile);
        +   (void) eunlink(job->tfile);
             }
    
             /*
        @@ -2403,13 +2402,6 @@
                                 * be running at once. */
         {
             GNode         *begin;     /* node for commands to do at the very start
    */
        -    int              tfd;
        -
        -    (void) strcpy(tfile, TMPPAT);
        -    if ((tfd = mkstemp(tfile)) == -1)
        -   Punt("cannot create temp file: %s", strerror(errno));
        -    else
        -   (void) close(tfd);
    
             jobs =           Lst_Init(FALSE);
             stoppedJobs = Lst_Init(FALSE);
        @@ -2914,7 +2906,7 @@
                }
            }
             }
        -    (void) eunlink(tfile);
        +    (void) eunlink(job->tfile);
         }
    
         /*
        @@ -2948,7 +2940,6 @@
                }
            }
             }
        -    (void) eunlink(tfile);
             return(errors);
         }
    
        @@ -3024,6 +3015,7 @@
                KILL(job->pid, SIGINT);
                KILL(job->pid, SIGKILL);
         #endif /* RMT_WANTS_SIGNALS */
        +       (void) eunlink(job->tfile);
            }
             }
    
        @@ -3032,7 +3024,6 @@
              */
             while (waitpid((pid_t) -1, &foo, WNOHANG) > 0)
            continue;
        -    (void) eunlink(tfile);
         }
    
         #ifdef REMOTE
        Index: job.h
        ===================================================================
        RCS file: /home/ncvs/src/usr.bin/make/job.h,v
        retrieving revision 1.10
        diff -u -r1.10 job.h
        --- job.h   1999/08/28 01:03:31     1.10
        +++ job.h   2000/01/17 01:42:31
        @@ -93,6 +93,8 @@
         #define JOB_BUFSIZE        1024
         typedef struct Job {
             int            pid;        /* The child's process ID */
        +    char   tfile[sizeof(TMPPAT)];
        +                       /* Temporary file to use for job */
             GNode          *node;      /* The target the child is making */
             LstNode        tailCmds;   /* The node of the first command to be
                                 * saved when the job has been run */
    
    =============================================================================
    FreeBSD, Inc.
    
    Web Site:                       http://www.freebsd.org/
    Confidential contacts:          security-officerat_private
    Security notifications:         security-notificationsat_private
    Security public discussion:     freebsd-securityat_private
    PGP Key:                ftp://ftp.freebsd.org/pub/FreeBSD/CERT/public_key.asc
    
    Notice: Any patches in this document may not apply cleanly due to
            modifications caused by digital signature or mailer software.
            Please reference the URL listed at the top of this document
            for original copies of all patches if necessary.
    =============================================================================
    
    -----BEGIN PGP SIGNATURE-----
    Version: 2.6.3ia
    Charset: noconv
    Comment: Processed by Mailcrypt 3.4, an Emacs/PGP interface
    
    iQCVAwUBOIVvCFUuHi5z0oilAQF7nQP+No1n5Rl2g0ltvu+Vrx2ImMZreOwz04zZ
    a6MM+bQQ0q/pXgupzSQ3xcfpzZzHjQx2+ajMg4P+l7+OsBvjBvrVFrc021rRW18W
    Ds3A/Vlm8seaWOe4Q4u5qSTdp2PO9HXJrEQWL37xAQtqVyT3J2E37MQyEfENWg4d
    FeIUCiTIMuA=
    =86yT
    -----END PGP SIGNATURE-----
    
    
    To Unsubscribe: send mail to majordomoat_private
    with "unsubscribe freebsd-security" in the body of the message
    
    --------------End of forwarded message-------------------------
    
    --
    * Fido: 2:480/124 ** WWW: http://www.FreeBSD.lublin.pl ** NIC-HDL: PMF9-RIPE *
    * Inet: venglinat_private ** PGP: D48684904685DF43  EA93AFA13BE170BF *
    



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