computerの日記

Cisco,SHELL,C,Qt,C++,Linux,ネットワーク,Windows Scriptなどの発言です

sar-analyzer で segfault したので、coredump を読んでみた ( is sar-analyzer の開発状況(20180726))

あるファイルを読み込ませると、sar-analyzer が coredump を吐くので、なぜだろう、と思っていました。ありえない数値のデータが入った sar ファイルを読むと、segfault するようでした。 ちなみに、sar-analyzer のバージョンは、8.5 です。

これは問題だなぁ、と考えているのですが、コード上、どこでひっかかっているのか、どう直したらいいのかを追求したいところです。

すぐにでも直したいところですが、せっかくのチャンスなので、coredump を確認してみようと思います。

 Fedora28 では、以下のディレクトリに coredump が吐かれるようでした。

/var/spool/abrt

今回作成されていたファイルとなります。

# ls /var/spool/abrt/ccpp-2018-07-26-22\:27\:57.89892-6205/
abrt_version cmdline cpuinfo executable kernel mountinfo pid rootdir uid
analyzer core_backtrace crash_function exploitable last_occurrence open_fds proc_pid_status runlevel username
architecture coredump dso_list hostname limits os_info pwd time uuid
cgroup count environ journald_cursor maps os_release reason type

ここで、coredump というファイルがありますので、gdb で読んでみます。

# gdb sar-analyzer /var/spool/abrt/ccpp-2018-07-26-22\:27\:57.89892-6205/coredump
GNU gdb (GDB) Fedora 8.1-23.fc28
Copyright (C) 2018 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 "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from sar-analyzer...done.
[New LWP 6205]
Core was generated by `./sar-analyzer -D ./tmp -ZM'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00007f5592201ad5 in __strncpy_sse2_unaligned () from /lib64/libc.so.6
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.27-30.fc28.x86_64
(gdb)

glibc の debuginfo パッケージが必要だということですよで、指示どおり、以下のコマンドを実行しました。

# dnf debuginfo-install glibc-2.27-30.fc28.x86_64
enabling docker-ce-stable-debuginfo repository
enabling docker-ce-edge-debuginfo repository
enabling docker-ce-test-debuginfo repository
enabling updates-debuginfo repository
enabling fedora-debuginfo repository
enabling rpmfusion-free-updates-debuginfo repository
enabling rpmfusion-free-debuginfo repository
enabling rpmfusion-nonfree-updates-debuginfo repository
enabling rpmfusion-nonfree-debuginfo repository
Docker CE Stable - Debuginfo x86_64 3.6 kB/s | 1.8 kB 00:00
Docker CE Edge - Debuginfo x86_64 3.7 kB/s | 2.3 kB 00:00
Docker CE Test - Debuginfo x86_64 5.6 kB/s | 4.0 kB 00:00
Fedora 28 - x86_64 - Updates - Debug 4.3 MB/s | 9.9 MB 00:02
Fedora 28 - x86_64 - Debug 9.3 MB/s | 28 MB 00:03
RPM Fusion for Fedora 28 - Free - Updates Debug 109 kB/s | 448 kB 00:04
RPM Fusion for Fedora 28 - Free - Debug 214 kB/s | 678 kB 00:03
RPM Fusion for Fedora 28 - Nonfree - Updates Debug 46 kB/s | 52 kB 00:01
RPM Fusion for Fedora 28 - Nonfree - Debug 79 kB/s | 105 kB 00:01
メタデータの期限切れの確認は、0:00:00 時間前の 2018年07月26日 22時50分34秒 に実施しました。
依存性が解決されました。
======================================================================================================================================
パッケージ アーキテクチャ バージョン リポジトリ サイズ
======================================================================================================================================
インストール:
glibc-debuginfo x86_64 2.27-30.fc28 updates-debuginfo 14 M
依存関係のインストール:
glibc-debuginfo-common x86_64 2.27-30.fc28 updates-debuginfo 10 M

トランザクションの要約
======================================================================================================================================
インストール 2 パッケージ

総ダウンロードサイズ: 24 M
パッケージ展開後のサイズ: 160 M
これでいいですか? [y/N]: y
パッケージをダウンロードしています:
(1/2): glibc-debuginfo-common-2.27-30.fc28.x86_64.rpm 179 kB/s | 10 MB 00:57
(2/2): glibc-debuginfo-2.27-30.fc28.x86_64.rpm 199 kB/s | 14 MB 01:10
--------------------------------------------------------------------------------------------------------------------------------------
合計 340 kB/s | 24 MB 01:11
トランザクションの確認を実行中...
トランザクションの確認に成功しました。
トランザクションのテストを実行中...
トランザクションのテストに成功しました。
トランザクションを実行中...
準備中 : 1/1
インストール : glibc-debuginfo-common-2.27-30.fc28.x86_64 1/2
インストール : glibc-debuginfo-2.27-30.fc28.x86_64 2/2
Running scriptlet: glibc-debuginfo-2.27-30.fc28.x86_64 2/2
検証中 : glibc-debuginfo-2.27-30.fc28.x86_64 1/2
検証中 : glibc-debuginfo-common-2.27-30.fc28.x86_64 2/2

インストール済み:
glibc-debuginfo.x86_64 2.27-30.fc28 glibc-debuginfo-common.x86_64 2.27-30.fc28

完了しました!

では、もう一度実行してみます。

 # gdb sar-analyzer /var/spool/abrt/ccpp-2018-07-26-22\:27\:57.89892-6205/coredump
GNU gdb (GDB) Fedora 8.1-23.fc28
Copyright (C) 2018 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 "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from sar-analyzer...done.
[New LWP 6205]
Core was generated by `./sar-analyzer -D ./tmp -ZM'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 __strncpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:298
298 movdqu (%rsi), %xmm1
(gdb)

 これではどうでしょうか。

(gdb) bt
#0 __strncpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:298
#1 0x0000000000402a0f in set_token_items (file_number=file_number@entry=1, item_name=item_name@entry=0x41412e "DEV",
utility=utility@entry=-999, SAR_OPTION=90, line=<optimized out>) at sar_analyzer.c:703
#2 0x000000000040b4f1 in get_word_line (file_number=file_number@entry=1, line=line@entry=0x7ffc08dd6a90,
SAR_OPTION=SAR_OPTION@entry=90, MESSAGE_ONLY=MESSAGE_ONLY@entry=1) at sar_analyzer.c:3581
#3 0x000000000040e858 in read_sar (REPORT=0, MESSAGE_ONLY=1, SAR_OPTION=90, filename=0x7ffc08dd89cf "./tmp/sar24", file_number=1)
at sar_analyzer.c:5226
#4 read_write_file (dname=dname@entry=0x7ffc08ddce4a "./tmp", sar_arr=sar_arr@entry=0x7ffc08ddaa20, files_n=files_n@entry=1,
SAR_OPTION=SAR_OPTION@entry=90, REPORT=REPORT@entry=0, MESSAGE_ONLY=MESSAGE_ONLY@entry=1) at sar_analyzer.c:3860
#5 0x0000000000413ee1 in read_sa_dir (dname=0x7ffc08ddce4a "./tmp", SAR_OPTION=90, REPORT=0, MESSAGE_ONLY=1) at sar_analyzer.c:3748
#6 0x00000000004012cc in main (argc=<optimized out>, argv=0x7ffc08ddaee8) at main.c:377
 

まずは、以下の記述です。

#6 0x00000000004012cc in main (argc=<optimized out>, argv=0x7ffc08ddaee8) at main.c:377

実際のコードは、以下のようになっています。

main.c

377 sar_analyzer_init ( dir_name, file_name, SAR_OPTION, REPORT, MESSAGE_ONLY );

初期化のコードですね。

次は、以下の記述です。

#5 0x0000000000413ee1 in read_sa_dir (dname=0x7ffc08ddce4a "./tmp", SAR_OPTION=90, REPORT=0, MESSAGE_ONLY=1) at sar_analyzer.c:3748

read_sa_dir() という関数で、sa ディレクトリを読み出します。デフォルトでは、./tmp となります。関数の頭もつけてみました。

3650 /*
3651 * This function reads sa directory.
3652 * Sorts file names and puts them into an array.
3653 * Pass an array and file numbers with the SAR_OPTION and REPORT to the function 'read_write_file()'.
3654 *
3655 * Caller : sar_analyzer_init()
3656 *
3657 * Calls : read_write_file()
3658 *
3659 */
3660 static void read_sa_dir ( const char *dname, int SAR_OPTION, int REPORT, int MESSAGE_ONLY )
3661 {

,,,(snip)...

3747 /* now pass an array to the function, this will be done by passing first pointer of an array */
3748 read_write_file ( dname, str_arr_to_function, files_n, SAR_OPTION, REPORT, MESSAGE_ONLY );

今回は、read_sa_dir 関数により、./tmp を読んでいます。

そして、read_write_file () 関数を呼び出しています。

 次は、この記述です。

#4 read_write_file (dname=dname@entry=0x7ffc08ddce4a "./tmp", sar_arr=sar_arr@entry=0x7ffc08ddaa20, files_n=files_n@entry=1,
SAR_OPTION=SAR_OPTION@entry=90, REPORT=REPORT@entry=0, MESSAGE_ONLY=MESSAGE_ONLY@entry=1) at sar_analyzer.c:3860 

read_write_file() 関数の頭もつけておきました。

3809 /*
3810 * This function loops through an array given by 'read_sa_dir()'.
3811 * During the procedure, files are read by 'read_sar()' and data are stored in the struct.
3812 * After 'read_sar()' job is done, calls 'make_report()' to store data in the struct.
3813 *
3814 * Caller read_sa_dir()
3815 *
3816 * Calls: read_sar()
3817 * Calls: make_report()
3818 *
3819 */
3820 static void read_write_file ( const char *dname, char *sar_arr [ ], int files_n, int SAR_OPTION, int REPORT, int MESSAGE_ONLY )
3821 {

...(snip)...

3849 /* read sar files in the hope that 'read_sar()' works fine */
3850 for ( i = 1; i <= files_n; i++ )
3851 {
3852 char str_tmp [ 17 ] = "--------file no.";
3853 char str_num [ 50 ] = { '\0' };
3854 snprintf ( str_num, MAX_INPUT, "%s%d", str_tmp, i );
3855 append_list ( &line_obj, "" );
3856 append_list ( &line_obj, str_num );
3857 append_list ( &line_all_obj, "" );
3858 append_list ( &line_all_obj, str_num );
3859 /* let 'read_sar()' do the job */
3860 read_sar ( i, sar_full_path_arr [ i ], SAR_OPTION, REPORT, MESSAGE_ONLY );
3861 }
3862 make_report ( SAR_OPTION, REPORT, files_n );
3863 }

3860 行目で、read_sar () 関数を呼び出すところですね。

 次は、この記述です。

#3 0x000000000040e858 in read_sar (REPORT=0, MESSAGE_ONLY=1, SAR_OPTION=90, filename=0x7ffc08dd89cf "./tmp/sar24", file_number=1)
at sar_analyzer.c:5226 

 お、./tmp/sar24 というファイルを最初に読み出したよ、といっていますね。

そうなんです、あり得ない数値を入れた sar24 というファイルを一つだけ ./tmp ディレクトリに入れておいたのです。すごいなー、丸見えやー。

read_sar() という関数により、sar ファイルを読むのですが、今回も、関数の頭もつけます。

5161 /*
5162 * This function reads sar file and during the procedure, 'get_word_line()' writes
5163 * item values to the struct as an option orders.
5164 *
5165 * Caller : read_write_file()
5166 *
5167 * Calls : get_word_line()
5168 *
5169 */
5170 static void read_sar ( int file_number, const char *filename, int SAR_OPTION, int REPORT, int MESSAGE_ONLY )
5171 {

...(snip)...

5204 /* read file and parse lines */
5205 while ( fgets ( linebuf,sizeof ( linebuf ),fp ) != NULL )
5206 {
5207 lnr++;
5208 line = linebuf;
5209 /* strip newline */
5210 i = ( int ) strlen ( line );
5211 if ( ( i <= 0 ) || ( line [ i - 1 ] != '\n' ) )
5212 {
5213 printf("%s:%d: line too long or last line missing newline\n Hint:$sed -i 's/\\x00//g' <sar_file>\n",filename,lnr);
5214 /* freeing object and setting it to NULL */
5215 free_sar_analyzer_obj ( );
5216 exit ( EXIT_FAILURE );
5217 }
5218 line [ i - 1 ] = '\0';
5219 /* ignore comment lines */
5220 if ( line [ 0 ] == '#' )
5221 continue;
5222 /* strip trailing spaces */
5223 for ( i--; ( i > 0 ) && isspace ( line [ i -1 ] ) ; i-- )
5224 line [ i -1 ] = '\0';
5225 /* get keyword from line and ignore empty lines */
5226 if ( get_word_line ( file_number, &line, SAR_OPTION, MESSAGE_ONLY ) != 0 )
5227 continue;
5228 }
5229 /* after reading all lines, close the file pointer */
5230 fclose ( fp );
5231 }

 5226 行目ですが、今回は、./tmp/sar24 ファイルを、get_word_line() という関数で 1行読んでいるところです。

だんだん近づいてきた感じがしますね。ドキドキ。。

でも、疲れたぁ。お腹すいたァ。じゃ、つづきはまた。。