Skip to content

Commit b58294e

Browse files
Christoph Hellwigtorvalds
authored andcommitted
maccess: allow architectures to provide kernel probing directly
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]>
1 parent fc3562d commit b58294e

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed

mm/maccess.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,81 @@ bool __weak probe_kernel_read_allowed(const void *unsafe_src, size_t size)
1111
return true;
1212
}
1313

14+
#ifdef HAVE_GET_KERNEL_NOFAULT
15+
16+
#define probe_kernel_read_loop(dst, src, len, type, err_label) \
17+
while (len >= sizeof(type)) { \
18+
__get_kernel_nofault(dst, src, type, err_label); \
19+
dst += sizeof(type); \
20+
src += sizeof(type); \
21+
len -= sizeof(type); \
22+
}
23+
24+
long probe_kernel_read(void *dst, const void *src, size_t size)
25+
{
26+
if (!probe_kernel_read_allowed(src, size))
27+
return -EFAULT;
28+
29+
pagefault_disable();
30+
probe_kernel_read_loop(dst, src, size, u64, Efault);
31+
probe_kernel_read_loop(dst, src, size, u32, Efault);
32+
probe_kernel_read_loop(dst, src, size, u16, Efault);
33+
probe_kernel_read_loop(dst, src, size, u8, Efault);
34+
pagefault_enable();
35+
return 0;
36+
Efault:
37+
pagefault_enable();
38+
return -EFAULT;
39+
}
40+
EXPORT_SYMBOL_GPL(probe_kernel_read);
41+
42+
#define probe_kernel_write_loop(dst, src, len, type, err_label) \
43+
while (len >= sizeof(type)) { \
44+
__put_kernel_nofault(dst, src, type, err_label); \
45+
dst += sizeof(type); \
46+
src += sizeof(type); \
47+
len -= sizeof(type); \
48+
}
49+
50+
long probe_kernel_write(void *dst, const void *src, size_t size)
51+
{
52+
pagefault_disable();
53+
probe_kernel_write_loop(dst, src, size, u64, Efault);
54+
probe_kernel_write_loop(dst, src, size, u32, Efault);
55+
probe_kernel_write_loop(dst, src, size, u16, Efault);
56+
probe_kernel_write_loop(dst, src, size, u8, Efault);
57+
pagefault_enable();
58+
return 0;
59+
Efault:
60+
pagefault_enable();
61+
return -EFAULT;
62+
}
63+
64+
long strncpy_from_kernel_nofault(char *dst, const void *unsafe_addr, long count)
65+
{
66+
const void *src = unsafe_addr;
67+
68+
if (unlikely(count <= 0))
69+
return 0;
70+
if (!probe_kernel_read_allowed(unsafe_addr, count))
71+
return -EFAULT;
72+
73+
pagefault_disable();
74+
do {
75+
__get_kernel_nofault(dst, src, u8, Efault);
76+
dst++;
77+
src++;
78+
} while (dst[-1] && src - unsafe_addr < count);
79+
pagefault_enable();
80+
81+
dst[-1] = '\0';
82+
return src - unsafe_addr;
83+
Efault:
84+
pagefault_enable();
85+
dst[-1] = '\0';
86+
return -EFAULT;
87+
}
88+
#else /* HAVE_GET_KERNEL_NOFAULT */
1489
/**
1590
* probe_kernel_read(): safely attempt to read from kernel-space
1691
* @dst: pointer to the buffer that shall take the data
@@ -113,6 +188,7 @@ long strncpy_from_kernel_nofault(char *dst, const void *unsafe_addr, long count)
113188

114189
return ret ? -EFAULT : src - unsafe_addr;
115190
}
191+
#endif /* HAVE_GET_KERNEL_NOFAULT */
116192

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

0 commit comments

Comments
 (0)