aboutsummaryrefslogtreecommitdiffstats
diff options
authorMark Brown <broonie@kernel.org>2026-05-29 18:09:33 +0100
committerMark Brown <broonie@kernel.org>2026-05-29 18:09:33 +0100
commit0e0824ca26a57bba404a6bf2fd63282e8f1ad757 (patch)
treef019c8bb449716026a49b09e165aa928fd129359
parent5f74287f42d47e9acdc9a987518387125f046527 (diff)
parent3334bbb60518582c3b430ce98f74d62cf9d5590d (diff)
downloadlinux-next-history-0e0824ca26a57bba404a6bf2fd63282e8f1ad757.tar.gz
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git
-rw-r--r--lib/tests/printf_kunit.c22
-rw-r--r--lib/vsprintf.c60
2 files changed, 53 insertions, 29 deletions
diff --git a/lib/tests/printf_kunit.c b/lib/tests/printf_kunit.c
index bb70b9cddadd8..58e639b01e836 100644
--- a/lib/tests/printf_kunit.c
+++ b/lib/tests/printf_kunit.c
@@ -319,7 +319,27 @@ symbol_ptr(struct kunit *kunittest)
static void
kernel_ptr(struct kunit *kunittest)
{
- /* We can't test this without access to kptr_restrict. */
+ switch (kptr_restrict) {
+ case 0:
+ if (no_hash_pointers) {
+ test(PTR_STR, "%pK", PTR);
+ } else {
+ char buf[PLAIN_BUF_SIZE];
+
+ plain_hash_to_buffer(kunittest, PTR, buf, PLAIN_BUF_SIZE);
+ /* %pK behaves the same as hashing */
+ test(buf, "%pK", PTR);
+ }
+ break;
+ case 1:
+ /* The KUnit kthread has all capabilities, including CAP_SYSLOG */
+ test(PTR_STR, "%pK", PTR);
+ break;
+ case 2:
+ default:
+ test(ZEROS "00000000", "%pK", PTR);
+ break;
+ }
}
static void
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index a6169e9bcdc9e..a3017bc58986f 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -59,7 +59,7 @@
/* Disable pointer hashing if requested */
bool no_hash_pointers __ro_after_init;
-EXPORT_SYMBOL_GPL(no_hash_pointers);
+EXPORT_SYMBOL_FOR_MODULES(no_hash_pointers, "printf_kunit");
/*
* Hashed pointers policy selected by "hash_pointers=..." boot param
@@ -850,6 +850,7 @@ static char *default_pointer(char *buf, char *end, const void *ptr,
}
int kptr_restrict __read_mostly;
+EXPORT_SYMBOL_FOR_MODULES(kptr_restrict, "printf_kunit");
static noinline_for_stack
char *restricted_pointer(char *buf, char *end, const void *ptr,
@@ -2354,13 +2355,13 @@ static int __init hash_pointers_mode_parse(char *str)
if (!str) {
pr_warn("Hash pointers mode empty; falling back to auto.\n");
hash_pointers_mode = HASH_PTR_AUTO;
- } else if (strncmp(str, "auto", 4) == 0) {
+ } else if (strcmp(str, "auto") == 0) {
pr_info("Hash pointers mode set to auto.\n");
hash_pointers_mode = HASH_PTR_AUTO;
- } else if (strncmp(str, "never", 5) == 0) {
+ } else if (strcmp(str, "never") == 0) {
pr_info("Hash pointers mode set to never.\n");
hash_pointers_mode = HASH_PTR_NEVER;
- } else if (strncmp(str, "always", 6) == 0) {
+ } else if (strcmp(str, "always") == 0) {
pr_info("Hash pointers mode set to always.\n");
hash_pointers_mode = HASH_PTR_ALWAYS;
} else {
@@ -2633,6 +2634,18 @@ static unsigned char spec_flag(unsigned char c)
return (c < sizeof(spec_flag_array)) ? spec_flag_array[c] : 0;
}
+static void set_field_width(struct printf_spec *spec, int width)
+{
+ spec->field_width = clamp(width, -FIELD_WIDTH_MAX, FIELD_WIDTH_MAX);
+ WARN_ONCE(spec->field_width != width, "field width %d out of range", width);
+}
+
+static void set_precision(struct printf_spec *spec, int prec)
+{
+ spec->precision = clamp(prec, 0, PRECISION_MAX);
+ WARN_ONCE(spec->precision < prec, "precision %d too large", prec);
+}
+
/*
* Helper function to decode printf style format.
* Each call decode a token from the format and return the
@@ -2703,7 +2716,7 @@ struct fmt format_decode(struct fmt fmt, struct printf_spec *spec)
spec->field_width = -1;
if (isdigit(*fmt.str))
- spec->field_width = skip_atoi(&fmt.str);
+ set_field_width(spec, skip_atoi(&fmt.str));
else if (unlikely(*fmt.str == '*')) {
/* it's the next argument */
fmt.state = FORMAT_STATE_WIDTH;
@@ -2717,9 +2730,7 @@ precision:
if (unlikely(*fmt.str == '.')) {
fmt.str++;
if (isdigit(*fmt.str)) {
- spec->precision = skip_atoi(&fmt.str);
- if (spec->precision < 0)
- spec->precision = 0;
+ set_precision(spec, skip_atoi(&fmt.str));
} else if (*fmt.str == '*') {
/* it's the next argument */
fmt.state = FORMAT_STATE_PRECISION;
@@ -2792,24 +2803,6 @@ qualifier:
return fmt;
}
-static void
-set_field_width(struct printf_spec *spec, int width)
-{
- spec->field_width = width;
- if (WARN_ONCE(spec->field_width != width, "field width %d too large", width)) {
- spec->field_width = clamp(width, -FIELD_WIDTH_MAX, FIELD_WIDTH_MAX);
- }
-}
-
-static void
-set_precision(struct printf_spec *spec, int prec)
-{
- spec->precision = prec;
- if (WARN_ONCE(spec->precision != prec, "precision %d too large", prec)) {
- spec->precision = clamp(prec, 0, PRECISION_MAX);
- }
-}
-
/*
* Turn a 1/2/4-byte value into a 64-bit one for printing: truncate
* as necessary and deal with signedness.
@@ -2857,6 +2850,7 @@ static unsigned long long convert_num_spec(unsigned int val, int size, struct pr
int vsnprintf(char *buf, size_t size, const char *fmt_str, va_list args)
{
char *str, *end;
+ size_t ret_size;
struct printf_spec spec = {0};
struct fmt fmt = {
.str = fmt_str,
@@ -2976,8 +2970,12 @@ out:
}
/* the trailing null byte doesn't count towards the total */
- return str-buf;
+ ret_size = str - buf;
+ /* Make sure the return value is within the positive integer range */
+ if (WARN_ON_ONCE(ret_size > INT_MAX))
+ ret_size = INT_MAX;
+ return ret_size;
}
EXPORT_SYMBOL(vsnprintf);
@@ -3281,6 +3279,7 @@ int bstr_printf(char *buf, size_t size, const char *fmt_str, const u32 *bin_buf)
struct printf_spec spec = {0};
char *str, *end;
const char *args = (const char *)bin_buf;
+ size_t ret_size;
if (WARN_ON_ONCE(size > INT_MAX))
return 0;
@@ -3429,7 +3428,12 @@ out:
#undef get_arg
/* the trailing null byte doesn't count towards the total */
- return str - buf;
+ ret_size = str - buf;
+
+ /* Make sure the return value is within the positive integer range */
+ if (WARN_ON_ONCE(ret_size > INT_MAX))
+ ret_size = INT_MAX;
+ return ret_size;
}
EXPORT_SYMBOL_GPL(bstr_printf);