Use the recently introduced PCuABI reservation interfaces to verify the address range for shmat syscall.
Signed-off-by: Amit Daniel Kachhap amitdaniel.kachhap@arm.com --- include/linux/shm.h | 4 ++-- ipc/shm.c | 24 ++++++++++++++++-------- 2 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/include/linux/shm.h b/include/linux/shm.h index d8e69aed3d32..bf5b2e5cbd0c 100644 --- a/include/linux/shm.h +++ b/include/linux/shm.h @@ -14,7 +14,7 @@ struct sysv_shm { struct list_head shm_clist; };
-long do_shmat(int shmid, char __user *shmaddr, int shmflg, unsigned long *addr, +long do_shmat(int shmid, char __user *shmaddr, int shmflg, user_uintptr_t *user_ptr, unsigned long shmlba); bool is_file_shm_hugepages(struct file *file); void exit_shm(struct task_struct *task); @@ -25,7 +25,7 @@ struct sysv_shm { };
static inline long do_shmat(int shmid, char __user *shmaddr, - int shmflg, unsigned long *addr, + int shmflg, user_uintptr_t *user_ptr, unsigned long shmlba) { return -ENOSYS; diff --git a/ipc/shm.c b/ipc/shm.c index 7bb7c4bbc383..d028a8ce8b39 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -44,6 +44,7 @@ #include <linux/mount.h> #include <linux/ipc_namespace.h> #include <linux/rhashtable.h> +#include <linux/cap_addr_mgmt.h>
#include <linux/uaccess.h>
@@ -1519,14 +1520,13 @@ COMPAT_SYSCALL_DEFINE3(old_shmctl, int, shmid, int, cmd, void __user *, uptr) * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists. * * NOTE! Despite the name, this is NOT a direct system call entrypoint. The - * "raddr" thing points to kernel space, and there has to be a wrapper around + * "ruser_ptr" thing points to kernel space, and there has to be a wrapper around * this. */ long do_shmat(int shmid, char __user *shmaddr, int shmflg, - ulong *raddr, unsigned long shmlba) + user_uintptr_t *ruser_ptr, unsigned long shmlba) { struct shmid_kernel *shp; - /* TODO [PCuABI] - capability checks for address space management */ unsigned long addr = user_ptr_addr(shmaddr); unsigned long size; struct file *file, *base; @@ -1666,11 +1666,20 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, goto invalid; }
+ err = check_pcuabi_params((user_uintptr_t)shmaddr, size, + (flags & MAP_FIXED) ? true : false, true); + if (err) + goto invalid; + addr = do_mmap(file, addr, size, prot, flags, 0, 0, &populate, NULL); - *raddr = addr; err = 0; if (IS_ERR_VALUE(addr)) err = (long)addr; + else if (!user_ptr_is_valid(shmaddr)) + *ruser_ptr = make_user_ptr_owning(addr, size, + user_ptr_owning_perms_from_prot(prot, false)); + else + *ruser_ptr = (user_uintptr_t)shmaddr; invalid: mmap_write_unlock(current->mm); if (populate) @@ -1699,15 +1708,14 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg,
SYSCALL_DEFINE3(__retptr__(shmat), int, shmid, char __user *, shmaddr, int, shmflg) { - unsigned long ret; + user_uintptr_t ret; long err;
err = do_shmat(shmid, shmaddr, shmflg, &ret, SHMLBA); if (err) return err; force_successful_syscall_return(); - /* TODO [PCuABI] - derive proper capability */ - return (user_uintptr_t)uaddr_to_user_ptr_safe(ret); + return ret; }
#ifdef CONFIG_COMPAT @@ -1718,7 +1726,7 @@ SYSCALL_DEFINE3(__retptr__(shmat), int, shmid, char __user *, shmaddr, int, shmf
COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg) { - unsigned long ret; + user_uintptr_t ret; long err;
err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA);