diff options
author | John Ogness <john.ogness@linutronix.de> | 2021-03-03 11:15:16 +0100 |
---|---|---|
committer | Petr Mladek <pmladek@suse.com> | 2021-03-08 11:42:50 +0100 |
commit | bb07b16c44b2c6ddbafa44bb06454719002e828e (patch) | |
tree | 5089091de3ff554808c411bd584f2d938a3f29a2 /kernel | |
parent | 40ddbbac7f16eb91f9f2bbc414f283102052ce14 (diff) |
printk: limit second loop of syslog_print_all
The second loop of syslog_print_all() subtracts lengths that were
added in the first loop. With commit b031a684bfd0 ("printk: remove
logbuf_lock writer-protection of ringbuffer") it is possible that
records are (over)written during syslog_print_all(). This allows the
possibility of the second loop subtracting lengths that were never
added in the first loop.
This situation can result in syslog_print_all() filling the buffer
starting from a later record, even though there may have been room
to fit the earlier record(s) as well.
Fixes: b031a684bfd0 ("printk: remove logbuf_lock writer-protection of ringbuffer")
Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20210303101528.29901-4-john.ogness@linutronix.de
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/printk/printk.c | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 575a34b88936..77ae2704e979 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1494,6 +1494,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear) struct printk_info info; unsigned int line_count; struct printk_record r; + u64 max_seq; char *text; int len = 0; u64 seq; @@ -1512,9 +1513,15 @@ static int syslog_print_all(char __user *buf, int size, bool clear) prb_for_each_info(clear_seq, prb, seq, &info, &line_count) len += get_record_print_text_size(&info, line_count, true, time); + /* + * Set an upper bound for the next loop to avoid subtracting lengths + * that were never added. + */ + max_seq = seq; + /* move first record forward until length fits into the buffer */ prb_for_each_info(clear_seq, prb, seq, &info, &line_count) { - if (len <= size) + if (len <= size || info.seq >= max_seq) break; len -= get_record_print_text_size(&info, line_count, true, time); } |