Skip to content

Commit

Permalink
maccess: allow architectures to provide kernel probing directly
Browse files Browse the repository at this point in the history
Provide alternative versions of probe_kernel_read, probe_kernel_write
and strncpy_from_kernel_unsafe that don't need set_fs magic, but instead
use arch hooks that are modelled after unsafe_{get,put}_user to access
kernel memory in an exception safe way.

Signed-off-by: Christoph Hellwig <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Cc: Alexei Starovoitov <[email protected]>
Cc: Daniel Borkmann <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Masami Hiramatsu <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Christoph Hellwig authored and torvalds committed Jun 9, 2020
1 parent fc3562d commit b58294e
Showing 1 changed file with 76 additions and 0 deletions.
76 changes: 76 additions & 0 deletions mm/maccess.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,81 @@ bool __weak probe_kernel_read_allowed(const void *unsafe_src, size_t size)
return true;
}

#ifdef HAVE_GET_KERNEL_NOFAULT

#define probe_kernel_read_loop(dst, src, len, type, err_label) \
while (len >= sizeof(type)) { \
__get_kernel_nofault(dst, src, type, err_label); \
dst += sizeof(type); \
src += sizeof(type); \
len -= sizeof(type); \
}

long probe_kernel_read(void *dst, const void *src, size_t size)
{
if (!probe_kernel_read_allowed(src, size))
return -EFAULT;

pagefault_disable();
probe_kernel_read_loop(dst, src, size, u64, Efault);
probe_kernel_read_loop(dst, src, size, u32, Efault);
probe_kernel_read_loop(dst, src, size, u16, Efault);
probe_kernel_read_loop(dst, src, size, u8, Efault);
pagefault_enable();
return 0;
Efault:
pagefault_enable();
return -EFAULT;
}
EXPORT_SYMBOL_GPL(probe_kernel_read);

#define probe_kernel_write_loop(dst, src, len, type, err_label) \
while (len >= sizeof(type)) { \
__put_kernel_nofault(dst, src, type, err_label); \
dst += sizeof(type); \
src += sizeof(type); \
len -= sizeof(type); \
}

long probe_kernel_write(void *dst, const void *src, size_t size)
{
pagefault_disable();
probe_kernel_write_loop(dst, src, size, u64, Efault);
probe_kernel_write_loop(dst, src, size, u32, Efault);
probe_kernel_write_loop(dst, src, size, u16, Efault);
probe_kernel_write_loop(dst, src, size, u8, Efault);
pagefault_enable();
return 0;
Efault:
pagefault_enable();
return -EFAULT;
}

long strncpy_from_kernel_nofault(char *dst, const void *unsafe_addr, long count)
{
const void *src = unsafe_addr;

if (unlikely(count <= 0))
return 0;
if (!probe_kernel_read_allowed(unsafe_addr, count))
return -EFAULT;

pagefault_disable();
do {
__get_kernel_nofault(dst, src, u8, Efault);
dst++;
src++;
} while (dst[-1] && src - unsafe_addr < count);
pagefault_enable();

dst[-1] = '\0';
return src - unsafe_addr;
Efault:
pagefault_enable();
dst[-1] = '\0';
return -EFAULT;
}
#else /* HAVE_GET_KERNEL_NOFAULT */
/**
* probe_kernel_read(): safely attempt to read from kernel-space
* @dst: pointer to the buffer that shall take the data
Expand Down Expand Up @@ -113,6 +188,7 @@ long strncpy_from_kernel_nofault(char *dst, const void *unsafe_addr, long count)

return ret ? -EFAULT : src - unsafe_addr;
}
#endif /* HAVE_GET_KERNEL_NOFAULT */

/**
* probe_user_read(): safely attempt to read from a user-space location
Expand Down

0 comments on commit b58294e

Please sign in to comment.