aboutsummaryrefslogtreecommitdiffstats
path: root/lib/test_printf.c
diff options
context:
space:
mode:
authorTobin C. Harding <me@tobin.cc>2017-11-01 00:32:23 -0400
committerTobin C. Harding <me@tobin.cc>2017-11-28 20:09:02 -0500
commitad67b74d2469d9b82aaa572d76474c95bc484d57 (patch)
treefb0ce583607629e6b5da2842f98febf831ab4c87 /lib/test_printf.c
parent57e734423adda83f3b05505875343284efe3b39c (diff)
printk: hash addresses printed with %p
Currently there exist approximately 14 000 places in the kernel where addresses are being printed using an unadorned %p. This potentially leaks sensitive information regarding the Kernel layout in memory. Many of these calls are stale, instead of fixing every call lets hash the address by default before printing. This will of course break some users, forcing code printing needed addresses to be updated. Code that _really_ needs the address will soon be able to use the new printk specifier %px to print the address. For what it's worth, usage of unadorned %p can be broken down as follows (thanks to Joe Perches). $ git grep -E '%p[^A-Za-z0-9]' | cut -f1 -d"/" | sort | uniq -c 1084 arch 20 block 10 crypto 32 Documentation 8121 drivers 1221 fs 143 include 101 kernel 69 lib 100 mm 1510 net 40 samples 7 scripts 11 security 166 sound 152 tools 2 virt Add function ptr_to_id() to map an address to a 32 bit unique identifier. Hash any unadorned usage of specifier %p and any malformed specifiers. Signed-off-by: Tobin C. Harding <me@tobin.cc>
Diffstat (limited to 'lib/test_printf.c')
-rw-r--r--lib/test_printf.c108
1 files changed, 70 insertions, 38 deletions
diff --git a/lib/test_printf.c b/lib/test_printf.c
index 563f10e6876a..71ebfa43ad05 100644
--- a/lib/test_printf.c
+++ b/lib/test_printf.c
@@ -24,24 +24,6 @@
24#define PAD_SIZE 16 24#define PAD_SIZE 16
25#define FILL_CHAR '$' 25#define FILL_CHAR '$'
26 26
27#define PTR1 ((void*)0x01234567)
28#define PTR2 ((void*)(long)(int)0xfedcba98)
29
30#if BITS_PER_LONG == 64
31#define PTR1_ZEROES "000000000"
32#define PTR1_SPACES " "
33#define PTR1_STR "1234567"
34#define PTR2_STR "fffffffffedcba98"
35#define PTR_WIDTH 16
36#else
37#define PTR1_ZEROES "0"
38#define PTR1_SPACES " "
39#define PTR1_STR "1234567"
40#define PTR2_STR "fedcba98"
41#define PTR_WIDTH 8
42#endif
43#define PTR_WIDTH_STR stringify(PTR_WIDTH)
44
45static unsigned total_tests __initdata; 27static unsigned total_tests __initdata;
46static unsigned failed_tests __initdata; 28static unsigned failed_tests __initdata;
47static char *test_buffer __initdata; 29static char *test_buffer __initdata;
@@ -217,30 +199,79 @@ test_string(void)
217 test("a | | ", "%-3.s|%-3.0s|%-3.*s", "a", "b", 0, "c"); 199 test("a | | ", "%-3.s|%-3.0s|%-3.*s", "a", "b", 0, "c");
218} 200}
219 201
202#define PLAIN_BUF_SIZE 64 /* leave some space so we don't oops */
203
204#if BITS_PER_LONG == 64
205
206#define PTR_WIDTH 16
207#define PTR ((void *)0xffff0123456789ab)
208#define PTR_STR "ffff0123456789ab"
209#define ZEROS "00000000" /* hex 32 zero bits */
210
211static int __init
212plain_format(void)
213{
214 char buf[PLAIN_BUF_SIZE];
215 int nchars;
216
217 nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR);
218
219 if (nchars != PTR_WIDTH || strncmp(buf, ZEROS, strlen(ZEROS)) != 0)
220 return -1;
221
222 return 0;
223}
224
225#else
226
227#define PTR_WIDTH 8
228#define PTR ((void *)0x456789ab)
229#define PTR_STR "456789ab"
230
231static int __init
232plain_format(void)
233{
234 /* Format is implicitly tested for 32 bit machines by plain_hash() */
235 return 0;
236}
237
238#endif /* BITS_PER_LONG == 64 */
239
240static int __init
241plain_hash(void)
242{
243 char buf[PLAIN_BUF_SIZE];
244 int nchars;
245
246 nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR);
247
248 if (nchars != PTR_WIDTH || strncmp(buf, PTR_STR, PTR_WIDTH) == 0)
249 return -1;
250
251 return 0;
252}
253
254/*
255 * We can't use test() to test %p because we don't know what output to expect
256 * after an address is hashed.
257 */
220static void __init 258static void __init
221plain(void) 259plain(void)
222{ 260{
223 test(PTR1_ZEROES PTR1_STR " " PTR2_STR, "%p %p", PTR1, PTR2); 261 int err;
224 /*
225 * The field width is overloaded for some %p extensions to
226 * pass another piece of information. For plain pointers, the
227 * behaviour is slightly odd: One cannot pass either the 0
228 * flag nor a precision to %p without gcc complaining, and if
229 * one explicitly gives a field width, the number is no longer
230 * zero-padded.
231 */
232 test("|" PTR1_STR PTR1_SPACES " | " PTR1_SPACES PTR1_STR "|",
233 "|%-*p|%*p|", PTR_WIDTH+2, PTR1, PTR_WIDTH+2, PTR1);
234 test("|" PTR2_STR " | " PTR2_STR "|",
235 "|%-*p|%*p|", PTR_WIDTH+2, PTR2, PTR_WIDTH+2, PTR2);
236 262
237 /* 263 err = plain_hash();
238 * Unrecognized %p extensions are treated as plain %p, but the 264 if (err) {
239 * alphanumeric suffix is ignored (that is, does not occur in 265 pr_warn("plain 'p' does not appear to be hashed\n");
240 * the output.) 266 failed_tests++;
241 */ 267 return;
242 test("|"PTR1_ZEROES PTR1_STR"|", "|%p0y|", PTR1); 268 }
243 test("|"PTR2_STR"|", "|%p0y|", PTR2); 269
270 err = plain_format();
271 if (err) {
272 pr_warn("hashing plain 'p' has unexpected format\n");
273 failed_tests++;
274 }
244} 275}
245 276
246static void __init 277static void __init
@@ -251,6 +282,7 @@ symbol_ptr(void)
251static void __init 282static void __init
252kernel_ptr(void) 283kernel_ptr(void)
253{ 284{
285 /* We can't test this without access to kptr_restrict. */
254} 286}
255 287
256static void __init 288static void __init