X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ipc%2Fsem.c;h=11b2960d6a20e909c969341dda6e81ce60c77cf4;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=2dae80d6013e5bfd06662c102d15a4fb33bdbaf6;hpb=cee37fe97739d85991964371c1f3a745c00dd236;p=linux-2.6.git diff --git a/ipc/sem.c b/ipc/sem.c index 2dae80d60..11b2960d6 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -56,11 +56,14 @@ * /proc/sysvipc/sem support (c) 1999 Dragos Acostachioaie * * SMP-threaded, sysctl's added - * (c) 1999 Manfred Spraul + * (c) 1999 Manfred Spraul * Enforced range limit on SEM_UNDO * (c) 2001 Red Hat Inc * Lockless wakeup * (c) 2003 Manfred Spraul + * + * support for audit of ipc object properties and permission changes + * Dustin Kirkland */ #include @@ -73,6 +76,10 @@ #include #include #include +#include +#include +#include + #include #include "util.h" @@ -89,7 +96,7 @@ static struct ipc_ids sem_ids; static int newary (key_t, int, int); static void freeary (struct sem_array *sma, int id); #ifdef CONFIG_PROC_FS -static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data); +static int sysvipc_sem_proc_show(struct seq_file *s, void *it); #endif #define SEMMSL_FAST 256 /* 512 bytes on stack */ @@ -116,10 +123,10 @@ void __init sem_init (void) { used_sems = 0; ipc_init_ids(&sem_ids,sc_semmni); - -#ifdef CONFIG_PROC_FS - create_proc_read_entry("sysvipc/sem", 0, NULL, sysvipc_sem_read_proc, NULL); -#endif + ipc_init_proc_interface("sysvipc/sem", + " key semid perms nsems uid gid cuid cgid otime ctime\n", + &sem_ids, + sysvipc_sem_proc_show); } /* @@ -137,7 +144,7 @@ void __init sem_init (void) * * if it's IN_WAKEUP, then it must wait until the value changes * * if it's not -EINTR, then the operation was completed by * update_queue. semtimedop can return queue.status without - * performing any operation on the semaphore array. + * performing any operation on the sem array. * * otherwise it must acquire the spinlock and check what's up. * * The two-stage algorithm is necessary to protect against the following @@ -194,6 +201,7 @@ static int newary (key_t key, int nsems, int semflg) } used_sems += nsems; + sma->sem_id = sem_buildid(id, sma->sem_perm.seq); sma->sem_base = (struct sem *) &sma[1]; /* sma->sem_pending = NULL; */ sma->sem_pending_last = &sma->sem_pending; @@ -202,7 +210,7 @@ static int newary (key_t key, int nsems, int semflg) sma->sem_ctime = get_seconds(); sem_unlock(sma); - return sem_buildid(id, sma->sem_perm.seq); + return sma->sem_id; } asmlinkage long sys_semget (key_t key, int nsems, int semflg) @@ -212,7 +220,7 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg) if (nsems < 0 || nsems > sc_semmsl) return -EINVAL; - down(&sem_ids.sem); + mutex_lock(&sem_ids.mutex); if (key == IPC_PRIVATE) { err = newary(key, nsems, semflg); @@ -225,8 +233,7 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg) err = -EEXIST; } else { sma = sem_lock(id); - if(sma==NULL) - BUG(); + BUG_ON(sma==NULL); if (nsems > sma->sem_nsems) err = -EINVAL; else if (ipcperms(&sma->sem_perm, semflg)) @@ -240,7 +247,7 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg) sem_unlock(sma); } - up(&sem_ids.sem); + mutex_unlock(&sem_ids.mutex); return err; } @@ -380,6 +387,7 @@ static void update_queue (struct sem_array * sma) /* hands-off: q will disappear immediately after * writing q->status. */ + smp_wmb(); q->status = error; q = n; } else { @@ -434,8 +442,8 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum) return semzcnt; } -/* Free a semaphore set. freeary() is called with sem_ids.sem down and - * the spinlock for this semaphore set hold. sem_ids.sem remains locked +/* Free a semaphore set. freeary() is called with sem_ids.mutex locked and + * the spinlock for this semaphore set hold. sem_ids.mutex remains locked * on exit. */ static void freeary (struct sem_array *sma, int id) @@ -460,6 +468,7 @@ static void freeary (struct sem_array *sma, int id) n = q->next; q->status = IN_WAKEUP; wake_up_process(q->sleeper); /* doesn't sleep */ + smp_wmb(); q->status = -EIDRM; /* hands-off q */ q = n; } @@ -521,7 +530,7 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu seminfo.semmnu = SEMMNU; seminfo.semmap = SEMMAP; seminfo.semume = SEMUME; - down(&sem_ids.sem); + mutex_lock(&sem_ids.mutex); if (cmd == SEM_INFO) { seminfo.semusz = sem_ids.in_use; seminfo.semaem = used_sems; @@ -530,7 +539,7 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu seminfo.semaem = SEMAEM; } max_id = sem_ids.max_id; - up(&sem_ids.sem); + mutex_unlock(&sem_ids.mutex); if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo))) return -EFAULT; return (max_id < 0) ? 0: max_id; @@ -805,8 +814,6 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun if(cmd == IPC_SET) { if(copy_semid_from_user (&setbuf, arg.buf, version)) return -EFAULT; - if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode))) - return err; } sma = sem_lock(semid); if(sma==NULL) @@ -817,7 +824,11 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun goto out_unlock; } ipcp = &sma->sem_perm; - + + err = audit_ipc_obj(ipcp); + if (err) + goto out_unlock; + if (current->euid != ipcp->cuid && current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) { err=-EPERM; @@ -834,6 +845,9 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun err = 0; break; case IPC_SET: + err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp); + if (err) + goto out_unlock; ipcp->uid = setbuf.uid; ipcp->gid = setbuf.gid; ipcp->mode = (ipcp->mode & ~S_IRWXUGO) @@ -882,9 +896,9 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) return err; case IPC_RMID: case IPC_SET: - down(&sem_ids.sem); + mutex_lock(&sem_ids.mutex); err = semctl_down(semid,semnum,cmd,version,arg); - up(&sem_ids.sem); + mutex_unlock(&sem_ids.mutex); return err; default: return -EINVAL; @@ -896,7 +910,7 @@ static inline void lock_semundo(void) struct sem_undo_list *undo_list; undo_list = current->sysvsem.undo_list; - if ((undo_list != NULL) && (atomic_read(&undo_list->refcnt) != 1)) + if (undo_list) spin_lock(&undo_list->lock); } @@ -916,7 +930,7 @@ static inline void unlock_semundo(void) struct sem_undo_list *undo_list; undo_list = current->sysvsem.undo_list; - if ((undo_list != NULL) && (atomic_read(&undo_list->refcnt) != 1)) + if (undo_list) spin_unlock(&undo_list->lock); } @@ -944,9 +958,7 @@ static inline int get_undo_list(struct sem_undo_list **undo_listp) if (undo_list == NULL) return -ENOMEM; memset(undo_list, 0, size); - /* don't initialize unodhd->lock here. It's done - * in copy_semundo() instead. - */ + spin_lock_init(&undo_list->lock); atomic_set(&undo_list->refcnt, 1); current->sysvsem.undo_list = undo_list; } @@ -1055,7 +1067,7 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops, struct sembuf fast_sops[SEMOPM_FAST]; struct sembuf* sops = fast_sops, *sop; struct sem_undo *un; - int undos = 0, decrease = 0, alter = 0, max; + int undos = 0, alter = 0, max; struct sem_queue queue; unsigned long jiffies_left = 0; @@ -1090,13 +1102,10 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops, if (sop->sem_num >= max) max = sop->sem_num; if (sop->sem_flg & SEM_UNDO) - undos++; - if (sop->sem_op < 0) - decrease = 1; - if (sop->sem_op > 0) + undos = 1; + if (sop->sem_op != 0) alter = 1; } - alter |= decrease; retry_undos: if (undos) { @@ -1183,8 +1192,7 @@ retry_undos: sma = sem_lock(semid); if(sma==NULL) { - if(queue.prev != NULL) - BUG(); + BUG_ON(queue.prev != NULL); error = -EIDRM; goto out_free; } @@ -1235,8 +1243,6 @@ int copy_semundo(unsigned long clone_flags, struct task_struct *tsk) error = get_undo_list(&undo_list); if (error) return error; - if (atomic_read(&undo_list->refcnt) == 1) - spin_lock_init(&undo_list->lock); atomic_inc(&undo_list->refcnt); tsk->sysvsem.undo_list = undo_list; } else @@ -1303,9 +1309,9 @@ found: /* perform adjustments registered in u */ nsems = sma->sem_nsems; for (i = 0; i < nsems; i++) { - struct sem * sem = &sma->sem_base[i]; + struct sem * semaphore = &sma->sem_base[i]; if (u->semadj[i]) { - sem->semval += u->semadj[i]; + semaphore->semval += u->semadj[i]; /* * Range checks of the new semaphore value, * not defined by sus: @@ -1319,11 +1325,11 @@ found: * * Manfred */ - if (sem->semval < 0) - sem->semval = 0; - if (sem->semval > SEMVMX) - sem->semval = SEMVMX; - sem->sempid = current->tgid; + if (semaphore->semval < 0) + semaphore->semval = 0; + if (semaphore->semval > SEMVMX) + semaphore->semval = SEMVMX; + semaphore->sempid = current->tgid; } } sma->sem_otime = get_seconds(); @@ -1336,54 +1342,24 @@ next_entry: } #ifdef CONFIG_PROC_FS -static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data) +static int sysvipc_sem_proc_show(struct seq_file *s, void *it) { - off_t pos = 0; - off_t begin = 0; - int i, len = 0; - - len += sprintf(buffer, " key semid perms nsems uid gid cuid cgid otime ctime\n"); - down(&sem_ids.sem); + struct sem_array *sma = it; - for(i = 0; i <= sem_ids.max_id; i++) { - struct sem_array *sma; - sma = sem_lock(i); - if (sma) { - if (!vx_check(sma->sem_perm.xid, VX_IDENT)) { - sem_unlock(sma); - continue; - } - len += sprintf(buffer + len, "%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n", - sma->sem_perm.key, - sem_buildid(i,sma->sem_perm.seq), - sma->sem_perm.mode, - sma->sem_nsems, - sma->sem_perm.uid, - sma->sem_perm.gid, - sma->sem_perm.cuid, - sma->sem_perm.cgid, - sma->sem_otime, - sma->sem_ctime); - sem_unlock(sma); + if (!vx_check(sma->sem_perm.xid, VX_IDENT)) + return 0; - pos += len; - if(pos < offset) { - len = 0; - begin = pos; - } - if(pos > offset + length) - goto done; - } - } - *eof = 1; -done: - up(&sem_ids.sem); - *start = buffer + (offset - begin); - len -= (offset - begin); - if(len > length) - len = length; - if(len < 0) - len = 0; - return len; + return seq_printf(s, + "%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n", + sma->sem_perm.key, + sma->sem_id, + sma->sem_perm.mode, + sma->sem_nsems, + sma->sem_perm.uid, + sma->sem_perm.gid, + sma->sem_perm.cuid, + sma->sem_perm.cgid, + sma->sem_otime, + sma->sem_ctime); } #endif