Skip to content

Commit

Permalink
Merge tag 'printk-hash-pointer-4.15-rc2' of git://github.com/tchardin…
Browse files Browse the repository at this point in the history
…g/linux

Pull printk pointer hashing update from Tobin Harding:
 "Here is the patch set that implements hashing of printk specifier %p.

  First we have two clean up patches then we do the hashing. Hashing is
  done via the SipHash algorithm. The next patch adds printk specifier
  %px for printing pointers when we _really_ want to see the address i.e
  %px is functionally equivalent to %lx. Final patch in the set fixes
  KASAN since we break it by hashing %p.

  For the record here is the justification for the series:

    Currently there exist approximately 14 000 places in the Kernel
    where addresses are being printed using an unadorned %p. This
    potentially leaks sensitive information about the Kernel layout in
    memory. Many of these calls are stale, instead of fixing every call
    we hash the address by default before printing. We then add %px to
    provide a way to print the actual address. Although this is
    achievable using %lx, using %px will assist us if we ever want to
    change pointer printing behaviour. %px is more uniquely grep'able
    (there are already >50 000 uses of %lx).

    The added advantage of hashing %p is that security is now opt-out,
    if you _really_ want the address you have to work a little harder
    and use %px.

  This will of course break some users, forcing code printing needed
  addresses to be updated"

[ I do expect this to be an annoyance, and a number of %px users to be
  added for debuggability. But nobody is willing to audit existing %p
  users for information leaks, and a number of places really only use
  the pointer as an object identifier rather than really 'I need the
  address'.

  IOW - sorry for the inconvenience, but it's the least inconvenient of
  the options.    - Linus ]

* tag 'printk-hash-pointer-4.15-rc2' of git://github.com/tcharding/linux:
  kasan: use %px to print addresses instead of %p
  vsprintf: add printk specifier %px
  printk: hash addresses printed with %p
  vsprintf: refactor %pK code out of pointer()
  docs: correct documentation for %pK
  • Loading branch information
torvalds committed Nov 29, 2017
2 parents f55e101 + 6424f6b commit da6af54
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 95 deletions.
31 changes: 28 additions & 3 deletions Documentation/printk-formats.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ How to get printk format specifiers right
:Author: Randy Dunlap <[email protected]>
:Author: Andrew Murray <[email protected]>


Integer types
=============

Expand Down Expand Up @@ -45,6 +44,18 @@ return from vsnprintf.
Raw pointer value SHOULD be printed with %p. The kernel supports
the following extended format specifiers for pointer types:

Pointer Types
=============

Pointers printed without a specifier extension (i.e unadorned %p) are
hashed to give a unique identifier without leaking kernel addresses to user
space. On 64 bit machines the first 32 bits are zeroed. If you _really_
want the address see %px below.

::

%p abcdef12 or 00000000abcdef12

Symbols/Function Pointers
=========================

Expand Down Expand Up @@ -85,18 +96,32 @@ Examples::
printk("Faulted at %pS\n", (void *)regs->ip);
printk(" %s%pB\n", (reliable ? "" : "? "), (void *)*stack);


Kernel Pointers
===============

::

%pK 0x01234567 or 0x0123456789abcdef
%pK 01234567 or 0123456789abcdef

For printing kernel pointers which should be hidden from unprivileged
users. The behaviour of ``%pK`` depends on the ``kptr_restrict sysctl`` - see
Documentation/sysctl/kernel.txt for more details.

Unmodified Addresses
====================

::

%px 01234567 or 0123456789abcdef

For printing pointers when you _really_ want to print the address. Please
consider whether or not you are leaking sensitive information about the
Kernel layout in memory before printing pointers with %px. %px is
functionally equivalent to %lx. %px is preferred to %lx because it is more
uniquely grep'able. If, in the future, we need to modify the way the Kernel
handles printing pointers it will be nice to be able to find the call
sites.

Struct Resources
================

Expand Down
108 changes: 70 additions & 38 deletions lib/test_printf.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,6 @@
#define PAD_SIZE 16
#define FILL_CHAR '$'

#define PTR1 ((void*)0x01234567)
#define PTR2 ((void*)(long)(int)0xfedcba98)

#if BITS_PER_LONG == 64
#define PTR1_ZEROES "000000000"
#define PTR1_SPACES " "
#define PTR1_STR "1234567"
#define PTR2_STR "fffffffffedcba98"
#define PTR_WIDTH 16
#else
#define PTR1_ZEROES "0"
#define PTR1_SPACES " "
#define PTR1_STR "1234567"
#define PTR2_STR "fedcba98"
#define PTR_WIDTH 8
#endif
#define PTR_WIDTH_STR stringify(PTR_WIDTH)

static unsigned total_tests __initdata;
static unsigned failed_tests __initdata;
static char *test_buffer __initdata;
Expand Down Expand Up @@ -217,30 +199,79 @@ test_string(void)
test("a | | ", "%-3.s|%-3.0s|%-3.*s", "a", "b", 0, "c");
}

#define PLAIN_BUF_SIZE 64 /* leave some space so we don't oops */

#if BITS_PER_LONG == 64

#define PTR_WIDTH 16
#define PTR ((void *)0xffff0123456789ab)
#define PTR_STR "ffff0123456789ab"
#define ZEROS "00000000" /* hex 32 zero bits */

static int __init
plain_format(void)
{
char buf[PLAIN_BUF_SIZE];
int nchars;

nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR);

if (nchars != PTR_WIDTH || strncmp(buf, ZEROS, strlen(ZEROS)) != 0)
return -1;

return 0;
}

#else

#define PTR_WIDTH 8
#define PTR ((void *)0x456789ab)
#define PTR_STR "456789ab"

static int __init
plain_format(void)
{
/* Format is implicitly tested for 32 bit machines by plain_hash() */
return 0;
}

#endif /* BITS_PER_LONG == 64 */

static int __init
plain_hash(void)
{
char buf[PLAIN_BUF_SIZE];
int nchars;

nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR);

if (nchars != PTR_WIDTH || strncmp(buf, PTR_STR, PTR_WIDTH) == 0)
return -1;

return 0;
}

/*
* We can't use test() to test %p because we don't know what output to expect
* after an address is hashed.
*/
static void __init
plain(void)
{
test(PTR1_ZEROES PTR1_STR " " PTR2_STR, "%p %p", PTR1, PTR2);
/*
* The field width is overloaded for some %p extensions to
* pass another piece of information. For plain pointers, the
* behaviour is slightly odd: One cannot pass either the 0
* flag nor a precision to %p without gcc complaining, and if
* one explicitly gives a field width, the number is no longer
* zero-padded.
*/
test("|" PTR1_STR PTR1_SPACES " | " PTR1_SPACES PTR1_STR "|",
"|%-*p|%*p|", PTR_WIDTH+2, PTR1, PTR_WIDTH+2, PTR1);
test("|" PTR2_STR " | " PTR2_STR "|",
"|%-*p|%*p|", PTR_WIDTH+2, PTR2, PTR_WIDTH+2, PTR2);
int err;

/*
* Unrecognized %p extensions are treated as plain %p, but the
* alphanumeric suffix is ignored (that is, does not occur in
* the output.)
*/
test("|"PTR1_ZEROES PTR1_STR"|", "|%p0y|", PTR1);
test("|"PTR2_STR"|", "|%p0y|", PTR2);
err = plain_hash();
if (err) {
pr_warn("plain 'p' does not appear to be hashed\n");
failed_tests++;
return;
}

err = plain_format();
if (err) {
pr_warn("hashing plain 'p' has unexpected format\n");
failed_tests++;
}
}

static void __init
Expand All @@ -251,6 +282,7 @@ symbol_ptr(void)
static void __init
kernel_ptr(void)
{
/* We can't test this without access to kptr_restrict. */
}

static void __init
Expand Down
Loading

0 comments on commit da6af54

Please sign in to comment.