Re: [PATCH] trace/writeback: fix Wstringop-truncation warnings
From: Qian Cai
Date: Thu Jul 18 2019 - 16:12:02 EST
> On Jul 16, 2019, at 5:03 PM, Steven Rostedt <rostedt@xxxxxxxxxxx> wrote:
>
> On Fri, 12 Jul 2019 12:14:47 -0400
> Qian Cai <cai@xxxxxx> wrote:
>
>> There are many of those warnings.
>>
>> In file included from ./arch/powerpc/include/asm/paca.h:15,
>> from ./arch/powerpc/include/asm/current.h:13,
>> from ./include/linux/thread_info.h:21,
>> from ./include/asm-generic/preempt.h:5,
>> from ./arch/powerpc/include/generated/asm/preempt.h:1,
>> from ./include/linux/preempt.h:78,
>> from ./include/linux/spinlock.h:51,
>> from fs/fs-writeback.c:19:
>> In function 'strncpy',
>> inlined from 'perf_trace_writeback_page_template' at
>> ./include/trace/events/writeback.h:56:1:
>> ./include/linux/string.h:260:9: warning: '__builtin_strncpy' specified
>> bound 32 equals destination size [-Wstringop-truncation]
>> return __builtin_strncpy(p, q, size);
>> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>
>> Fix it by using strlcpy() which will always be NUL-terminated instead of
>> strncpy(). strlcpy() has already been used at some places in this file.
>>
>> Fixes: 455b2864686d ("writeback: Initial tracing support")
>> Fixes: 028c2dd184c0 ("writeback: Add tracing to balance_dirty_pages")
>> Fixes: e84d0a4f8e39 ("writeback: trace event writeback_queue_io")
>> Fixes: b48c104d2211 ("writeback: trace event bdi_dirty_ratelimit")
>> Fixes: cc1676d917f3 ("writeback: Move requeueing when I_SYNC set to writeback_sb_inodes()")
>> Fixes: 9fb0a7da0c52 ("writeback: add more tracepoints")
>>
>> Signed-off-by: Qian Cai <cai@xxxxxx>
>> ---
>> include/trace/events/writeback.h | 20 ++++++++++----------
>> 1 file changed, 10 insertions(+), 10 deletions(-)
>>
>> diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h
>> index aa7f3aeac740..8e3b3c4fd964 100644
>> --- a/include/trace/events/writeback.h
>> +++ b/include/trace/events/writeback.h
>> @@ -66,7 +66,7 @@
>> ),
>>
>> TP_fast_assign(
>> - strncpy(__entry->name,
>> + strlcpy(__entry->name,
>> mapping ? dev_name(inode_to_bdi(mapping->host)->dev) : "(unknown)", 32);
>
>
> Not sure this is an issue or not, but although the fix looks legit (in
> case a string is more that 31 bytes), strlcpy() does not pad the rest
> of the string like strncpy() does. This means we can possibly leak data
> through the ring buffer.
>
> This may not be an issue as ftrace can only be used by a super user
> account, but this code can also be used by perf. If it is possible for
> a non admin account to enable these events through perf, then there is
> a case of data leak.
>
> Again, it may not be a big issue, but I'm just letting people know.
>
> Note, this needs to go through the maintainer of the writeback.h, who
> are those that created it, not the tracing maintainers.
Adding Jens. He handled those patches in the past. The original patch is here,
https://lkml.kernel.org/lkml/1562948087-5374-1-git-send-email-cai@xxxxxx/
>
> -- Steve
>
>
>> __entry->ino = mapping ? mapping->host->i_ino : 0;
>> __entry->index = page->index;
>> @@ -110,7 +110,7 @@
>> struct backing_dev_info *bdi = inode_to_bdi(inode);
>>
>> /* may be called for files on pseudo FSes w/ unregistered bdi */
>> - strncpy(__entry->name,
>> + strlcpy(__entry->name,
>> bdi->dev ? dev_name(bdi->dev) : "(unknown)", 32);
>> __entry->ino = inode->i_ino;
>> __entry->state = inode->i_state;
>> @@ -190,7 +190,7 @@ static inline unsigned int __trace_wbc_assign_cgroup(struct writeback_control *w
>> ),
>>
>> TP_fast_assign(
>> - strncpy(__entry->name,
>> + strlcpy(__entry->name,
>> dev_name(inode_to_bdi(inode)->dev), 32);
>> __entry->ino = inode->i_ino;
>> __entry->sync_mode = wbc->sync_mode;
>> @@ -234,7 +234,7 @@ static inline unsigned int __trace_wbc_assign_cgroup(struct writeback_control *w
>> __field(unsigned int, cgroup_ino)
>> ),
>> TP_fast_assign(
>> - strncpy(__entry->name,
>> + strlcpy(__entry->name,
>> wb->bdi->dev ? dev_name(wb->bdi->dev) : "(unknown)", 32);
>> __entry->nr_pages = work->nr_pages;
>> __entry->sb_dev = work->sb ? work->sb->s_dev : 0;
>> @@ -288,7 +288,7 @@ static inline unsigned int __trace_wbc_assign_cgroup(struct writeback_control *w
>> __field(unsigned int, cgroup_ino)
>> ),
>> TP_fast_assign(
>> - strncpy(__entry->name, dev_name(wb->bdi->dev), 32);
>> + strlcpy(__entry->name, dev_name(wb->bdi->dev), 32);
>> __entry->cgroup_ino = __trace_wb_assign_cgroup(wb);
>> ),
>> TP_printk("bdi %s: cgroup_ino=%u",
>> @@ -310,7 +310,7 @@ static inline unsigned int __trace_wbc_assign_cgroup(struct writeback_control *w
>> __array(char, name, 32)
>> ),
>> TP_fast_assign(
>> - strncpy(__entry->name, dev_name(bdi->dev), 32);
>> + strlcpy(__entry->name, dev_name(bdi->dev), 32);
>> ),
>> TP_printk("bdi %s",
>> __entry->name
>> @@ -335,7 +335,7 @@ static inline unsigned int __trace_wbc_assign_cgroup(struct writeback_control *w
>> ),
>>
>> TP_fast_assign(
>> - strncpy(__entry->name, dev_name(bdi->dev), 32);
>> + strlcpy(__entry->name, dev_name(bdi->dev), 32);
>> __entry->nr_to_write = wbc->nr_to_write;
>> __entry->pages_skipped = wbc->pages_skipped;
>> __entry->sync_mode = wbc->sync_mode;
>> @@ -386,7 +386,7 @@ static inline unsigned int __trace_wbc_assign_cgroup(struct writeback_control *w
>> ),
>> TP_fast_assign(
>> unsigned long *older_than_this = work->older_than_this;
>> - strncpy(__entry->name, dev_name(wb->bdi->dev), 32);
>> + strlcpy(__entry->name, dev_name(wb->bdi->dev), 32);
>> __entry->older = older_than_this ? *older_than_this : 0;
>> __entry->age = older_than_this ?
>> (jiffies - *older_than_this) * 1000 / HZ : -1;
>> @@ -597,7 +597,7 @@ static inline unsigned int __trace_wbc_assign_cgroup(struct writeback_control *w
>> ),
>>
>> TP_fast_assign(
>> - strncpy(__entry->name,
>> + strlcpy(__entry->name,
>> dev_name(inode_to_bdi(inode)->dev), 32);
>> __entry->ino = inode->i_ino;
>> __entry->state = inode->i_state;
>> @@ -671,7 +671,7 @@ static inline unsigned int __trace_wbc_assign_cgroup(struct writeback_control *w
>> ),
>>
>> TP_fast_assign(
>> - strncpy(__entry->name,
>> + strlcpy(__entry->name,
>> dev_name(inode_to_bdi(inode)->dev), 32);
>> __entry->ino = inode->i_ino;
>> __entry->state = inode->i_state;