From: Chris Wright Couple more nits. The default lockable amount is one page now (first patch is was 0). Why don't we keep it as 0, with the CAP_IPC_LOCK overrides in place? That way nothing is changed from user perspective, and the rest of the policy can be done by userspace as it should. This patch breaks in one scenario. When ulimit == 0, process has CAP_IPC_LOCK, and does SHM_LOCK. The subsequent unlock or destroy will corrupt the locked_shm count. It's also inconsistent in handling user_can_mlock/CAP_IPC_LOCK interaction betwen shm_lock and shm_hugetlb. SHM_HUGETLB can now only be done by the shm_group or CAP_IPC_LOCK. Not any can_do_mlock() user. Double check of can_do_mlock isn't needed in SHM_LOCK path. Interface names user_can_mlock and user_substract_mlock could be better. Incremental update below. Ran some simple sanity tests on this plus my patch below and didn't find any problems. * Make default RLIM_MEMLOCK limit 0. * Move CAP_IPC_LOCK check into user_can_mlock to be consistent and fix but with ulimit == 0 && CAP_IPC_LOCK with SHM_LOCK. * Allow can_do_mlock() user to try SHM_HUGETLB setup. * Remove unecessary extra can_do_mlock() test in shmem_lock(). * Rename user_can_mlock to user_shm_lock and user_subtract_mlock to user_shm_unlock. * Use user instead of current->user to fit in 80 cols on SHM_LOCK. Signed-off-by: Andrew Morton --- 25-akpm/fs/hugetlbfs/inode.c | 11 ++++++----- 25-akpm/include/asm-alpha/resource.h | 2 +- 25-akpm/include/asm-arm/resource.h | 2 +- 25-akpm/include/asm-arm26/resource.h | 2 +- 25-akpm/include/asm-cris/resource.h | 2 +- 25-akpm/include/asm-h8300/resource.h | 2 +- 25-akpm/include/asm-i386/resource.h | 2 +- 25-akpm/include/asm-ia64/resource.h | 2 +- 25-akpm/include/asm-m68k/resource.h | 2 +- 25-akpm/include/asm-parisc/resource.h | 2 +- 25-akpm/include/asm-ppc/resource.h | 2 +- 25-akpm/include/asm-ppc64/resource.h | 2 +- 25-akpm/include/asm-s390/resource.h | 2 +- 25-akpm/include/asm-sh/resource.h | 2 +- 25-akpm/include/asm-sparc/resource.h | 2 +- 25-akpm/include/asm-sparc64/resource.h | 2 +- 25-akpm/include/asm-v850/resource.h | 2 +- 25-akpm/include/asm-x86_64/resource.h | 2 +- 25-akpm/include/linux/mm.h | 4 ++-- 25-akpm/ipc/shm.c | 4 ++-- 25-akpm/mm/mlock.c | 20 ++++++++++---------- 25-akpm/mm/shmem.c | 7 ++----- 22 files changed, 39 insertions(+), 41 deletions(-) diff -puN fs/hugetlbfs/inode.c~mlock-as-user-fixes fs/hugetlbfs/inode.c --- 25/fs/hugetlbfs/inode.c~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/fs/hugetlbfs/inode.c Wed Aug 4 16:17:36 2004 @@ -734,7 +734,8 @@ static unsigned long hugetlbfs_counter(v static int can_do_hugetlb_shm(void) { return likely(capable(CAP_IPC_LOCK) || - in_group_p(sysctl_hugetlb_shm_group)); + in_group_p(sysctl_hugetlb_shm_group) || + can_do_mlock()); } struct file *hugetlb_zero_setup(size_t size) @@ -752,7 +753,7 @@ struct file *hugetlb_zero_setup(size_t s if (!is_hugepage_mem_enough(size)) return ERR_PTR(-ENOMEM); - if (!user_can_mlock(size, current->user)) + if (!user_shm_lock(size, current->user)) return ERR_PTR(-ENOMEM); root = hugetlbfs_vfsmount->mnt_root; @@ -762,7 +763,7 @@ struct file *hugetlb_zero_setup(size_t s quick_string.hash = 0; dentry = d_alloc(root, &quick_string); if (!dentry) - goto out_subtract_mlock; + goto out_shm_unlock; error = -ENFILE; file = get_empty_filp(); @@ -789,8 +790,8 @@ out_file: put_filp(file); out_dentry: dput(dentry); -out_subtract_mlock: - user_subtract_mlock(size, current->user); +out_shm_unlock: + user_shm_unlock(size, current->user); return ERR_PTR(error); } diff -puN include/asm-alpha/resource.h~mlock-as-user-fixes include/asm-alpha/resource.h --- 25/include/asm-alpha/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-alpha/resource.h Wed Aug 4 16:17:22 2004 @@ -41,7 +41,7 @@ {INR_OPEN, INR_OPEN}, /* RLIMIT_NOFILE */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_AS */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_NPROC */ \ - {PAGE_SIZE, PAGE_SIZE}, /* RLIMIT_MEMLOCK */ \ + {0, 0 }, /* RLIMIT_MEMLOCK */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_LOCKS */ \ {MAX_SIGPENDING, MAX_SIGPENDING}, /* RLIMIT_SIGPENDING */ \ {MQ_BYTES_MAX, MQ_BYTES_MAX}, /* RLIMIT_MSGQUEUE */ \ diff -puN include/asm-arm26/resource.h~mlock-as-user-fixes include/asm-arm26/resource.h --- 25/include/asm-arm26/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-arm26/resource.h Wed Aug 4 16:17:22 2004 @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { PAGE_SIZE, PAGE_SIZE }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING}, \ diff -puN include/asm-arm/resource.h~mlock-as-user-fixes include/asm-arm/resource.h --- 25/include/asm-arm/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-arm/resource.h Wed Aug 4 16:17:22 2004 @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { PAGE_SIZE, PAGE_SIZE }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING}, \ diff -puN include/asm-cris/resource.h~mlock-as-user-fixes include/asm-cris/resource.h --- 25/include/asm-cris/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-cris/resource.h Wed Aug 4 16:17:22 2004 @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { PAGE_SIZE, PAGE_SIZE }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff -puN include/asm-h8300/resource.h~mlock-as-user-fixes include/asm-h8300/resource.h --- 25/include/asm-h8300/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-h8300/resource.h Wed Aug 4 16:17:22 2004 @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { PAGE_SIZE, PAGE_SIZE }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff -puN include/asm-i386/resource.h~mlock-as-user-fixes include/asm-i386/resource.h --- 25/include/asm-i386/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-i386/resource.h Wed Aug 4 16:17:22 2004 @@ -40,7 +40,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { PAGE_SIZE, PAGE_SIZE }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff -puN include/asm-ia64/resource.h~mlock-as-user-fixes include/asm-ia64/resource.h --- 25/include/asm-ia64/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-ia64/resource.h Wed Aug 4 16:17:22 2004 @@ -46,7 +46,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { PAGE_SIZE, PAGE_SIZE }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff -puN include/asm-m68k/resource.h~mlock-as-user-fixes include/asm-m68k/resource.h --- 25/include/asm-m68k/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-m68k/resource.h Wed Aug 4 16:17:22 2004 @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { PAGE_SIZE, PAGE_SIZE }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff -puN include/asm-parisc/resource.h~mlock-as-user-fixes include/asm-parisc/resource.h --- 25/include/asm-parisc/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-parisc/resource.h Wed Aug 4 16:17:22 2004 @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { PAGE_SIZE, PAGE_SIZE }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff -puN include/asm-ppc64/resource.h~mlock-as-user-fixes include/asm-ppc64/resource.h --- 25/include/asm-ppc64/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-ppc64/resource.h Wed Aug 4 16:17:22 2004 @@ -45,7 +45,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { PAGE_SIZE, PAGE_SIZE }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff -puN include/asm-ppc/resource.h~mlock-as-user-fixes include/asm-ppc/resource.h --- 25/include/asm-ppc/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-ppc/resource.h Wed Aug 4 16:17:22 2004 @@ -36,7 +36,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { PAGE_SIZE, PAGE_SIZE }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff -puN include/asm-s390/resource.h~mlock-as-user-fixes include/asm-s390/resource.h --- 25/include/asm-s390/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-s390/resource.h Wed Aug 4 16:17:22 2004 @@ -47,7 +47,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { PAGE_SIZE, PAGE_SIZE }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff -puN include/asm-sh/resource.h~mlock-as-user-fixes include/asm-sh/resource.h --- 25/include/asm-sh/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-sh/resource.h Wed Aug 4 16:17:22 2004 @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { PAGE_SIZE, PAGE_SIZE }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff -puN include/asm-sparc64/resource.h~mlock-as-user-fixes include/asm-sparc64/resource.h --- 25/include/asm-sparc64/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-sparc64/resource.h Wed Aug 4 16:17:22 2004 @@ -43,7 +43,7 @@ { 0, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {INR_OPEN, INR_OPEN}, {0, 0}, \ - {PAGE_SIZE, PAGE_SIZE }, \ + {0, 0 }, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {MAX_SIGPENDING, MAX_SIGPENDING}, \ diff -puN include/asm-sparc/resource.h~mlock-as-user-fixes include/asm-sparc/resource.h --- 25/include/asm-sparc/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-sparc/resource.h Wed Aug 4 16:17:22 2004 @@ -44,7 +44,7 @@ { 0, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {INR_OPEN, INR_OPEN}, {0, 0}, \ - {PAGE_SIZE, PAGE_SIZE}, \ + {0, 0}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {MAX_SIGPENDING, MAX_SIGPENDING}, \ diff -puN include/asm-v850/resource.h~mlock-as-user-fixes include/asm-v850/resource.h --- 25/include/asm-v850/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-v850/resource.h Wed Aug 4 16:17:22 2004 @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { PAGE_SIZE, PAGE_SIZE }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff -puN include/asm-x86_64/resource.h~mlock-as-user-fixes include/asm-x86_64/resource.h --- 25/include/asm-x86_64/resource.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/asm-x86_64/resource.h Wed Aug 4 16:17:22 2004 @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { PAGE_SIZE , PAGE_SIZE }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff -puN include/linux/mm.h~mlock-as-user-fixes include/linux/mm.h --- 25/include/linux/mm.h~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/include/linux/mm.h Wed Aug 4 16:17:22 2004 @@ -509,8 +509,8 @@ static inline int can_do_mlock(void) return 1; return 0; } -extern int user_can_mlock(size_t, struct user_struct *user); -extern void user_subtract_mlock(size_t, struct user_struct *user); +extern int user_shm_lock(size_t, struct user_struct *); +extern void user_shm_unlock(size_t, struct user_struct *); /* * Parameter block passed down to zap_pte_range in exceptional cases. diff -puN ipc/shm.c~mlock-as-user-fixes ipc/shm.c --- 25/ipc/shm.c~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/ipc/shm.c Wed Aug 4 16:17:22 2004 @@ -116,7 +116,7 @@ static void shm_destroy (struct shmid_ke if (!is_file_hugepages(shp->shm_file)) shmem_lock(shp->shm_file, 0, shp->mlock_user); else - user_subtract_mlock(shp->shm_file->f_dentry->d_inode->i_size, + user_shm_unlock(shp->shm_file->f_dentry->d_inode->i_size, shp->mlock_user); fput (shp->shm_file); security_shm_free(shp); @@ -531,7 +531,7 @@ asmlinkage long sys_shmctl (int shmid, i if(cmd==SHM_LOCK) { struct user_struct * user = current->user; if (!is_file_hugepages(shp->shm_file)) { - err = shmem_lock(shp->shm_file, 1, current->user); + err = shmem_lock(shp->shm_file, 1, user); if (!err) { shp->shm_flags |= SHM_LOCKED; shp->mlock_user = user; diff -puN mm/mlock.c~mlock-as-user-fixes mm/mlock.c --- 25/mm/mlock.c~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/mm/mlock.c Wed Aug 4 16:17:22 2004 @@ -195,34 +195,34 @@ asmlinkage long sys_munlockall(void) } /* - * Objects with different lifetime than processes (mlocked shm segments - * and hugetlb files) get accounted against the user_struct instead. + * Objects with different lifetime than processes (SHM_LOCK and SHM_HUGETLB + * shm segments) get accounted against the user_struct instead. */ -static spinlock_t mlock_user_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t shmlock_user_lock = SPIN_LOCK_UNLOCKED; -int user_can_mlock(size_t size, struct user_struct *user) +int user_shm_lock(size_t size, struct user_struct *user) { unsigned long lock_limit, locked; int allowed = 0; - spin_lock(&mlock_user_lock); + spin_lock(&shmlock_user_lock); locked = size >> PAGE_SHIFT; lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; lock_limit >>= PAGE_SHIFT; - if (locked + user->locked_shm > lock_limit) + if (locked + user->locked_shm > lock_limit && !capable(CAP_IPC_LOCK)) goto out; get_uid(user); user->locked_shm += locked; allowed = 1; out: - spin_unlock(&mlock_user_lock); + spin_unlock(&shmlock_user_lock); return allowed; } -void user_subtract_mlock(size_t size, struct user_struct *user) +void user_shm_unlock(size_t size, struct user_struct *user) { - spin_lock(&mlock_user_lock); + spin_lock(&shmlock_user_lock); user->locked_shm -= (size >> PAGE_SHIFT); - spin_unlock(&mlock_user_lock); + spin_unlock(&shmlock_user_lock); free_uid(user); } diff -puN mm/shmem.c~mlock-as-user-fixes mm/shmem.c --- 25/mm/shmem.c~mlock-as-user-fixes Wed Aug 4 16:17:22 2004 +++ 25-akpm/mm/shmem.c Wed Aug 4 16:17:22 2004 @@ -1157,17 +1157,14 @@ int shmem_lock(struct file *file, int lo struct shmem_inode_info *info = SHMEM_I(inode); int retval = -ENOMEM; - if (lock && !can_do_mlock()) - return -EPERM; - spin_lock(&info->lock); if (lock && !(info->flags & VM_LOCKED)) { - if (!user_can_mlock(inode->i_size, user) && !capable(CAP_IPC_LOCK)) + if (!user_shm_lock(inode->i_size, user)) goto out_nomem; info->flags |= VM_LOCKED; } if (!lock && (info->flags & VM_LOCKED) && user) { - user_subtract_mlock(inode->i_size, user); + user_shm_unlock(inode->i_size, user); info->flags &= ~VM_LOCKED; } retval = 0; _