Skip to content

Commit 48e3694

Browse files
committed
Merge tag 'printk-for-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux
Pull printk updates from Petr Mladek: - Add KUnit test for the printk ring buffer - Fix the check of the maximal record size which is allowed to be stored into the printk ring buffer. It prevents corruptions of the ring buffer. Note that printk() is on the safe side. The messages are limited by 1kB buffer and are always small enough for the minimal log buffer size 4kB, see CONFIG_LOG_BUF_SHIFT definition. * tag 'printk-for-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux: printk: ringbuffer: Fix data block max size check printk: kunit: support offstack cpumask printk: kunit: Fix __counted_by() in struct prbtest_rbdata printk: ringbuffer: Explain why the KUnit test ignores failed writes printk: ringbuffer: Add KUnit test
2 parents b410484 + 7a75a5d commit 48e3694

File tree

5 files changed

+378
-14
lines changed

5 files changed

+378
-14
lines changed

init/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,6 +1710,18 @@ config PRINTK
17101710
very difficult to diagnose system problems, saying N here is
17111711
strongly discouraged.
17121712

1713+
config PRINTK_RINGBUFFER_KUNIT_TEST
1714+
tristate "KUnit Test for the printk ringbuffer" if !KUNIT_ALL_TESTS
1715+
depends on PRINTK && KUNIT
1716+
default KUNIT_ALL_TESTS
1717+
help
1718+
This builds the printk ringbuffer KUnit test suite.
1719+
1720+
For more information on KUnit and unit tests in general, please refer
1721+
to the KUnit documentation.
1722+
1723+
If unsure, say N.
1724+
17131725
config BUG
17141726
bool "BUG() support" if EXPERT
17151727
default y

kernel/printk/.kunitconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CONFIG_KUNIT=y
2+
CONFIG_PRINTK=y
3+
CONFIG_PRINTK_RINGBUFFER_KUNIT_TEST=y

kernel/printk/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ obj-$(CONFIG_PRINTK_INDEX) += index.o
77
obj-$(CONFIG_PRINTK) += printk_support.o
88
printk_support-y := printk_ringbuffer.o
99
printk_support-$(CONFIG_SYSCTL) += sysctl.o
10+
11+
obj-$(CONFIG_PRINTK_RINGBUFFER_KUNIT_TEST) += printk_ringbuffer_kunit_test.o

kernel/printk/printk_ringbuffer.c

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0
22

3+
#include <kunit/visibility.h>
34
#include <linux/kernel.h>
45
#include <linux/irqflags.h>
56
#include <linux/string.h>
@@ -393,25 +394,21 @@ static unsigned int to_blk_size(unsigned int size)
393394
* Sanity checker for reserve size. The ringbuffer code assumes that a data
394395
* block does not exceed the maximum possible size that could fit within the
395396
* ringbuffer. This function provides that basic size check so that the
396-
* assumption is safe.
397+
* assumption is safe. In particular, it guarantees that data_push_tail() will
398+
* never attempt to push the tail beyond the head.
397399
*/
398400
static bool data_check_size(struct prb_data_ring *data_ring, unsigned int size)
399401
{
400-
struct prb_data_block *db = NULL;
401-
402+
/* Data-less blocks take no space. */
402403
if (size == 0)
403404
return true;
404405

405406
/*
406-
* Ensure the alignment padded size could possibly fit in the data
407-
* array. The largest possible data block must still leave room for
408-
* at least the ID of the next block.
407+
* If data blocks were allowed to be larger than half the data ring
408+
* size, a wrapping data block could require more space than the full
409+
* ringbuffer.
409410
*/
410-
size = to_blk_size(size);
411-
if (size > DATA_SIZE(data_ring) - sizeof(db->id))
412-
return false;
413-
414-
return true;
411+
return to_blk_size(size) <= DATA_SIZE(data_ring) / 2;
415412
}
416413

417414
/* Query the state of a descriptor. */
@@ -1051,8 +1048,17 @@ static char *data_alloc(struct printk_ringbuffer *rb, unsigned int size,
10511048
do {
10521049
next_lpos = get_next_lpos(data_ring, begin_lpos, size);
10531050

1054-
if (!data_push_tail(rb, next_lpos - DATA_SIZE(data_ring))) {
1055-
/* Failed to allocate, specify a data-less block. */
1051+
/*
1052+
* data_check_size() prevents data block allocation that could
1053+
* cause illegal ringbuffer states. But double check that the
1054+
* used space will not be bigger than the ring buffer. Wrapped
1055+
* messages need to reserve more space, see get_next_lpos().
1056+
*
1057+
* Specify a data-less block when the check or the allocation
1058+
* fails.
1059+
*/
1060+
if (WARN_ON_ONCE(next_lpos - begin_lpos > DATA_SIZE(data_ring)) ||
1061+
!data_push_tail(rb, next_lpos - DATA_SIZE(data_ring))) {
10561062
blk_lpos->begin = FAILED_LPOS;
10571063
blk_lpos->next = FAILED_LPOS;
10581064
return NULL;
@@ -1140,8 +1146,18 @@ static char *data_realloc(struct printk_ringbuffer *rb, unsigned int size,
11401146
return &blk->data[0];
11411147
}
11421148

1143-
if (!data_push_tail(rb, next_lpos - DATA_SIZE(data_ring)))
1149+
/*
1150+
* data_check_size() prevents data block reallocation that could
1151+
* cause illegal ringbuffer states. But double check that the
1152+
* new used space will not be bigger than the ring buffer. Wrapped
1153+
* messages need to reserve more space, see get_next_lpos().
1154+
*
1155+
* Specify failure when the check or the allocation fails.
1156+
*/
1157+
if (WARN_ON_ONCE(next_lpos - blk_lpos->begin > DATA_SIZE(data_ring)) ||
1158+
!data_push_tail(rb, next_lpos - DATA_SIZE(data_ring))) {
11441159
return NULL;
1160+
}
11451161

11461162
/* The memory barrier involvement is the same as data_alloc:A. */
11471163
if (!atomic_long_try_cmpxchg(&data_ring->head_lpos, &head_lpos,
@@ -1685,6 +1701,7 @@ bool prb_reserve(struct prb_reserved_entry *e, struct printk_ringbuffer *rb,
16851701
memset(r, 0, sizeof(*r));
16861702
return false;
16871703
}
1704+
EXPORT_SYMBOL_IF_KUNIT(prb_reserve);
16881705

16891706
/* Commit the data (possibly finalizing it) and restore interrupts. */
16901707
static void _prb_commit(struct prb_reserved_entry *e, unsigned long state_val)
@@ -1759,6 +1776,7 @@ void prb_commit(struct prb_reserved_entry *e)
17591776
if (head_id != e->id)
17601777
desc_make_final(e->rb, e->id);
17611778
}
1779+
EXPORT_SYMBOL_IF_KUNIT(prb_commit);
17621780

17631781
/**
17641782
* prb_final_commit() - Commit and finalize (previously reserved) data to
@@ -2184,6 +2202,7 @@ bool prb_read_valid(struct printk_ringbuffer *rb, u64 seq,
21842202
{
21852203
return _prb_read_valid(rb, &seq, r, NULL);
21862204
}
2205+
EXPORT_SYMBOL_IF_KUNIT(prb_read_valid);
21872206

21882207
/**
21892208
* prb_read_valid_info() - Non-blocking read of meta data for a requested
@@ -2333,6 +2352,7 @@ void prb_init(struct printk_ringbuffer *rb,
23332352
infos[0].seq = -(u64)_DESCS_COUNT(descbits);
23342353
infos[_DESCS_COUNT(descbits) - 1].seq = 0;
23352354
}
2355+
EXPORT_SYMBOL_IF_KUNIT(prb_init);
23362356

23372357
/**
23382358
* prb_record_text_space() - Query the full actual used ringbuffer space for

0 commit comments

Comments
 (0)