X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=ipc%2Fshm.c;h=8098968519026406191014b4cb64ee870e2a721c;hb=8b8c8d280ab2d18fe6e42d671f60d4ffed451cdc;hp=b58c651d31ae23a36c58a1de3005e6b5d46a2662;hpb=ba77df570c6710c9c19b31e0e48e4bcdf31cefe8;p=linux-2.6-omap-h63xx.git diff --git a/ipc/shm.c b/ipc/shm.c index b58c651d31a..80989685190 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -13,6 +13,8 @@ * Shared /dev/zero support, Kanoj Sarcar * Move the mm functionality over to mm/shmem.c, Christoph Rohland * + * support for audit of ipc object properties and permission changes + * Dustin Kirkland */ #include @@ -27,15 +29,15 @@ #include #include #include +#include #include #include +#include #include #include "util.h" -#define shm_flags shm_perm.mode - static struct file_operations shm_file_operations; static struct vm_operations_struct shm_vm_ops; @@ -91,8 +93,8 @@ static inline int shm_addid(struct shmid_kernel *shp) static inline void shm_inc (int id) { struct shmid_kernel *shp; - if(!(shp = shm_lock(id))) - BUG(); + shp = shm_lock(id); + BUG_ON(!shp); shp->shm_atim = get_seconds(); shp->shm_lprid = current->tgid; shp->shm_nattch++; @@ -110,7 +112,7 @@ static void shm_open (struct vm_area_struct *shmd) * * @shp: struct to free * - * It has to be called with shp and shm_ids.sem locked, + * It has to be called with shp and shm_ids.mutex locked, * but returns with shp unlocked and freed. */ static void shm_destroy (struct shmid_kernel *shp) @@ -140,31 +142,41 @@ static void shm_close (struct vm_area_struct *shmd) int id = file->f_dentry->d_inode->i_ino; struct shmid_kernel *shp; - down (&shm_ids.sem); + mutex_lock(&shm_ids.mutex); /* remove from the list of attaches of the shm segment */ - if(!(shp = shm_lock(id))) - BUG(); + shp = shm_lock(id); + BUG_ON(!shp); shp->shm_lprid = current->tgid; shp->shm_dtim = get_seconds(); shp->shm_nattch--; if(shp->shm_nattch == 0 && - shp->shm_flags & SHM_DEST) + shp->shm_perm.mode & SHM_DEST) shm_destroy (shp); else shm_unlock(shp); - up (&shm_ids.sem); + mutex_unlock(&shm_ids.mutex); } static int shm_mmap(struct file * file, struct vm_area_struct * vma) { - file_accessed(file); - vma->vm_ops = &shm_vm_ops; - shm_inc(file->f_dentry->d_inode->i_ino); - return 0; + int ret; + + ret = shmem_mmap(file, vma); + if (ret == 0) { + vma->vm_ops = &shm_vm_ops; + if (!(vma->vm_flags & VM_WRITE)) + vma->vm_flags &= ~VM_MAYWRITE; + shm_inc(file->f_dentry->d_inode->i_ino); + } + + return ret; } static struct file_operations shm_file_operations = { - .mmap = shm_mmap + .mmap = shm_mmap, +#ifndef CONFIG_MMU + .get_unmapped_area = shmem_get_unmapped_area, +#endif }; static struct vm_operations_struct shm_vm_ops = { @@ -197,7 +209,7 @@ static int newseg (key_t key, int shmflg, size_t size) return -ENOMEM; shp->shm_perm.key = key; - shp->shm_flags = (shmflg & S_IRWXUGO); + shp->shm_perm.mode = (shmflg & S_IRWXUGO); shp->mlock_user = NULL; shp->shm_perm.security = NULL; @@ -212,8 +224,16 @@ static int newseg (key_t key, int shmflg, size_t size) file = hugetlb_zero_setup(size); shp->mlock_user = current->user; } else { + int acctflag = VM_ACCOUNT; + /* + * Do not allow no accounting for OVERCOMMIT_NEVER, even + * if it's asked for. + */ + if ((shmflg & SHM_NORESERVE) && + sysctl_overcommit_memory != OVERCOMMIT_NEVER) + acctflag = 0; sprintf (name, "SYSV%08x", key); - file = shmem_file_setup(name, size, VM_ACCOUNT); + file = shmem_file_setup(name, size, acctflag); } error = PTR_ERR(file); if (IS_ERR(file)) @@ -255,7 +275,7 @@ asmlinkage long sys_shmget (key_t key, size_t size, int shmflg) struct shmid_kernel *shp; int err, id = 0; - down(&shm_ids.sem); + mutex_lock(&shm_ids.mutex); if (key == IPC_PRIVATE) { err = newseg(key, shmflg, size); } else if ((id = ipc_findkey(&shm_ids, key)) == -1) { @@ -267,8 +287,7 @@ asmlinkage long sys_shmget (key_t key, size_t size, int shmflg) err = -EEXIST; } else { shp = shm_lock(id); - if(shp==NULL) - BUG(); + BUG_ON(shp==NULL); if (shp->shm_segsz < size) err = -EINVAL; else if (ipcperms(&shp->shm_perm, shmflg)) @@ -281,7 +300,7 @@ asmlinkage long sys_shmget (key_t key, size_t size, int shmflg) } shm_unlock(shp); } - up(&shm_ids.sem); + mutex_unlock(&shm_ids.mutex); return err; } @@ -329,7 +348,7 @@ static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void __ out->uid = tbuf.shm_perm.uid; out->gid = tbuf.shm_perm.gid; - out->mode = tbuf.shm_flags; + out->mode = tbuf.shm_perm.mode; return 0; } @@ -342,7 +361,7 @@ static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void __ out->uid = tbuf_old.shm_perm.uid; out->gid = tbuf_old.shm_perm.gid; - out->mode = tbuf_old.shm_flags; + out->mode = tbuf_old.shm_perm.mode; return 0; } @@ -452,14 +471,14 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) return err; memset(&shm_info,0,sizeof(shm_info)); - down(&shm_ids.sem); + mutex_lock(&shm_ids.mutex); shm_info.used_ids = shm_ids.in_use; shm_get_stat (&shm_info.shm_rss, &shm_info.shm_swp); shm_info.shm_tot = shm_tot; shm_info.swap_attempts = 0; shm_info.swap_successes = 0; err = shm_ids.max_id; - up(&shm_ids.sem); + mutex_unlock(&shm_ids.mutex); if(copy_to_user (buf, &shm_info, sizeof(shm_info))) { err = -EFAULT; goto out; @@ -525,6 +544,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) if(err) goto out_unlock; + err = audit_ipc_obj(&(shp->shm_perm)); + if (err) + goto out_unlock; + if (!capable(CAP_IPC_LOCK)) { err = -EPERM; if (current->euid != shp->shm_perm.uid && @@ -544,13 +567,13 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) if (!is_file_hugepages(shp->shm_file)) { err = shmem_lock(shp->shm_file, 1, user); if (!err) { - shp->shm_flags |= SHM_LOCKED; + shp->shm_perm.mode |= SHM_LOCKED; shp->mlock_user = user; } } } else if (!is_file_hugepages(shp->shm_file)) { shmem_lock(shp->shm_file, 0, shp->mlock_user); - shp->shm_flags &= ~SHM_LOCKED; + shp->shm_perm.mode &= ~SHM_LOCKED; shp->mlock_user = NULL; } shm_unlock(shp); @@ -568,7 +591,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) * Instead we set a destroyed flag, and then blow * the name away when the usage hits zero. */ - down(&shm_ids.sem); + mutex_lock(&shm_ids.mutex); shp = shm_lock(shmid); err = -EINVAL; if (shp == NULL) @@ -577,6 +600,10 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) if(err) goto out_unlock_up; + err = audit_ipc_obj(&(shp->shm_perm)); + if (err) + goto out_unlock_up; + if (current->euid != shp->shm_perm.uid && current->euid != shp->shm_perm.cuid && !capable(CAP_SYS_ADMIN)) { @@ -589,13 +616,13 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) goto out_unlock_up; if (shp->shm_nattch){ - shp->shm_flags |= SHM_DEST; + shp->shm_perm.mode |= SHM_DEST; /* Do not find it any more */ shp->shm_perm.key = IPC_PRIVATE; shm_unlock(shp); } else shm_destroy (shp); - up(&shm_ids.sem); + mutex_unlock(&shm_ids.mutex); goto out; } @@ -605,9 +632,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) err = -EFAULT; goto out; } - if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode))) - return err; - down(&shm_ids.sem); + mutex_lock(&shm_ids.mutex); shp = shm_lock(shmid); err=-EINVAL; if(shp==NULL) @@ -615,6 +640,12 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) err = shm_checkid(shp,shmid); if(err) goto out_unlock_up; + err = audit_ipc_obj(&(shp->shm_perm)); + if (err) + goto out_unlock_up; + err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode, &(shp->shm_perm)); + if (err) + goto out_unlock_up; err=-EPERM; if (current->euid != shp->shm_perm.uid && current->euid != shp->shm_perm.cuid && @@ -628,7 +659,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) shp->shm_perm.uid = setbuf.uid; shp->shm_perm.gid = setbuf.gid; - shp->shm_flags = (shp->shm_flags & ~S_IRWXUGO) + shp->shm_perm.mode = (shp->shm_perm.mode & ~S_IRWXUGO) | (setbuf.mode & S_IRWXUGO); shp->shm_ctim = get_seconds(); break; @@ -643,7 +674,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) out_unlock_up: shm_unlock(shp); out_up: - up(&shm_ids.sem); + mutex_unlock(&shm_ids.mutex); goto out; out_unlock: shm_unlock(shp); @@ -756,16 +787,16 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) invalid: up_write(¤t->mm->mmap_sem); - down (&shm_ids.sem); - if(!(shp = shm_lock(shmid))) - BUG(); + mutex_lock(&shm_ids.mutex); + shp = shm_lock(shmid); + BUG_ON(!shp); shp->shm_nattch--; if(shp->shm_nattch == 0 && - shp->shm_flags & SHM_DEST) + shp->shm_perm.mode & SHM_DEST) shm_destroy (shp); else shm_unlock(shp); - up (&shm_ids.sem); + mutex_unlock(&shm_ids.mutex); *raddr = (unsigned long) user_addr; err = 0; @@ -799,6 +830,9 @@ asmlinkage long sys_shmdt(char __user *shmaddr) loff_t size = 0; int retval = -EINVAL; + if (addr & ~PAGE_MASK) + return retval; + down_write(&mm->mmap_sem); /* @@ -855,6 +889,7 @@ asmlinkage long sys_shmdt(char __user *shmaddr) * could possibly have landed at. Also cast things to loff_t to * prevent overflows and make comparisions vs. equal-width types. */ + size = PAGE_ALIGN(size); while (vma && (loff_t)(vma->vm_end - addr) <= size) { next = vma->vm_next; @@ -886,7 +921,7 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it) return seq_printf(s, format, shp->shm_perm.key, shp->id, - shp->shm_flags, + shp->shm_perm.mode, shp->shm_segsz, shp->shm_cprid, shp->shm_lprid,