Skip to content

Commit 59f8bcc

Browse files
jognesspmladek
authored andcommitted
printk: avoid and/or handle record truncation
If a reader provides a buffer that is smaller than the message text, the @text_len field of @info will have a value larger than the buffer size. If readers blindly read @text_len bytes of data without checking the size, they will read beyond their buffer. Add this check to record_print_text() to properly recognize when such truncation has occurred. Add a maximum size argument to the ringbuffer function to extend records so that records can not be created that are larger than the buffer size of readers. When extending records (LOG_CONT), do not extend records beyond LOG_LINE_MAX since that is the maximum size available in the buffers used by consoles and syslog. Fixes: f5f022e ("printk: reimplement log_cont using record extension") Reported-by: Marek Szyprowski <m.szyprowski@samsung.com> 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/20200930090134.8723-2-john.ogness@linutronix.de
1 parent f35efc7 commit 59f8bcc

3 files changed

Lines changed: 19 additions & 4 deletions

File tree

kernel/printk/printk.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1349,6 +1349,13 @@ static size_t record_print_text(struct printk_record *r, bool syslog,
13491349
size_t len = 0;
13501350
char *next;
13511351

1352+
/*
1353+
* If the message was truncated because the buffer was not large
1354+
* enough, treat the available text as if it were the full text.
1355+
*/
1356+
if (text_len > buf_size)
1357+
text_len = buf_size;
1358+
13521359
prefix_len = info_print_prefix(r->info, syslog, time, prefix);
13531360

13541361
/*
@@ -1903,7 +1910,7 @@ static size_t log_output(int facility, int level, enum log_flags lflags,
19031910
struct printk_record r;
19041911

19051912
prb_rec_init_wr(&r, text_len);
1906-
if (prb_reserve_in_last(&e, prb, &r, caller_id)) {
1913+
if (prb_reserve_in_last(&e, prb, &r, caller_id, LOG_LINE_MAX)) {
19071914
memcpy(&r.text_buf[r.info->text_len], text, text_len);
19081915
r.info->text_len += text_len;
19091916
if (lflags & LOG_NEWLINE) {

kernel/printk/printk_ringbuffer.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@
202202
* // specify additional 5 bytes text space to extend
203203
* prb_rec_init_wr(&r, 5);
204204
*
205-
* if (prb_reserve_in_last(&e, &test_rb, &r, printk_caller_id())) {
205+
* // try to extend, but only if it does not exceed 32 bytes
206+
* if (prb_reserve_in_last(&e, &test_rb, &r, printk_caller_id()), 32) {
206207
* snprintf(&r.text_buf[r.info->text_len],
207208
* r.text_buf_size - r.info->text_len, "hello");
208209
*
@@ -1309,6 +1310,7 @@ static struct prb_desc *desc_reopen_last(struct prb_desc_ring *desc_ring,
13091310
* @rb: The ringbuffer to re-reserve and extend data in.
13101311
* @r: The record structure to allocate buffers for.
13111312
* @caller_id: The caller ID of the caller (reserving writer).
1313+
* @max_size: Fail if the extended size would be greater than this.
13121314
*
13131315
* This is the public function available to writers to re-reserve and extend
13141316
* data.
@@ -1343,7 +1345,7 @@ static struct prb_desc *desc_reopen_last(struct prb_desc_ring *desc_ring,
13431345
* @r->info->text_len after concatenating.
13441346
*/
13451347
bool prb_reserve_in_last(struct prb_reserved_entry *e, struct printk_ringbuffer *rb,
1346-
struct printk_record *r, u32 caller_id)
1348+
struct printk_record *r, u32 caller_id, unsigned int max_size)
13471349
{
13481350
struct prb_desc_ring *desc_ring = &rb->desc_ring;
13491351
struct printk_info *info;
@@ -1389,6 +1391,9 @@ bool prb_reserve_in_last(struct prb_reserved_entry *e, struct printk_ringbuffer
13891391
if (!data_check_size(&rb->text_data_ring, r->text_buf_size))
13901392
goto fail;
13911393

1394+
if (r->text_buf_size > max_size)
1395+
goto fail;
1396+
13921397
r->text_buf = data_alloc(rb, &rb->text_data_ring, r->text_buf_size,
13931398
&d->text_blk_lpos, id);
13941399
} else {
@@ -1410,6 +1415,9 @@ bool prb_reserve_in_last(struct prb_reserved_entry *e, struct printk_ringbuffer
14101415
if (!data_check_size(&rb->text_data_ring, r->text_buf_size))
14111416
goto fail;
14121417

1418+
if (r->text_buf_size > max_size)
1419+
goto fail;
1420+
14131421
r->text_buf = data_realloc(rb, &rb->text_data_ring, r->text_buf_size,
14141422
&d->text_blk_lpos, id);
14151423
}

kernel/printk/printk_ringbuffer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ static inline void prb_rec_init_wr(struct printk_record *r,
303303
bool prb_reserve(struct prb_reserved_entry *e, struct printk_ringbuffer *rb,
304304
struct printk_record *r);
305305
bool prb_reserve_in_last(struct prb_reserved_entry *e, struct printk_ringbuffer *rb,
306-
struct printk_record *r, u32 caller_id);
306+
struct printk_record *r, u32 caller_id, unsigned int max_size);
307307
void prb_commit(struct prb_reserved_entry *e);
308308
void prb_final_commit(struct prb_reserved_entry *e);
309309

0 commit comments

Comments
 (0)