Bugtraq mailing list archives

Re: Foward: FreeBSD Security Advisory: FreeBSD-SA-00:19.semconfig


From: thorpej () ZEMBU COM (Jason R Thorpe)
Date: Fri, 26 May 2000 16:48:28 -0700


On Sat, May 27, 2000 at 08:29:18AM +0900, Takahiro Kambe wrote:

This advisory says that the problem also exists in NetBSD.

The advisory is wrong[*].

If you examine the code in NetBSD (which FreeBSD should have done before
claiming that NetBSD was vulnerable as claimed in the alert), you will
note that if the exiting process is not using semaphores (i.e. has no
`sem_undo' structure allocated for it), then the exiting process will
not block, but rather semexit() will simply return.

The corresponding commit log message for kern/sysv_sem.c is:

revision 1.14
date: 1994/12/05 07:22:12;  author: mycroft;  state: Exp;  lines: +83 -16
Merge changes from Daniel Boulet to avoid waiting for the semaphore lock in
semexit() if there are no undo records to process.

[*] Technically speaking, if the exiting process was using semaphores,
yes, it is vulnerable.  But there aren't very many that do.  In any
case, it's a far cry from "prevent all processes from exiting".

--
Takahiro Kambe <taca () sky yamashina kyoto jp>

To: undisclosed-recipients: ;
Date: Fri, 26 May 2000 10:32:23 -0700 (PDT)
From: FreeBSD Security Officer <security-officer () freebsd org>
From: FreeBSD Security Officer <security-officer () freebsd org>
Subject: FreeBSD Security Advisory: FreeBSD-SA-00:19.semconfig

-----BEGIN PGP SIGNED MESSAGE-----

=============================================================================
FreeBSD-SA-00:19                                           Security Advisory
                                                                FreeBSD, Inc.

Topic:               local users can prevent all processes from exiting

Category:    core
Module:              kernel
Announced:   2000-05-26
Credits:     Peter Wemm <peter () FreeBSD org>
Affects:     386BSD-derived OSes, including all versions of FreeBSD,
             NetBSD and OpenBSD.
Corrected:   2000-05-01
FreeBSD only:        NO
Patch:               ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-00:19/semconfig.patch

I.   Background

System V IPC is a set of interfaces for providing inter-process
communication, in the form of shared memory segments, message queues
and semaphores. These are managed in user-space by ipcs(1) and
related utilities.

II.  Problem Description

An undocumented system call is incorrectly exported from the kernel
without access-control checks. This operation causes the acquisition
in the kernel of a global semaphore which causes all processes on the
system to block during exit() handling, thereby preventing any process
from exiting until the corresponding "unblock" system call is issued.

This operation was intended for use only by ipcs(1) to atomically
sample the state of System V IPC resources on the system (i.e., to
ensure that resources are not allocated or deallocated during the
process of sampling itself).

In the future, this functionality may be reimplemented as a sysctl()
node.

III. Impact

An unprivileged local user can cause every process on the system to
hang during exiting. In other words, after the system call is issued,
no process on the system will be able to exit completely until another
user issues the "unblock" call or the system is rebooted. This is a
denial-of-service attack.

IV.  Workaround

None available.

V.   Solution

Upgrade to FreeBSD 2.1.7.1-STABLE, 2.2.8-STABLE, 3.4-STABLE,
4.0-STABLE or 5.0-CURRENT after the correction date.

Alternatively, apply the following patch and rebuild the kernel and
the src/usr.bin/ipcs utility. This patch removes the semconfig()
syscall. It has been tested to apply cleanly against 3.4-RELEASE,
3.4-STABLE, 4.0-RELEASE and 4.0-STABLE systems.

1) Save this advisory as a file, and run the following commands as root:

# cd /usr/src
# patch -p < /path/to/advisory
# cd usr.bin/ipcs
# make all install

2) Rebuild and reinstall the kernel and kernel modules as described in
the FreeBSD handbook (see:
http://www.freebsd.org/handbook/kernelconfig.html for more information)

3) Reboot the system

Patches for FreeBSD systems before the resolution date:

    --- sys/kern/syscalls.master     2000/01/19 06:01:07     1.72
    +++ sys/kern/syscalls.master     2000/05/01 11:15:10     1.72.2.1
    @@ -342,7 +342,7 @@
     221     STD     BSD     { int semget(key_t key, int nsems, int semflg); }
     222     STD     BSD     { int semop(int semid, struct sembuf *sops, \
                                 u_int nsops); }
    -223     STD     BSD     { int semconfig(int flag); }
    +223     UNIMPL  NOHIDE  semconfig
     224     STD     BSD     { int msgctl(int msqid, int cmd, \
                                 struct msqid_ds *buf); }
     225     STD     BSD     { int msgget(key_t key, int msgflg); }
    --- sys/kern/init_sysent.c       2000/01/19 06:02:29     1.79
    +++ sys/kern/init_sysent.c       2000/05/01 11:15:56     1.79.2.1
    @@ -243,7 +243,7 @@
             { 4, (sy_call_t *)__semctl },                   /* 220 = __semctl */
             { 3, (sy_call_t *)semget },                     /* 221 = semget */
             { 3, (sy_call_t *)semop },                      /* 222 = semop */
    -        { 1, (sy_call_t *)semconfig },                  /* 223 = semconfig */
    +        { 0, (sy_call_t *)nosys },                      /* 223 = semconfig */
             { 3, (sy_call_t *)msgctl },                     /* 224 = msgctl */
             { 2, (sy_call_t *)msgget },                     /* 225 = msgget */
             { 4, (sy_call_t *)msgsnd },                     /* 226 = msgsnd */
    --- sys/kern/syscalls.c  2000/01/19 06:02:29     1.71
    +++ sys/kern/syscalls.c  2000/05/01 11:15:56     1.71.2.1
    @@ -230,7 +230,7 @@
             "__semctl",                     /* 220 = __semctl */
             "semget",                       /* 221 = semget */
             "semop",                        /* 222 = semop */
    -        "semconfig",                    /* 223 = semconfig */
    +        "#223",                 /* 223 = semconfig */
             "msgctl",                       /* 224 = msgctl */
             "msgget",                       /* 225 = msgget */
             "msgsnd",                       /* 226 = msgsnd */
    --- sys/kern/sysv_ipc.c  2000/02/29 22:58:59     1.13
    +++ sys/kern/sysv_ipc.c  2000/05/01 11:15:56     1.13.2.1
    @@ -107,15 +107,6 @@
     semsys(p, uap)
             struct proc *p;
             struct semsys_args *uap;
    -{
    -        sysv_nosys(p, "SYSVSEM");
    -        return nosys(p, (struct nosys_args *)uap);
    -};
    -
    -int
    -semconfig(p, uap)
    -        struct proc *p;
    -        struct semconfig_args *uap;
     {
             sysv_nosys(p, "SYSVSEM");
             return nosys(p, (struct nosys_args *)uap);
    --- sys/kern/sysv_sem.c  2000/04/02 08:47:08     1.24.2.1
    +++ sys/kern/sysv_sem.c  2000/05/01 11:15:56     1.24.2.2
    @@ -26,8 +26,6 @@
     int semget __P((struct proc *p, struct semget_args *uap));
     struct semop_args;
     int semop __P((struct proc *p, struct semop_args *uap));
    -struct semconfig_args;
    -int semconfig __P((struct proc *p, struct semconfig_args *uap));
     #endif

     static struct sem_undo *semu_alloc __P((struct proc *p));
    @@ -38,7 +36,7 @@
     /* XXX casting to (sy_call_t *) is bogus, as usual. */
     static sy_call_t *semcalls[] = {
             (sy_call_t *)__semctl, (sy_call_t *)semget,
    -        (sy_call_t *)semop, (sy_call_t *)semconfig
    +        (sy_call_t *)semop
     };

     static int      semtot = 0;
    @@ -47,8 +45,6 @@
     static struct sem_undo *semu_list;      /* list of active undo structures */
     int     *semu;                  /* undo structure pool */

    -static struct proc *semlock_holder = NULL;
    -
     void
     seminit(dummy)
             void *dummy;
    @@ -87,64 +83,12 @@
             } */ *uap;
     {

    -        while (semlock_holder != NULL && semlock_holder != p)
    -                (void) tsleep((caddr_t)&semlock_holder, (PZERO - 4), "semsys", 0);
    -
             if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
                     return (EINVAL);
             return ((*semcalls[uap->which])(p, &uap->a2));
     }

     /*
    - * Lock or unlock the entire semaphore facility.
    - *
    - * This will probably eventually evolve into a general purpose semaphore
    - * facility status enquiry mechanism (I don't like the "read /dev/kmem"
    - * approach currently taken by ipcs and the amount of info that we want
    - * to be able to extract for ipcs is probably beyond what the capability
    - * of the getkerninfo facility.
    - *
    - * At the time that the current version of semconfig was written, ipcs is
    - * the only user of the semconfig facility.  It uses it to ensure that the
    - * semaphore facility data structures remain static while it fishes around
    - * in /dev/kmem.
    - */
    -
    -#ifndef _SYS_SYSPROTO_H_
    -struct semconfig_args {
    -        semconfig_ctl_t flag;
    -};
    -#endif
    -
    -int
    -semconfig(p, uap)
    -        struct proc *p;
    -        struct semconfig_args *uap;
    -{
    -        int eval = 0;
    -
    -        switch (uap->flag) {
    -        case SEM_CONFIG_FREEZE:
    -                semlock_holder = p;
    -                break;
    -
    -        case SEM_CONFIG_THAW:
    -                semlock_holder = NULL;
    -                wakeup((caddr_t)&semlock_holder);
    -                break;
    -
    -        default:
    -                printf("semconfig: unknown flag parameter value (%d) - ignored\n",
    -                    uap->flag);
    -                eval = EINVAL;
    -                break;
    -        }
    -
    -        p->p_retval[0] = 0;
    -        return(eval);
    -}
    -
    -/*
      * Allocate a new sem_undo structure for a process
      * (returns ptr to structure or NULL if no more room)
      */
    @@ -873,17 +817,6 @@
             register struct sem_undo **supptr;
             int did_something;

    -        /*
    -         * If somebody else is holding the global semaphore facility lock
    -         * then sleep until it is released.
    -         */
    -        while (semlock_holder != NULL && semlock_holder != p) {
    -#ifdef SEM_DEBUG
    -                printf("semaphore facility locked - sleeping ...\n");
    -#endif
    -                (void) tsleep((caddr_t)&semlock_holder, (PZERO - 4), "semext", 0);
    -        }
    -
             did_something = 0;

             /*
    @@ -898,7 +831,7 @@
             }

             if (suptr == NULL)
    -                goto unlock;
    +                return;

     #ifdef SEM_DEBUG
             printf("proc @%08x has undo structure with %d entries\n", p,
    @@ -955,14 +888,4 @@
     #endif
             suptr->un_proc = NULL;
             *supptr = suptr->un_next;
    -
    -unlock:
    -        /*
    -         * If the exiting process is holding the global semaphore facility
    -         * lock then release it.
    -         */
    -        if (semlock_holder == p) {
    -                semlock_holder = NULL;
    -                wakeup((caddr_t)&semlock_holder);
    -        }
     }

    --- sys/sys/sem.h        1999/12/29 04:24:46     1.20
    +++ sys/sys/sem.h        2000/05/01 11:15:58     1.20.2.1
    @@ -163,13 +163,5 @@
      * Process sem_undo vectors at proc exit.
      */
     void    semexit __P((struct proc *p));
    -
    -/*
    - * Parameters to the semconfig system call
    - */
    -typedef enum {
    -        SEM_CONFIG_FREEZE,      /* Freeze the semaphore facility. */
    -        SEM_CONFIG_THAW         /* Thaw the semaphore facility. */
    -} semconfig_ctl_t;
     #endif /* _KERNEL */

    --- sys/sys/syscall-hide.h       2000/01/19 06:02:31     1.65
    +++ sys/sys/syscall-hide.h       2000/05/01 11:15:58     1.65.2.1
    @@ -191,7 +191,6 @@
     HIDE_BSD(__semctl)
     HIDE_BSD(semget)
     HIDE_BSD(semop)
    -HIDE_BSD(semconfig)
     HIDE_BSD(msgctl)
     HIDE_BSD(msgget)
     HIDE_BSD(msgsnd)
    --- sys/sys/syscall.h    2000/01/19 06:02:31     1.69
    +++ sys/sys/syscall.h    2000/05/01 11:15:59     1.69.2.1
    @@ -196,7 +196,6 @@
     #define SYS___semctl    220
     #define SYS_semget      221
     #define SYS_semop       222
    -#define SYS_semconfig   223
     #define SYS_msgctl      224
     #define SYS_msgget      225
     #define SYS_msgsnd      226
    --- sys/sys/syscall.mk   2000/01/19 06:07:34     1.23
    +++ sys/sys/syscall.mk   2000/05/01 11:15:59     1.23.2.1
    @@ -148,7 +148,6 @@
             __semctl.o \
             semget.o \
             semop.o \
    -        semconfig.o \
             msgctl.o \
             msgget.o \
             msgsnd.o \
    --- sys/sys/sysproto.h   2000/01/19 06:02:31     1.59
    +++ sys/sys/sysproto.h   2000/05/01 11:16:00     1.59.2.1
    @@ -662,9 +662,6 @@
             struct sembuf * sops;   char sops_[PAD_(struct sembuf *)];
             u_int   nsops;  char nsops_[PAD_(u_int)];
     };
    -struct  semconfig_args {
    -        int     flag;   char flag_[PAD_(int)];
    -};
     struct  msgctl_args {
             int     msqid;  char msqid_[PAD_(int)];
             int     cmd;    char cmd_[PAD_(int)];
    @@ -1158,7 +1155,6 @@
     int     __semctl __P((struct proc *, struct __semctl_args *));
     int     semget __P((struct proc *, struct semget_args *));
     int     semop __P((struct proc *, struct semop_args *));
    -int     semconfig __P((struct proc *, struct semconfig_args *));
     int     msgctl __P((struct proc *, struct msgctl_args *));
     int     msgget __P((struct proc *, struct msgget_args *));
     int     msgsnd __P((struct proc *, struct msgsnd_args *));
    --- usr.bin/ipcs/ipcs.c  1999/12/29 05:05:32     1.12
    +++ usr.bin/ipcs/ipcs.c  2000/05/01 10:51:37     1.12.2.1
    @@ -56,7 +56,6 @@
     struct shminfo  shminfo;
     struct shmid_ds *shmsegs;

    -int     semconfig __P((int,...));
     void    usage __P((void));

     static struct nlist symbols[] = {
    @@ -420,11 +419,6 @@
                                 seminfo.semaem);
                     }
                     if (display & SEMINFO) {
    -                        if (semconfig(SEM_CONFIG_FREEZE) != 0) {
    -                                perror("semconfig");
    -                                fprintf(stderr,
    -                                    "Can't lock semaphore facility - winging it...\n");
    -                        }
                             kvm_read(kd, symbols[X_SEMA].n_value, &sema, sizeof(sema));
                             xsema = malloc(sizeof(struct semid_ds) * seminfo.semmni);
                             kvm_read(kd, (u_long) sema, xsema, sizeof(struct semid_ds) * seminfo.semmni);
    @@ -470,8 +464,6 @@
                                             printf("\n");
                                     }
                             }
    -
    -                        (void) semconfig(SEM_CONFIG_THAW);

                             printf("\n");
                     }


-----BEGIN PGP SIGNATURE-----
Version: 2.6.2

iQCVAwUBOS60U1UuHi5z0oilAQHsmQP/aCL1lV5RiVnP9Cm6AE6NU6o3pqFLKQWa
RIeGgjOHJ8ctkQQj3ljECh49eCsdYKSGYkPzFlPg2ikgRylcjQDo+pakLB3IUuEE
X+bSvyaayM5yF+v2pLj7FgarcvxsbattzL8WcHcNMWAJ5wCyceh85/8bsUdVyEJm
Qw17BQPDPcU=
=hKnq
-----END PGP SIGNATURE-----


This is the moderated mailing list freebsd-announce.
The list contains announcements of new FreeBSD capabilities,
important events and project milestones.
See also the FreeBSD Web pages at http://www.freebsd.org


To Unsubscribe: send mail to majordomo () FreeBSD org
with "unsubscribe freebsd-announce" in the body of the message


--
        -- Jason R. Thorpe <thorpej () zembu com>



Current thread: