Commit 41cd7805 authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman

uaccess: Selectively open read or write user access

When opening user access to only perform reads, only open read access.
When opening user access to only perform writes, only open write
access.
Signed-off-by: default avatarChristophe Leroy <christophe.leroy@c-s.fr>
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/2e73bc57125c2c6ab12a587586a4eed3a47105fc.1585898438.git.christophe.leroy@c-s.fr
parent 999a2289
...@@ -242,7 +242,7 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen, ...@@ -242,7 +242,7 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen,
return -EINTR; return -EINTR;
dirent = buf->current_dir; dirent = buf->current_dir;
prev = (void __user *) dirent - prev_reclen; prev = (void __user *) dirent - prev_reclen;
if (!user_access_begin(prev, reclen + prev_reclen)) if (!user_write_access_begin(prev, reclen + prev_reclen))
goto efault; goto efault;
/* This might be 'dirent->d_off', but if so it will get overwritten */ /* This might be 'dirent->d_off', but if so it will get overwritten */
...@@ -251,14 +251,14 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen, ...@@ -251,14 +251,14 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen,
unsafe_put_user(reclen, &dirent->d_reclen, efault_end); unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end); unsafe_put_user(d_type, (char __user *) dirent + reclen - 1, efault_end);
unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end); unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
user_access_end(); user_write_access_end();
buf->current_dir = (void __user *)dirent + reclen; buf->current_dir = (void __user *)dirent + reclen;
buf->prev_reclen = reclen; buf->prev_reclen = reclen;
buf->count -= reclen; buf->count -= reclen;
return 0; return 0;
efault_end: efault_end:
user_access_end(); user_write_access_end();
efault: efault:
buf->error = -EFAULT; buf->error = -EFAULT;
return -EFAULT; return -EFAULT;
...@@ -327,7 +327,7 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen, ...@@ -327,7 +327,7 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen,
return -EINTR; return -EINTR;
dirent = buf->current_dir; dirent = buf->current_dir;
prev = (void __user *)dirent - prev_reclen; prev = (void __user *)dirent - prev_reclen;
if (!user_access_begin(prev, reclen + prev_reclen)) if (!user_write_access_begin(prev, reclen + prev_reclen))
goto efault; goto efault;
/* This might be 'dirent->d_off', but if so it will get overwritten */ /* This might be 'dirent->d_off', but if so it will get overwritten */
...@@ -336,7 +336,7 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen, ...@@ -336,7 +336,7 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen,
unsafe_put_user(reclen, &dirent->d_reclen, efault_end); unsafe_put_user(reclen, &dirent->d_reclen, efault_end);
unsafe_put_user(d_type, &dirent->d_type, efault_end); unsafe_put_user(d_type, &dirent->d_type, efault_end);
unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end); unsafe_copy_dirent_name(dirent->d_name, name, namlen, efault_end);
user_access_end(); user_write_access_end();
buf->prev_reclen = reclen; buf->prev_reclen = reclen;
buf->current_dir = (void __user *)dirent + reclen; buf->current_dir = (void __user *)dirent + reclen;
...@@ -344,7 +344,7 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen, ...@@ -344,7 +344,7 @@ static int filldir64(struct dir_context *ctx, const char *name, int namlen,
return 0; return 0;
efault_end: efault_end:
user_access_end(); user_write_access_end();
efault: efault:
buf->error = -EFAULT; buf->error = -EFAULT;
return -EFAULT; return -EFAULT;
......
...@@ -199,7 +199,7 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, ...@@ -199,7 +199,7 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
if (!user_access_begin(umask, bitmap_size / 8)) if (!user_read_access_begin(umask, bitmap_size / 8))
return -EFAULT; return -EFAULT;
while (nr_compat_longs > 1) { while (nr_compat_longs > 1) {
...@@ -211,11 +211,11 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, ...@@ -211,11 +211,11 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
} }
if (nr_compat_longs) if (nr_compat_longs)
unsafe_get_user(*mask, umask++, Efault); unsafe_get_user(*mask, umask++, Efault);
user_access_end(); user_read_access_end();
return 0; return 0;
Efault: Efault:
user_access_end(); user_read_access_end();
return -EFAULT; return -EFAULT;
} }
...@@ -228,7 +228,7 @@ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, ...@@ -228,7 +228,7 @@ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
if (!user_access_begin(umask, bitmap_size / 8)) if (!user_write_access_begin(umask, bitmap_size / 8))
return -EFAULT; return -EFAULT;
while (nr_compat_longs > 1) { while (nr_compat_longs > 1) {
...@@ -239,10 +239,10 @@ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, ...@@ -239,10 +239,10 @@ long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
} }
if (nr_compat_longs) if (nr_compat_longs)
unsafe_put_user((compat_ulong_t)*mask, umask++, Efault); unsafe_put_user((compat_ulong_t)*mask, umask++, Efault);
user_access_end(); user_write_access_end();
return 0; return 0;
Efault: Efault:
user_access_end(); user_write_access_end();
return -EFAULT; return -EFAULT;
} }
......
...@@ -1557,7 +1557,7 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, ...@@ -1557,7 +1557,7 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
if (!infop) if (!infop)
return err; return err;
if (!user_access_begin(infop, sizeof(*infop))) if (!user_write_access_begin(infop, sizeof(*infop)))
return -EFAULT; return -EFAULT;
unsafe_put_user(signo, &infop->si_signo, Efault); unsafe_put_user(signo, &infop->si_signo, Efault);
...@@ -1566,10 +1566,10 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, ...@@ -1566,10 +1566,10 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
unsafe_put_user(info.pid, &infop->si_pid, Efault); unsafe_put_user(info.pid, &infop->si_pid, Efault);
unsafe_put_user(info.uid, &infop->si_uid, Efault); unsafe_put_user(info.uid, &infop->si_uid, Efault);
unsafe_put_user(info.status, &infop->si_status, Efault); unsafe_put_user(info.status, &infop->si_status, Efault);
user_access_end(); user_write_access_end();
return err; return err;
Efault: Efault:
user_access_end(); user_write_access_end();
return -EFAULT; return -EFAULT;
} }
...@@ -1684,7 +1684,7 @@ COMPAT_SYSCALL_DEFINE5(waitid, ...@@ -1684,7 +1684,7 @@ COMPAT_SYSCALL_DEFINE5(waitid,
if (!infop) if (!infop)
return err; return err;
if (!user_access_begin(infop, sizeof(*infop))) if (!user_write_access_begin(infop, sizeof(*infop)))
return -EFAULT; return -EFAULT;
unsafe_put_user(signo, &infop->si_signo, Efault); unsafe_put_user(signo, &infop->si_signo, Efault);
...@@ -1693,10 +1693,10 @@ COMPAT_SYSCALL_DEFINE5(waitid, ...@@ -1693,10 +1693,10 @@ COMPAT_SYSCALL_DEFINE5(waitid,
unsafe_put_user(info.pid, &infop->si_pid, Efault); unsafe_put_user(info.pid, &infop->si_pid, Efault);
unsafe_put_user(info.uid, &infop->si_uid, Efault); unsafe_put_user(info.uid, &infop->si_uid, Efault);
unsafe_put_user(info.status, &infop->si_status, Efault); unsafe_put_user(info.status, &infop->si_status, Efault);
user_access_end(); user_write_access_end();
return err; return err;
Efault: Efault:
user_access_end(); user_write_access_end();
return -EFAULT; return -EFAULT;
} }
#endif #endif
......
...@@ -116,9 +116,9 @@ long strncpy_from_user(char *dst, const char __user *src, long count) ...@@ -116,9 +116,9 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
kasan_check_write(dst, count); kasan_check_write(dst, count);
check_object_size(dst, count, false); check_object_size(dst, count, false);
if (user_access_begin(src, max)) { if (user_read_access_begin(src, max)) {
retval = do_strncpy_from_user(dst, src, count, max); retval = do_strncpy_from_user(dst, src, count, max);
user_access_end(); user_read_access_end();
return retval; return retval;
} }
} }
......
...@@ -109,9 +109,9 @@ long strnlen_user(const char __user *str, long count) ...@@ -109,9 +109,9 @@ long strnlen_user(const char __user *str, long count)
if (max > count) if (max > count)
max = count; max = count;
if (user_access_begin(str, max)) { if (user_read_access_begin(str, max)) {
retval = do_strnlen_user(str, count, max); retval = do_strnlen_user(str, count, max);
user_access_end(); user_read_access_end();
return retval; return retval;
} }
} }
......
...@@ -58,7 +58,7 @@ int check_zeroed_user(const void __user *from, size_t size) ...@@ -58,7 +58,7 @@ int check_zeroed_user(const void __user *from, size_t size)
from -= align; from -= align;
size += align; size += align;
if (!user_access_begin(from, size)) if (!user_read_access_begin(from, size))
return -EFAULT; return -EFAULT;
unsafe_get_user(val, (unsigned long __user *) from, err_fault); unsafe_get_user(val, (unsigned long __user *) from, err_fault);
...@@ -79,10 +79,10 @@ int check_zeroed_user(const void __user *from, size_t size) ...@@ -79,10 +79,10 @@ int check_zeroed_user(const void __user *from, size_t size)
val &= aligned_byte_mask(size); val &= aligned_byte_mask(size);
done: done:
user_access_end(); user_read_access_end();
return (val == 0); return (val == 0);
err_fault: err_fault:
user_access_end(); user_read_access_end();
return -EFAULT; return -EFAULT;
} }
EXPORT_SYMBOL(check_zeroed_user); EXPORT_SYMBOL(check_zeroed_user);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment