Skip to content

Commit b2bec7d

Browse files
committed
Merge tag 'printk-for-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux
Pull printk updates from Petr Mladek: - New "no_hash_pointers" kernel parameter causes that %p shows raw pointer values instead of hashed ones. It is intended only for debugging purposes. Misuse is prevented by a fat warning message that is inspired by trace_printk(). - Prevent a possible deadlock when flushing printk_safe buffers during panic(). - Fix performance regression caused by the lockless printk ringbuffer. It was visible with huge log buffer and long messages. - Documentation fix-up. * tag 'printk-for-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux: lib/vsprintf: no_hash_pointers prints all addresses as unhashed kselftest: add support for skipped tests lib: use KSTM_MODULE_GLOBALS macro in kselftest drivers printk: avoid prb_first_valid_seq() where possible printk: fix deadlock when kernel panic printk: rectify kernel-doc for prb_rec_init_wr()
2 parents 783955f + 16182ac commit b2bec7d

File tree

8 files changed

+103
-27
lines changed

8 files changed

+103
-27
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3293,6 +3293,21 @@
32933293
in certain environments such as networked servers or
32943294
real-time systems.
32953295

3296+
no_hash_pointers
3297+
Force pointers printed to the console or buffers to be
3298+
unhashed. By default, when a pointer is printed via %p
3299+
format string, that pointer is "hashed", i.e. obscured
3300+
by hashing the pointer value. This is a security feature
3301+
that hides actual kernel addresses from unprivileged
3302+
users, but it also makes debugging the kernel more
3303+
difficult since unequal pointers can no longer be
3304+
compared. However, if this command-line option is
3305+
specified, then all normal pointers will have their true
3306+
value printed. Pointers printed via %pK may still be
3307+
hashed. This option should only be specified when
3308+
debugging the kernel. Please do not use on production
3309+
kernels.
3310+
32963311
nohibernate [HIBERNATION] Disable hibernation and resume.
32973312

32983313
nohz= [KNL] Boottime enable/disable dynamic ticks

kernel/printk/printk.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -735,9 +735,9 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
735735
logbuf_lock_irq();
736736
}
737737

738-
if (user->seq < prb_first_valid_seq(prb)) {
738+
if (r->info->seq != user->seq) {
739739
/* our last seen message is gone, return error and reset */
740-
user->seq = prb_first_valid_seq(prb);
740+
user->seq = r->info->seq;
741741
ret = -EPIPE;
742742
logbuf_unlock_irq();
743743
goto out;
@@ -812,6 +812,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
812812
static __poll_t devkmsg_poll(struct file *file, poll_table *wait)
813813
{
814814
struct devkmsg_user *user = file->private_data;
815+
struct printk_info info;
815816
__poll_t ret = 0;
816817

817818
if (!user)
@@ -820,9 +821,9 @@ static __poll_t devkmsg_poll(struct file *file, poll_table *wait)
820821
poll_wait(file, &log_wait, wait);
821822

822823
logbuf_lock_irq();
823-
if (prb_read_valid(prb, user->seq, NULL)) {
824+
if (prb_read_valid_info(prb, user->seq, &info, NULL)) {
824825
/* return error when data has vanished underneath us */
825-
if (user->seq < prb_first_valid_seq(prb))
826+
if (info.seq != user->seq)
826827
ret = EPOLLIN|EPOLLRDNORM|EPOLLERR|EPOLLPRI;
827828
else
828829
ret = EPOLLIN|EPOLLRDNORM;
@@ -1559,6 +1560,7 @@ static void syslog_clear(void)
15591560

15601561
int do_syslog(int type, char __user *buf, int len, int source)
15611562
{
1563+
struct printk_info info;
15621564
bool clear = false;
15631565
static int saved_console_loglevel = LOGLEVEL_DEFAULT;
15641566
int error;
@@ -1629,9 +1631,14 @@ int do_syslog(int type, char __user *buf, int len, int source)
16291631
/* Number of chars in the log buffer */
16301632
case SYSLOG_ACTION_SIZE_UNREAD:
16311633
logbuf_lock_irq();
1632-
if (syslog_seq < prb_first_valid_seq(prb)) {
1634+
if (!prb_read_valid_info(prb, syslog_seq, &info, NULL)) {
1635+
/* No unread messages. */
1636+
logbuf_unlock_irq();
1637+
return 0;
1638+
}
1639+
if (info.seq != syslog_seq) {
16331640
/* messages are gone, move to first one */
1634-
syslog_seq = prb_first_valid_seq(prb);
1641+
syslog_seq = info.seq;
16351642
syslog_partial = 0;
16361643
}
16371644
if (source == SYSLOG_FROM_PROC) {
@@ -1643,7 +1650,6 @@ int do_syslog(int type, char __user *buf, int len, int source)
16431650
error = prb_next_seq(prb) - syslog_seq;
16441651
} else {
16451652
bool time = syslog_partial ? syslog_time : printk_time;
1646-
struct printk_info info;
16471653
unsigned int line_count;
16481654
u64 seq;
16491655

@@ -3429,9 +3435,11 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
34293435
goto out;
34303436

34313437
logbuf_lock_irqsave(flags);
3432-
if (dumper->cur_seq < prb_first_valid_seq(prb)) {
3433-
/* messages are gone, move to first available one */
3434-
dumper->cur_seq = prb_first_valid_seq(prb);
3438+
if (prb_read_valid_info(prb, dumper->cur_seq, &info, NULL)) {
3439+
if (info.seq != dumper->cur_seq) {
3440+
/* messages are gone, move to first available one */
3441+
dumper->cur_seq = info.seq;
3442+
}
34353443
}
34363444

34373445
/* last entry */

kernel/printk/printk_ringbuffer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ _DEFINE_PRINTKRB(name, descbits, avgtextbits, &_##name##_text[0])
287287
/* Writer Interface */
288288

289289
/**
290-
* prb_rec_init_wd() - Initialize a buffer for writing records.
290+
* prb_rec_init_wr() - Initialize a buffer for writing records.
291291
*
292292
* @r: The record to initialize.
293293
* @text_buf_size: The needed text buffer size.

kernel/printk/printk_safe.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ struct printk_safe_seq_buf {
4545
static DEFINE_PER_CPU(struct printk_safe_seq_buf, safe_print_seq);
4646
static DEFINE_PER_CPU(int, printk_context);
4747

48+
static DEFINE_RAW_SPINLOCK(safe_read_lock);
49+
4850
#ifdef CONFIG_PRINTK_NMI
4951
static DEFINE_PER_CPU(struct printk_safe_seq_buf, nmi_print_seq);
5052
#endif
@@ -180,8 +182,6 @@ static void report_message_lost(struct printk_safe_seq_buf *s)
180182
*/
181183
static void __printk_safe_flush(struct irq_work *work)
182184
{
183-
static raw_spinlock_t read_lock =
184-
__RAW_SPIN_LOCK_INITIALIZER(read_lock);
185185
struct printk_safe_seq_buf *s =
186186
container_of(work, struct printk_safe_seq_buf, work);
187187
unsigned long flags;
@@ -195,7 +195,7 @@ static void __printk_safe_flush(struct irq_work *work)
195195
* different CPUs. This is especially important when printing
196196
* a backtrace.
197197
*/
198-
raw_spin_lock_irqsave(&read_lock, flags);
198+
raw_spin_lock_irqsave(&safe_read_lock, flags);
199199

200200
i = 0;
201201
more:
@@ -232,7 +232,7 @@ static void __printk_safe_flush(struct irq_work *work)
232232

233233
out:
234234
report_message_lost(s);
235-
raw_spin_unlock_irqrestore(&read_lock, flags);
235+
raw_spin_unlock_irqrestore(&safe_read_lock, flags);
236236
}
237237

238238
/**
@@ -278,6 +278,14 @@ void printk_safe_flush_on_panic(void)
278278
raw_spin_lock_init(&logbuf_lock);
279279
}
280280

281+
if (raw_spin_is_locked(&safe_read_lock)) {
282+
if (num_online_cpus() > 1)
283+
return;
284+
285+
debug_locks_off();
286+
raw_spin_lock_init(&safe_read_lock);
287+
}
288+
281289
printk_safe_flush();
282290
}
283291

lib/test_bitmap.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616

1717
#include "../tools/testing/selftests/kselftest_module.h"
1818

19-
static unsigned total_tests __initdata;
20-
static unsigned failed_tests __initdata;
19+
KSTM_MODULE_GLOBALS();
2120

2221
static char pbl_buffer[PAGE_SIZE] __initdata;
2322

lib/test_printf.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@
3030
#define PAD_SIZE 16
3131
#define FILL_CHAR '$'
3232

33-
static unsigned total_tests __initdata;
34-
static unsigned failed_tests __initdata;
33+
KSTM_MODULE_GLOBALS();
34+
3535
static char *test_buffer __initdata;
3636
static char *alloced_buffer __initdata;
3737

38+
extern bool no_hash_pointers;
39+
3840
static int __printf(4, 0) __init
3941
do_test(int bufsize, const char *expect, int elen,
4042
const char *fmt, va_list ap)
@@ -301,6 +303,12 @@ plain(void)
301303
{
302304
int err;
303305

306+
if (no_hash_pointers) {
307+
pr_warn("skipping plain 'p' tests");
308+
skipped_tests += 2;
309+
return;
310+
}
311+
304312
err = plain_hash();
305313
if (err) {
306314
pr_warn("plain 'p' does not appear to be hashed\n");

lib/vsprintf.c

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2090,6 +2090,32 @@ char *fwnode_string(char *buf, char *end, struct fwnode_handle *fwnode,
20902090
return widen_string(buf, buf - buf_start, end, spec);
20912091
}
20922092

2093+
/* Disable pointer hashing if requested */
2094+
bool no_hash_pointers __ro_after_init;
2095+
EXPORT_SYMBOL_GPL(no_hash_pointers);
2096+
2097+
static int __init no_hash_pointers_enable(char *str)
2098+
{
2099+
no_hash_pointers = true;
2100+
2101+
pr_warn("**********************************************************\n");
2102+
pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n");
2103+
pr_warn("** **\n");
2104+
pr_warn("** This system shows unhashed kernel memory addresses **\n");
2105+
pr_warn("** via the console, logs, and other interfaces. This **\n");
2106+
pr_warn("** might reduce the security of your system. **\n");
2107+
pr_warn("** **\n");
2108+
pr_warn("** If you see this message and you are not debugging **\n");
2109+
pr_warn("** the kernel, report this immediately to your system **\n");
2110+
pr_warn("** administrator! **\n");
2111+
pr_warn("** **\n");
2112+
pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n");
2113+
pr_warn("**********************************************************\n");
2114+
2115+
return 0;
2116+
}
2117+
early_param("no_hash_pointers", no_hash_pointers_enable);
2118+
20932119
/*
20942120
* Show a '%p' thing. A kernel extension is that the '%p' is followed
20952121
* by an extra set of alphanumeric characters that are extended format
@@ -2297,8 +2323,14 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
22972323
}
22982324
}
22992325

2300-
/* default is to _not_ leak addresses, hash before printing */
2301-
return ptr_to_id(buf, end, ptr, spec);
2326+
/*
2327+
* default is to _not_ leak addresses, so hash before printing,
2328+
* unless no_hash_pointers is specified on the command line.
2329+
*/
2330+
if (unlikely(no_hash_pointers))
2331+
return pointer_string(buf, end, ptr, spec);
2332+
else
2333+
return ptr_to_id(buf, end, ptr, spec);
23022334
}
23032335

23042336
/*

tools/testing/selftests/kselftest_module.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111

1212
#define KSTM_MODULE_GLOBALS() \
1313
static unsigned int total_tests __initdata; \
14-
static unsigned int failed_tests __initdata
14+
static unsigned int failed_tests __initdata; \
15+
static unsigned int skipped_tests __initdata
1516

1617
#define KSTM_CHECK_ZERO(x) do { \
1718
total_tests++; \
@@ -21,11 +22,16 @@ static unsigned int failed_tests __initdata
2122
} \
2223
} while (0)
2324

24-
static inline int kstm_report(unsigned int total_tests, unsigned int failed_tests)
25+
static inline int kstm_report(unsigned int total_tests, unsigned int failed_tests,
26+
unsigned int skipped_tests)
2527
{
26-
if (failed_tests == 0)
27-
pr_info("all %u tests passed\n", total_tests);
28-
else
28+
if (failed_tests == 0) {
29+
if (skipped_tests) {
30+
pr_info("skipped %u tests\n", skipped_tests);
31+
pr_info("remaining %u tests passed\n", total_tests);
32+
} else
33+
pr_info("all %u tests passed\n", total_tests);
34+
} else
2935
pr_warn("failed %u out of %u tests\n", failed_tests, total_tests);
3036

3137
return failed_tests ? -EINVAL : 0;
@@ -36,7 +42,7 @@ static int __init __module##_init(void) \
3642
{ \
3743
pr_info("loaded.\n"); \
3844
selftest(); \
39-
return kstm_report(total_tests, failed_tests); \
45+
return kstm_report(total_tests, failed_tests, skipped_tests); \
4046
} \
4147
static void __exit __module##_exit(void) \
4248
{ \

0 commit comments

Comments
 (0)