diff options
author | Christophe Leroy <christophe.leroy@csgroup.eu> | 2020-08-18 17:19:33 +0000 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2020-12-04 01:01:14 +1100 |
commit | de781ebdf6b8a256742da4fd6b0e39bb22ed9fe3 (patch) | |
tree | c9592674a2b48a45cfa3386ecac9d6cf9d9c9215 /arch/powerpc/kernel/signal_32.c | |
parent | 14026b94ccfe626e512bc9fa01e0e72ee75c7a98 (diff) | |
download | linux-stable-de781ebdf6b8a256742da4fd6b0e39bb22ed9fe3.tar.gz linux-stable-de781ebdf6b8a256742da4fd6b0e39bb22ed9fe3.tar.bz2 linux-stable-de781ebdf6b8a256742da4fd6b0e39bb22ed9fe3.zip |
powerpc/signal32: Add and use unsafe_put_sigset_t()
put_sigset_t() calls copy_to_user() for copying two words.
This is terribly inefficient for copying two words.
By switching to unsafe_put_user(), we end up with something as
simple as:
3cc: 81 3d 00 00 lwz r9,0(r29)
3d0: 91 26 00 b4 stw r9,180(r6)
3d4: 81 3d 00 04 lwz r9,4(r29)
3d8: 91 26 00 b8 stw r9,184(r6)
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/06def97e87ac1c4ae8e3197e0982e1fab7b3c8ae.1597770847.git.christophe.leroy@csgroup.eu
Diffstat (limited to 'arch/powerpc/kernel/signal_32.c')
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 310d3b8d9ad5..3f9f315dd036 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -87,6 +87,8 @@ static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set) return put_compat_sigset(uset, set, sizeof(*uset)); } +#define unsafe_put_sigset_t unsafe_put_compat_sigset + static inline int get_sigset_t(sigset_t *set, const compat_sigset_t __user *uset) { @@ -141,6 +143,13 @@ static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set) return copy_to_user(uset, set, sizeof(*uset)); } +#define unsafe_put_sigset_t(uset, set, label) do { \ + sigset_t __user *__us = uset ; \ + const sigset_t *__s = set; \ + \ + unsafe_copy_to_user(__us, __s, sizeof(*__us), label); \ +} while (0) + static inline int get_sigset_t(sigset_t *set, const sigset_t __user *uset) { return copy_from_user(set, uset, sizeof(*uset)); @@ -780,10 +789,10 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, failed); unsafe_put_user(PPC_INST_SC, &mctx->mc_pad[1], failed); } + unsafe_put_sigset_t(&frame->uc.uc_sigmask, oldset, failed); + user_write_access_end(); - if (put_sigset_t(&frame->uc.uc_sigmask, oldset)) - goto badframe; if (copy_siginfo_to_user(&frame->info, &ksig->info)) goto badframe; |