diff options
author | Jan Kratochvil <jan.kratochvil@redhat.com> | 2014-02-21 18:39:40 +0100 |
---|---|---|
committer | Jan Kratochvil <jan.kratochvil@redhat.com> | 2014-02-21 18:39:40 +0100 |
commit | 184cd07257b5dd74a4eb9f6857fc6dd785f53492 (patch) | |
tree | 9821fa0b3d4983f24cfe26269caa8b152beca499 /gdb/linux-tdep.c | |
parent | dcf893b581c440902d68a0095967acd4ae7ae8d1 (diff) | |
download | gdb-184cd07257b5dd74a4eb9f6857fc6dd785f53492.zip gdb-184cd07257b5dd74a4eb9f6857fc6dd785f53492.tar.gz gdb-184cd07257b5dd74a4eb9f6857fc6dd785f53492.tar.bz2 |
Fix crash on process name "(sd-pam)" (PR 16594).
info os processes -fsanitize=address error
https://sourceware.org/bugzilla/show_bug.cgi?id=16594
info os processes
=================================================================
==5795== ERROR: AddressSanitizer: heap-use-after-free on address
0x600600214974 at pc 0x757a92 bp 0x7fff95dd9f00 sp 0x7fff95dd9ef0
READ of size 4 at 0x600600214974 thread T0
#0 0x757a91 in get_cores_used_by_process (.../gdb/gdb+0x757a91)
At least Fedora 20 has process(es):
6678 ? Ss 0:00 /usr/lib/systemd/systemd --user
6680 ? S 0:00 \_ (sd-pam)
and GDB "info os processes" crashes on it as /proc/6680/stat contains:
6680 ((sd-pam)) S 6678 6678 6678 0 -1 1077961024 33 0 0 0 0 0 0 0 20 0 1 0 18568 73768960 120 18446744073709551615 1 1
0 0 0 0 0 4096 0 18446744073709551615 0 0 17 6 0 0 0 0 0 0 0 0 0 0 0 0 0
and GDB fails to find the proper end of the process name "((sd-pam))".
Therefore it reads core number off-by-one (it reads 17 instead of 6) and
overruns the array.
(1) Make the process name parsing more foolproof.
(2) Do not trust the parsed number from /proc/PID/stat and verify it against
the array size.
I noticed that 'ps' gets this right, so I've peeked at its
sources, and it just looks for the first ')' starting at
the end.
https://gitorious.org/procps/procps/source/dc072aced7250fed9b01fb05f0d672678752a63e:proc/readproc.c
Look for stat2proc.
Given ps does that, I believe the kernel won't ever be changed
in a way that would break it. So it sounds like could do strrchr
from the end of stat just as well without worry, which is simpler.
gdb/
2014-02-21 Jan Kratochvil <jan.kratochvil@redhat.com>
PR gdb/16594
* common/linux-osdata.c (linux_common_core_of_thread): Find the end of
process name.
(get_cores_used_by_process): New parameter num_cores, use it.
(linux_xfer_osdata_processes): Pass num_cores to it.
* linux-tdep.c (linux_info_proc, linux_fill_prpsinfo): Find the end of
process name.
Message-ID: <20140217212826.GA15080@host2.jankratochvil.net>
Diffstat (limited to 'gdb/linux-tdep.c')
-rw-r--r-- | gdb/linux-tdep.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index bd1e5a2..c10b8ee 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -476,7 +476,9 @@ linux_info_proc (struct gdbarch *gdbarch, char *args, p = skip_spaces_const (p); if (*p == '(') { - const char *ep = strchr (p, ')'); + /* ps command also relies on no trailing fields + ever contain ')'. */ + const char *ep = strrchr (p, ')'); if (ep != NULL) { printf_filtered ("Exec file: %.*s\n", @@ -1331,12 +1333,14 @@ linux_fill_prpsinfo (struct elf_internal_linux_prpsinfo *p) proc_stat = skip_spaces (proc_stat); - /* Getting rid of the executable name, since we already have it. We - know that this name will be in parentheses, so we can safely look - for the close-paren. */ - while (*proc_stat != ')') - ++proc_stat; - ++proc_stat; + /* ps command also relies on no trailing fields ever contain ')'. */ + proc_stat = strrchr (proc_stat, ')'); + if (proc_stat == NULL) + { + do_cleanups (c); + return 1; + } + proc_stat++; proc_stat = skip_spaces (proc_stat); |