From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.8 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE, SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 07C3BC4741F for ; Fri, 30 Oct 2020 15:49:46 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 66EB52151B for ; Fri, 30 Oct 2020 15:49:45 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=kernel.org header.i=@kernel.org header.b="tNj45Aqw" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 66EB52151B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=kernel.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 2E0A06B0082; Fri, 30 Oct 2020 11:49:44 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 265786B0083; Fri, 30 Oct 2020 11:49:44 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 0E2326B0085; Fri, 30 Oct 2020 11:49:44 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0006.hostedemail.com [216.40.44.6]) by kanga.kvack.org (Postfix) with ESMTP id C7D966B0082 for ; Fri, 30 Oct 2020 11:49:43 -0400 (EDT) Received: from smtpin11.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay02.hostedemail.com (Postfix) with ESMTP id 428673628 for ; Fri, 30 Oct 2020 15:49:43 +0000 (UTC) X-FDA: 77429027046.11.voice09_631221127297 Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin11.hostedemail.com (Postfix) with ESMTP id 21259180F8B80 for ; Fri, 30 Oct 2020 15:49:43 +0000 (UTC) X-HE-Tag: voice09_631221127297 X-Filterd-Recvd-Size: 10929 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by imf01.hostedemail.com (Postfix) with ESMTP for ; Fri, 30 Oct 2020 15:49:42 +0000 (UTC) Received: from localhost.localdomain (HSI-KBW-46-223-126-90.hsi.kabel-badenwuerttemberg.de [46.223.126.90]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id B0A3320A8B; Fri, 30 Oct 2020 15:49:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1604072981; bh=Nohcs14NXVmzDPgy7u84GYyJC54hRaPFadvgsNBjXrI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tNj45AqwPZGaVSNZpP/1A40HzTQLDVBwf2c34+4NvqbGTUhoh/FO1BRqJrOzNVruE LD4BOIie9hoNn4iQjlQcwnREWhJReYlSVouLAnKm8M47AUNXUKe7p+0J5aXJlKS3Jx fB308cFDSQauT/MWaRTsr+6FJpvDCoAqru2H5sJE= From: Arnd Bergmann To: Russell King , Christoph Hellwig Cc: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-arch@vger.kernel.org, linux-mm@kvack.org, viro@zeniv.linux.org.uk, linus.walleij@linaro.org, arnd@arndb.de Subject: [PATCH 6/9] ARM: oabi-compat: rework sys_semtimedop emulation Date: Fri, 30 Oct 2020 16:49:16 +0100 Message-Id: <20201030154919.1246645-6-arnd@kernel.org> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20201030154919.1246645-1-arnd@kernel.org> References: <20201030154519.1245983-1-arnd@kernel.org> <20201030154919.1246645-1-arnd@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: From: Arnd Bergmann sys_oabi_semtimedop() is one of the last users of set_fs() on Arm. To remove this one, expose the internal code of the actual implementation that operates on a kernel pointer and call it directly after copying. There should be no measurable impact on the normal execution of this function, and it makes the overly long function a little shorter, which may help readability. While reworking the oabi version, make it behave a little more like the native one, using kvmalloc_array() and restructure the code flow in a similar way. The naming of __do_semtimedop() is not very good, I hope someone can come up with a better name. One regression was spotted by kernel test robot and fixed before the first mailing list submission. Signed-off-by: Arnd Bergmann --- arch/arm/kernel/sys_oabi-compat.c | 38 ++++++++------ include/linux/syscalls.h | 3 ++ ipc/sem.c | 84 +++++++++++++++++++------------ 3 files changed, 77 insertions(+), 48 deletions(-) diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi= -compat.c index f9d8e5be6ba0..c3e63b73b6ae 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #include =20 @@ -294,46 +295,51 @@ struct oabi_sembuf { unsigned short __pad; }; =20 +#define sc_semopm sem_ctls[2] + asmlinkage long sys_oabi_semtimedop(int semid, struct oabi_sembuf __user *tsops, unsigned nsops, const struct old_timespec32 __user *timeout) { + struct ipc_namespace *ns; struct sembuf *sops; - struct old_timespec32 local_timeout; long err; int i; =20 + ns =3D current->nsproxy->ipc_ns; + if (nsops > ns->sc_semopm) + return -E2BIG; if (nsops < 1 || nsops > SEMOPM) return -EINVAL; - if (!access_ok(tsops, sizeof(*tsops) * nsops)) - return -EFAULT; - sops =3D kmalloc_array(nsops, sizeof(*sops), GFP_KERNEL); + sops =3D kvmalloc_array(nsops, sizeof(*sops), GFP_KERNEL); if (!sops) return -ENOMEM; err =3D 0; for (i =3D 0; i < nsops; i++) { struct oabi_sembuf osb; - err |=3D __copy_from_user(&osb, tsops, sizeof(osb)); + err |=3D copy_from_user(&osb, tsops, sizeof(osb)); sops[i].sem_num =3D osb.sem_num; sops[i].sem_op =3D osb.sem_op; sops[i].sem_flg =3D osb.sem_flg; tsops++; } - if (timeout) { - /* copy this as well before changing domain protection */ - err |=3D copy_from_user(&local_timeout, timeout, sizeof(*timeout)); - timeout =3D &local_timeout; - } if (err) { err =3D -EFAULT; - } else { - mm_segment_t fs =3D get_fs(); - set_fs(KERNEL_DS); - err =3D sys_semtimedop_time32(semid, sops, nsops, timeout); - set_fs(fs); + goto out; + } + + if (timeout) { + struct timespec64 ts; + err =3D get_old_timespec32(&ts, timeout); + if (err) + goto out; + err =3D __do_semtimedop(semid, sops, nsops, &ts, ns); + goto out; } - kfree(sops); + err =3D __do_semtimedop(semid, sops, nsops, NULL, ns); +out: + kvfree(sops); return err; } =20 diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 37bea07c12f2..fc7340fa4702 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -1342,6 +1342,9 @@ long ksys_old_shmctl(int shmid, int cmd, struct shm= id_ds __user *buf); long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems, unsigned int nsops, const struct old_timespec32 __user *timeout); +long __do_semtimedop(int semid, struct sembuf *tsems, unsigned int nsops= , + const struct timespec64 *timeout, + struct ipc_namespace *ns); =20 int __sys_getsockopt(int fd, int level, int optname, char __user *optval= , int __user *optlen); diff --git a/ipc/sem.c b/ipc/sem.c index f6c30a85dadf..c7725031c2ba 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -1978,46 +1978,34 @@ static struct sem_undo *find_alloc_undo(struct ip= c_namespace *ns, int semid) return un; } =20 -static long do_semtimedop(int semid, struct sembuf __user *tsops, - unsigned nsops, const struct timespec64 *timeout) +long __do_semtimedop(int semid, struct sembuf *sops, + unsigned nsops, const struct timespec64 *timeout, + struct ipc_namespace *ns) { int error =3D -EINVAL; struct sem_array *sma; - struct sembuf fast_sops[SEMOPM_FAST]; - struct sembuf *sops =3D fast_sops, *sop; + struct sembuf *sop; struct sem_undo *un; int max, locknum; bool undos =3D false, alter =3D false, dupsop =3D false; struct sem_queue queue; unsigned long dup =3D 0, jiffies_left =3D 0; - struct ipc_namespace *ns; - - ns =3D current->nsproxy->ipc_ns; =20 if (nsops < 1 || semid < 0) return -EINVAL; if (nsops > ns->sc_semopm) return -E2BIG; - if (nsops > SEMOPM_FAST) { - sops =3D kvmalloc_array(nsops, sizeof(*sops), GFP_KERNEL); - if (sops =3D=3D NULL) - return -ENOMEM; - } - - if (copy_from_user(sops, tsops, nsops * sizeof(*tsops))) { - error =3D -EFAULT; - goto out_free; - } =20 if (timeout) { if (timeout->tv_sec < 0 || timeout->tv_nsec < 0 || timeout->tv_nsec >=3D 1000000000L) { error =3D -EINVAL; - goto out_free; + goto out; } jiffies_left =3D timespec64_to_jiffies(timeout); } =20 + max =3D 0; for (sop =3D sops; sop < sops + nsops; sop++) { unsigned long mask =3D 1ULL << ((sop->sem_num) % BITS_PER_LONG); @@ -2046,7 +2034,7 @@ static long do_semtimedop(int semid, struct sembuf = __user *tsops, un =3D find_alloc_undo(ns, semid); if (IS_ERR(un)) { error =3D PTR_ERR(un); - goto out_free; + goto out; } } else { un =3D NULL; @@ -2057,25 +2045,25 @@ static long do_semtimedop(int semid, struct sembu= f __user *tsops, if (IS_ERR(sma)) { rcu_read_unlock(); error =3D PTR_ERR(sma); - goto out_free; + goto out; } =20 error =3D -EFBIG; if (max >=3D sma->sem_nsems) { rcu_read_unlock(); - goto out_free; + goto out; } =20 error =3D -EACCES; if (ipcperms(ns, &sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) { rcu_read_unlock(); - goto out_free; + goto out; } =20 error =3D security_sem_semop(&sma->sem_perm, sops, nsops, alter); if (error) { rcu_read_unlock(); - goto out_free; + goto out; } =20 error =3D -EIDRM; @@ -2089,7 +2077,7 @@ static long do_semtimedop(int semid, struct sembuf = __user *tsops, * entangled here and why it's RMID race safe on comments at sem_lock() */ if (!ipc_valid_object(&sma->sem_perm)) - goto out_unlock_free; + goto out_unlock; /* * semid identifiers are not unique - find_alloc_undo may have * allocated an undo structure, it was invalidated by an RMID @@ -2098,7 +2086,7 @@ static long do_semtimedop(int semid, struct sembuf = __user *tsops, * "un" itself is guaranteed by rcu. */ if (un && un->semid =3D=3D -1) - goto out_unlock_free; + goto out_unlock; =20 queue.sops =3D sops; queue.nsops =3D nsops; @@ -2124,10 +2112,10 @@ static long do_semtimedop(int semid, struct sembu= f __user *tsops, rcu_read_unlock(); wake_up_q(&wake_q); =20 - goto out_free; + goto out; } if (error < 0) /* non-blocking error path */ - goto out_unlock_free; + goto out_unlock; =20 /* * We need to sleep on this operation, so we put the current @@ -2192,14 +2180,14 @@ static long do_semtimedop(int semid, struct sembu= f __user *tsops, if (error !=3D -EINTR) { /* see SEM_BARRIER_2 for purpose/pairing */ smp_acquire__after_ctrl_dep(); - goto out_free; + goto out; } =20 rcu_read_lock(); locknum =3D sem_lock(sma, sops, nsops); =20 if (!ipc_valid_object(&sma->sem_perm)) - goto out_unlock_free; + goto out_unlock; =20 /* * No necessity for any barrier: We are protect by sem_lock() @@ -2211,7 +2199,7 @@ static long do_semtimedop(int semid, struct sembuf = __user *tsops, * Leave without unlink_queue(), but with sem_unlock(). */ if (error !=3D -EINTR) - goto out_unlock_free; + goto out_unlock; =20 /* * If an interrupt occurred we have to clean up the queue. @@ -2222,13 +2210,45 @@ static long do_semtimedop(int semid, struct sembu= f __user *tsops, =20 unlink_queue(sma, &queue); =20 -out_unlock_free: +out_unlock: sem_unlock(sma, locknum); rcu_read_unlock(); +out: + return error; +} + +static long do_semtimedop(int semid, struct sembuf __user *tsops, + unsigned nsops, const struct timespec64 *timeout) +{ + struct sembuf fast_sops[SEMOPM_FAST]; + struct sembuf *sops =3D fast_sops; + struct ipc_namespace *ns; + int ret; + + ns =3D current->nsproxy->ipc_ns; + if (nsops > ns->sc_semopm) + return -E2BIG; + if (nsops < 1) + return -EINVAL; + + if (nsops > SEMOPM_FAST) { + sops =3D kvmalloc_array(nsops, sizeof(*sops), GFP_KERNEL); + if (sops =3D=3D NULL) + return -ENOMEM; + } + + if (copy_from_user(sops, tsops, nsops * sizeof(*tsops))) { + ret =3D -EFAULT; + goto out_free; + } + + ret =3D __do_semtimedop(semid, sops, nsops, timeout, ns); + out_free: if (sops !=3D fast_sops) kvfree(sops); - return error; + + return ret; } =20 long ksys_semtimedop(int semid, struct sembuf __user *tsops, --=20 2.27.0