Bug 1295801

Summary: buffer overflow in refresh_proc_net_softnet
Product: Red Hat Enterprise Linux 6 Reporter: Miloš Prchlík <mprchlik>
Component: pcpAssignee: Nathan Scott <nathans>
Status: CLOSED ERRATA QA Contact: Miloš Prchlík <mprchlik>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 6.8CC: brolley, fche, lberk, mbenitez, mgoodwin
Target Milestone: rc   
Target Release: ---   
Hardware: i686   
OS: Unspecified   
Whiteboard:
Fixed In Version: pcp-3.10.9-3.el6 Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2016-05-10 21:13:24 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:

Description Miloš Prchlík 2016-01-05 13:46:38 UTC
Description of problem:

Running pminfo with specific arguments - I'm not sure if the actual code flow isn't influenced by the box pminfo runs on in this case - leads to buffer overflow, and pminfo is killed.

[root@sheep-2 ~]# pminfo -L -K clear -K add,60,/var/lib/pcp/pmdas/linux/pmda_linux.so,linux_init -f network.softnet.cpu_collision network.softnet.dropped network.softnet.flow_limit_count network.softnet.processed network.softnet.received_rps network.softnet.time_squeeze
*** buffer overflow detected ***: pminfo terminated
======= Backtrace: =========
/lib/libc.so.6(__fortify_fail+0x4d)[0x5a9e1d]
/lib/libc.so.6[0x5a7e5a]
/lib/libc.so.6[0x5a710a]
/var/lib/pcp/pmdas/linux/pmda_linux.so(+0x15c6d)[0x670c6d]
/var/lib/pcp/pmdas/linux/pmda_linux.so(+0x9f86)[0x664f86]
/var/lib/pcp/pmdas/linux/pmda_linux.so(+0xa27f)[0x66527f]
/usr/lib/libpcp.so.3(__pmFetchLocal+0x2e3)[0x5c4a263]
/usr/lib/libpcp.so.3(pmFetch+0x3d0)[0x5c22970]
pminfo[0x8049994]
pminfo[0x804a7e1]
/lib/libc.so.6(__libc_start_main+0xe6)[0x4c3d36]
pminfo[0x8048e21]
======= Memory map: ========
...
Aborted (core dumped)
[root@sheep-2 ~]# 


Using gdb to get further:


[root@sheep-2 ~]# gdb pminfo
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-83.el6)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /usr/bin/pminfo...Reading symbols from /usr/lib/debug/usr/bin/pminfo.debug...done.
done.
(gdb) 
(gdb) 
(gdb) 
(gdb) r -L -K clear -K add,60,/var/lib/pcp/pmdas/linux/pmda_linux.so,linux_init -f network.softnet.cpu_collision network.softnet.dropped network.softnet.flow_limit_count network.softnet.processed network.softnet.received_rps network.softnet.time_squeeze
Starting program: /usr/bin/pminfo -L -K clear -K add,60,/var/lib/pcp/pmdas/linux/pmda_linux.so,linux_init -f network.softnet.cpu_collision network.softnet.dropped network.softnet.flow_limit_count network.softnet.processed network.softnet.received_rps network.softnet.time_squeeze
[Thread debugging using libthread_db enabled]
*** buffer overflow detected ***: /usr/bin/pminfo terminated
======= Backtrace: =========
<... snip ... >
Program received signal SIGABRT, Aborted.
0x00110424 in __kernel_vsyscall ()
(gdb) 
(gdb) bt
#0  0x00110424 in __kernel_vsyscall ()
#1  0x004d7871 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#2  0x004d914a in abort () at abort.c:92
#3  0x00517735 in __libc_message (do_abort=2, fmt=0x605290 "*** %s ***: %s terminated\n") at ../sysdeps/unix/sysv/linux/libc_fatal.c:198
#4  0x005a9e1d in __fortify_fail (msg=0x605236 "buffer overflow detected") at fortify_fail.c:32
#5  0x005a7e5a in __chk_fail () at chk_fail.c:29
#6  0x005a710a in __strcat_chk (dest=0x134a20 "%08llx %08llx %08llx %08llx %08llx %08llx %08llx %08llx %08llx %08llx %08llx ", src=0x12a314 "%08llx ", destlen=<value optimized out>) at strcat_chk.c:51
#7  0x00126c6d in strcat (proc_net_softnet=0x134280) at /usr/include/bits/string3.h:144
#8  refresh_proc_net_softnet (proc_net_softnet=0x134280) at proc_net_softnet.c:44
#9  0x0011af86 in linux_refresh (pmda=0x804eb60, need_refresh=0xbfffee30, context=0) at pmda.c:4585
#10 0x0011b27f in linux_fetch (numpmid=6, pmidlist=0x805d008, resp=0xbfffefd4, pmda=0x804eb60) at pmda.c:6377
#11 0x05c4a263 in __pmFetchLocal (ctxp=0x804e198, numpmid=6, pmidlist=0x804e130, result=0xbffff1f8) at fetchlocal.c:131
#12 0x05c22970 in pmFetch (numpmid=6, pmidlist=0x804e130, result=0xbffff1f8) at fetch.c:147
#13 0x08049994 in report () at pminfo.c:359
#14 0x0804a7e1 in main (argc=13, argv=0xbffff334) at pminfo.c:692
(gdb) frame 8
#8  refresh_proc_net_softnet (proc_net_softnet=0x134280) at proc_net_softnet.c:44
44                      strcat(fmt, "%08llx ");
(gdb) 

Looking at fmt in refresh_proc_net_softnet() I wonder if it is big enough:

int
refresh_proc_net_softnet(proc_net_softnet_t *proc_net_softnet)
{   
    <... snip ...>
    static char fmt[11*7] = { '\0' };   /* 7 == strlen("%08llx ") */

    if (fmt[0] == '\0') {
        int i;
        /*
         * one trip initialization to decide the correct sscanf format
         * for a uint64_t data type .. needs to be
         * "%08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx"
         * or
         * "%08llx %08llx %08llx %08llx %08llx %08llx %08llx %08llx %08llx %08llx %08llx"
         */
        fmt[0] = '\0';
        if (strcmp(FMT_INT64, "lld") == 0) {
            for (i = 0; i < 11; i++)
                strcat(fmt, "%08llx "); <=== line 44
        }

According to backtrace (frame #6) fmt contains 11 formatting groups by this time, and I'd say fmt is 1 byte short - 11 * 7 is enough for 11 groups but the last \0 can't fit in. I did some stepping exercise in gdb, and this idea of mine seems to be correct.


Version-Release number of selected component (if applicable):

pcp-3.10.9-2.el6.i686


How reproducible:


Steps to Reproduce:
1.
2.
3.

Actual results:


Expected results:


Additional info:

Comment 1 Miloš Prchlík 2016-01-05 13:56:49 UTC
Setting Hardware to i686 - the branch in question gets executed when FMT_INT64 == "lld" which in this RHEL is just x86 only, IMHO. On other arches, "%08lx " is short enough to fit 11 times into fmt, including the last '\0'. Also, on other arches in my test run this command runs fine, and provides some network-related data.

Comment 2 Nathan Scott 2016-01-05 22:44:17 UTC
mgoodwin and I both had a look this morning and your analysis is spot on as usual Miloš - your fix will flow upstream shortly & a pcp-3.10.9-3 will follow soon.  Thanks!

Comment 4 Miloš Prchlík 2016-02-08 09:50:21 UTC
Verified for build pcp-3.10.9-5.el6.

Comment 6 errata-xmlrpc 2016-05-10 21:13:24 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://rhn.redhat.com/errata/RHBA-2016-0825.html