|
@@ -33,6 +33,8 @@
|
|
#include <linux/uuid.h>
|
|
#include <linux/uuid.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of.h>
|
|
#include <net/addrconf.h>
|
|
#include <net/addrconf.h>
|
|
|
|
+#include <linux/siphash.h>
|
|
|
|
+#include <linux/compiler.h>
|
|
#ifdef CONFIG_BLOCK
|
|
#ifdef CONFIG_BLOCK
|
|
#include <linux/blkdev.h>
|
|
#include <linux/blkdev.h>
|
|
#endif
|
|
#endif
|
|
@@ -1644,6 +1646,73 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
|
|
return widen_string(buf, buf - buf_start, end, spec);
|
|
return widen_string(buf, buf - buf_start, end, spec);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool have_filled_random_ptr_key __read_mostly;
|
|
|
|
+static siphash_key_t ptr_key __read_mostly;
|
|
|
|
+
|
|
|
|
+static void fill_random_ptr_key(struct random_ready_callback *unused)
|
|
|
|
+{
|
|
|
|
+ get_random_bytes(&ptr_key, sizeof(ptr_key));
|
|
|
|
+ /*
|
|
|
|
+ * have_filled_random_ptr_key==true is dependent on get_random_bytes().
|
|
|
|
+ * ptr_to_id() needs to see have_filled_random_ptr_key==true
|
|
|
|
+ * after get_random_bytes() returns.
|
|
|
|
+ */
|
|
|
|
+ smp_mb();
|
|
|
|
+ WRITE_ONCE(have_filled_random_ptr_key, true);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct random_ready_callback random_ready = {
|
|
|
|
+ .func = fill_random_ptr_key
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int __init initialize_ptr_random(void)
|
|
|
|
+{
|
|
|
|
+ int ret = add_random_ready_callback(&random_ready);
|
|
|
|
+
|
|
|
|
+ if (!ret) {
|
|
|
|
+ return 0;
|
|
|
|
+ } else if (ret == -EALREADY) {
|
|
|
|
+ fill_random_ptr_key(&random_ready);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+early_initcall(initialize_ptr_random);
|
|
|
|
+
|
|
|
|
+/* Maps a pointer to a 32 bit unique identifier. */
|
|
|
|
+static char *ptr_to_id(char *buf, char *end, void *ptr, struct printf_spec spec)
|
|
|
|
+{
|
|
|
|
+ unsigned long hashval;
|
|
|
|
+ const int default_width = 2 * sizeof(ptr);
|
|
|
|
+
|
|
|
|
+ if (unlikely(!have_filled_random_ptr_key)) {
|
|
|
|
+ spec.field_width = default_width;
|
|
|
|
+ /* string length must be less than default_width */
|
|
|
|
+ return string(buf, end, "(ptrval)", spec);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_64BIT
|
|
|
|
+ hashval = (unsigned long)siphash_1u64((u64)ptr, &ptr_key);
|
|
|
|
+ /*
|
|
|
|
+ * Mask off the first 32 bits, this makes explicit that we have
|
|
|
|
+ * modified the address (and 32 bits is plenty for a unique ID).
|
|
|
|
+ */
|
|
|
|
+ hashval = hashval & 0xffffffff;
|
|
|
|
+#else
|
|
|
|
+ hashval = (unsigned long)siphash_1u32((u32)ptr, &ptr_key);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ spec.flags |= SMALL;
|
|
|
|
+ if (spec.field_width == -1) {
|
|
|
|
+ spec.field_width = default_width;
|
|
|
|
+ spec.flags |= ZEROPAD;
|
|
|
|
+ }
|
|
|
|
+ spec.base = 16;
|
|
|
|
+
|
|
|
|
+ return number(buf, end, hashval, spec);
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Show a '%p' thing. A kernel extension is that the '%p' is followed
|
|
* Show a '%p' thing. A kernel extension is that the '%p' is followed
|
|
* by an extra set of alphanumeric characters that are extended format
|
|
* by an extra set of alphanumeric characters that are extended format
|
|
@@ -1754,6 +1823,9 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
|
|
* Note: The difference between 'S' and 'F' is that on ia64 and ppc64
|
|
* Note: The difference between 'S' and 'F' is that on ia64 and ppc64
|
|
* function pointers are really function descriptors, which contain a
|
|
* function pointers are really function descriptors, which contain a
|
|
* pointer to the real address.
|
|
* pointer to the real address.
|
|
|
|
+ *
|
|
|
|
+ * Note: The default behaviour (unadorned %p) is to hash the address,
|
|
|
|
+ * rendering it useful as a unique identifier.
|
|
*/
|
|
*/
|
|
static noinline_for_stack
|
|
static noinline_for_stack
|
|
char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
|
char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
|
@@ -1869,14 +1941,9 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
|
return device_node_string(buf, end, ptr, spec, fmt + 1);
|
|
return device_node_string(buf, end, ptr, spec, fmt + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- spec.flags |= SMALL;
|
|
|
|
- if (spec.field_width == -1) {
|
|
|
|
- spec.field_width = default_width;
|
|
|
|
- spec.flags |= ZEROPAD;
|
|
|
|
- }
|
|
|
|
- spec.base = 16;
|
|
|
|
|
|
|
|
- return number(buf, end, (unsigned long) ptr, spec);
|
|
|
|
|
|
+ /* default is to _not_ leak addresses, hash before printing */
|
|
|
|
+ return ptr_to_id(buf, end, ptr, spec);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|