
SmallBASICは、日常的な計算、スクリプト、プロトタイプに最適な、高速で学びやすいBASIC言語インタプリタです。SmallBASICには、三角関数、行列、代数関数、組み込みIDE、強力な文字列ライブラリ、システム、サウンド、グラフィックコマンド、そして構造化プログラミング構文が含まれています。
src/platform/sdl/main.cppの277行目で、strcpyが呼び出され、argvをグローバル変数opt_commandにコピーしています。このグローバル変数はsrc/common/smbas.hで定義されています。同じファイルで定義されているOPT_CMD_CZマクロに従い、固定サイズの配列です。
// src/common/smbas.h:105
EXTERN char opt_command[OPT_CMD_CZ] //
// src/platform/sdl/main.cpp:263
while (1) {
int option_index = 0;
int c = getopt_long(argc, argv, "hvkc:f:r:x:n:m:e:d:p:", OPTIONS, &option_index);
if (c == -1) {
// no more options
if (!option_index) {
for (int i = 1; i < argc; i++) {
const char *s = argv[i];
int len = strlen(s);
if (runFile == NULL
&& ((strcasecmp(s + len - 4, ".bas") == 0 && access(s, 0) == 0)
|| (strstr(s, "://") != NULL))) {
runFile = strdup(s);
} else if (chdir(s) != 0) {
strcpy(opt_command, s); // VULNERABLE
}
}
}
break;
}
src/common/smbas.hによると、OPT_CMD_CZは1024と定義されています。
#define OPT_CMD_CZ 1024
strlcpy関数とは異なり、strcpyはコピーするバイト数をチェックしません。そのため、1024バイトを超えるデータがopt_command配列にコピーされる可能性があります。コマンドライン引数が1024バイトより長くなり得るため、入力によって他のオブジェクトが上書きされる可能性があります。これにより、プログラムsbasicgが予期しない動作を引き起こす可能性があります。
Windowsのコマンドプロンプトで使用できる文字列の最大長は8191文字です。Linuxでは、長さはARG_MAXとMAX_ARG_STRINGSに依存します。
SmallBASICプロジェクトをビルドし、次を実行します。
$ src/platform/sdl/sbasicg $(python -c 'print("a"*1024)')
これにより、main関数で実装されたコマンドライン引数の解析中にグローバルバッファオーバーフローが発生します。以下はAddress Sanitizerからの出力です。
=================================================================
==5322==ERROR: AddressSanitizer: global-buffer-overflow on address 0x0000016c22a0 at pc 0x0000004ba2e4 bp 0x7ffeb3ebac70 sp 0x7ffeb3eba428
WRITE of size 1025 at 0x0000016c22a0 thread T0
#0 0x4ba2e3 in strcpy (/home/ch1keen/fuzz/SmallBASIC/src/platform/sdl/sbasicg+0x4ba2e3) (BuildId: 4a800899b4dac082870bb647e1d872811e8633ea)
#1 0x8759c6 in main /home/ch1keen/fuzz/SmallBASIC/src/platform/sdl/main.cpp:277:13
#2 0x79e3ca62a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#3 0x79e3ca62a28a in __libc_start_main csu/../csu/libc-start.c:360:3
#4 0x4378b4 in _start (/home/ch1keen/fuzz/SmallBASIC/src/platform/sdl/sbasicg+0x4378b4) (BuildId: 4a800899b4dac082870bb647e1d872811e8633ea)
0x0000016c22a0 is located 0 bytes after global variable 'opt_command' defined in '/home/ch1keen/fuzz/SmallBASIC/src/common/smbas.h:105' (0x16c1ea0) of size 1024
SUMMARY: AddressSanitizer: global-buffer-overflow (/home/ch1keen/fuzz/SmallBASIC/src/platform/sdl/sbasicg+0x4ba2e3) (BuildId: 4a800899b4dac082870bb647e1d872811e8633ea) in strcpy
Shadow bytes around the buggy address:
0x0000016c2000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000016c2080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000016c2100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000016c2180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000016c2200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0000016c2280: 00 00 00 00[f9]f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
0x0000016c2300: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
0x0000016c2380: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
0x0000016c2400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000016c2480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0000016c2500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==5322==ABORTING
この脆弱性の影響は不明です。しかし、グローバルバッファオーバーフローにより他のグローバル変数が上書きされる可能性があり、プログラムのフラグや設定が上書きされる可能性があります。
この脆弱性は、私が報告した問題を含め、ほぼすべてのstrcpyをstrlcpyに置き換えることで修正されました。
@@ -277,1 +277,1 @@ int main(int argc, char* argv[]) {
< strcpy(opt_command, command);
---
> strlcpy(opt_command, command, sizeof(opt_command));
詳細なパッチについてはコミットを参照してください。