On Sat 2018-11-24 23:28:36, Tetsuo Handa wrote:
> Since /sys/module/printk/parameters/time can change from N to Y between
> "msg_print_text() called print_prefix() with buf == NULL" and
> "msg_print_text() again calls print_prefix() with buf != NULL", it is not
> safe for print_time() to unconditionally return 0 if printk_time == false.
> 
> But print_prefix() is called by only msg_print_text(), and print_prefix()
> is called once more for calculating output length of prefix, and there is
> no need to recalculate it when one log entry contains multiple lines.
> 
> Since max output length for syslog marker and timestamp are known to be
> small enough, let's close this race by deduplicating print_prefix() calls.
> 
> Signed-off-by: Tetsuo Handa <penguin-ker...@i-love.sakura.ne.jp>
> ---
>  kernel/printk/printk.c | 64 
> +++++++++++++++-----------------------------------
>  1 file changed, 19 insertions(+), 45 deletions(-)
> 
> diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
> index 1b2a029..eac4c80 100644
> --- a/kernel/printk/printk.c
> +++ b/kernel/printk/printk.c
> @@ -1213,50 +1213,26 @@ static inline void boot_delay_msec(int level)
>  static bool printk_time = IS_ENABLED(CONFIG_PRINTK_TIME);
>  module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
>  
> -static size_t print_time(u64 ts, char *buf)
> -{
> -     unsigned long rem_nsec;
> -
> -     if (!printk_time)
> -             return 0;
> -
> -     rem_nsec = do_div(ts, 1000000000);
> -
> -     if (!buf)
> -             return snprintf(NULL, 0, "[%5lu.000000] ", (unsigned long)ts);
> -
> -     return sprintf(buf, "[%5lu.%06lu] ",
> -                    (unsigned long)ts, rem_nsec / 1000);
> -}
> -
> -static size_t print_prefix(const struct printk_log *msg, bool syslog, char 
> *buf)
> -{
> -     size_t len = 0;
> -     unsigned int prefix = (msg->facility << 3) | msg->level;
> -
> -     if (syslog) {
> -             if (buf) {
> -                     len += sprintf(buf, "<%u>", prefix);
> -             } else {
> -                     len += 3;
> -                     if (prefix > 999)
> -                             len += 3;
> -                     else if (prefix > 99)
> -                             len += 2;
> -                     else if (prefix > 9)
> -                             len++;
> -             }
> -     }
> -
> -     len += print_time(msg->ts_nsec, buf ? buf + len : NULL);
> -     return len;
> -}
> -
>  static size_t msg_print_text(const struct printk_log *msg, bool syslog, char 
> *buf, size_t size)
>  {
>       const char *text = log_text(msg);
>       size_t text_size = msg->text_len;
>       size_t len = 0;
> +     char prefix[32]; /* "<2047>[18446744073.709551] " */
> +     size_t prefix_len = 0;
> +
> +     if (syslog)
> +             prefix_len += snprintf(prefix, sizeof(prefix), "<%u>",
> +                                    (msg->facility << 3) | msg->level);
> +     if (printk_time) {

This does not solve the real problem (buffer overflow) in
syslog_print_all() and kmsg_dump_get_buffer().

> +             u64 ts = msg->ts_nsec;
> +             unsigned long rem_nsec = do_div(ts, 1000000000);
> +
> +             prefix_len += snprintf(prefix + prefix_len,
> +                                    sizeof(prefix) - prefix_len,
> +                                    "[%5lu.%06lu] ", (unsigned long)ts,
> +                                    rem_nsec / 1000);
> +     }

I am not against removing some optimizations when buf == NULL.
It is a crazy code and the win is questionable. But the helper
functions still might make sense. msg_print_text() is complicated
enough as is.

Finally, I have mixed feelings about the memcpy() of the prefix.
On one hand, it makes some conditions a bit more readable.
On the other hand, it looks strange to copy it when most
messages have only one line and one prefix. It does not
look like a win in the end.

Let's fix the buffer overflow first and do any code clean up
later in a separate patch.

Best Regards,
Petr

Reply via email to