diff options
author | Christopher M. Riedl <cmr@codefail.de> | 2021-02-27 04:12:50 +0300 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2021-03-29 04:49:46 +0300 |
commit | 9466c1799fa2acb68e505a264dcdf53779101ac6 (patch) | |
tree | 952e7bca4caabd041c874a951d405140f4de35cd /arch | |
parent | deb9b13eb2571fbde164ae012c77985fd14f2f02 (diff) | |
download | linux-9466c1799fa2acb68e505a264dcdf53779101ac6.tar.xz |
powerpc/uaccess: Add unsafe_copy_from_user()
Use the same approach as unsafe_copy_to_user() but instead call
unsafe_get_user() in a loop.
Signed-off-by: Christopher M. Riedl <cmr@codefail.de>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210227011259.11992-2-cmr@codefail.de
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/include/asm/uaccess.h | 21 |
1 files changed, 21 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h index 479cb30eabd7..c3d3d178fa0e 100644 --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -486,6 +486,27 @@ user_write_access_begin(const void __user *ptr, size_t len) #define unsafe_put_user(x, p, e) \ __unsafe_put_user_goto((__typeof__(*(p)))(x), (p), sizeof(*(p)), e) +#define unsafe_copy_from_user(d, s, l, e) \ +do { \ + u8 *_dst = (u8 *)(d); \ + const u8 __user *_src = (const u8 __user *)(s); \ + size_t _len = (l); \ + int _i; \ + \ + for (_i = 0; _i < (_len & ~(sizeof(long) - 1)); _i += sizeof(long)) \ + unsafe_get_user(*(long *)(_dst + _i), (long __user *)(_src + _i), e); \ + if (IS_ENABLED(CONFIG_PPC64) && (_len & 4)) { \ + unsafe_get_user(*(u32 *)(_dst + _i), (u32 __user *)(_src + _i), e); \ + _i += 4; \ + } \ + if (_len & 2) { \ + unsafe_get_user(*(u16 *)(_dst + _i), (u16 __user *)(_src + _i), e); \ + _i += 2; \ + } \ + if (_len & 1) \ + unsafe_get_user(*(u8 *)(_dst + _i), (u8 __user *)(_src + _i), e); \ +} while (0) + #define unsafe_copy_to_user(d, s, l, e) \ do { \ u8 __user *_dst = (u8 __user *)(d); \ |