There exsits one null pointer dereference in function bsii
at nasmlib/bsi.c:68 in nasm-2.14rc15. which can cause a segment fault.
To reproduce:1
2./configure && make
./nasm -f elf poc
gdb output:
backtrace:1
2
3
4
5
6
7#0 __strcasecmp_l_avx () at ../sysdeps/x86_64/multiarch/strcmp-sse42.S:198
#1 0x00005555555f2291 in bsii (string=0x0, array=0x5555558de220 <size_names>, size=7) at nasmlib/bsi.c:68 <-------null str
#2 0x00005555555bc9e0 in parse_size (str=0x0) at asm/preproc.c:2214 <-------null str
#3 0x00005555555bd310 in do_directive (tline=0x7ffff7fda2d0, output=0x7fffffffd6b8) at asm/preproc.c:2471
#4 0x00005555555c49a4 in pp_getline () at asm/preproc.c:5210
#5 0x00005555555a86ae in assemble_file (fname=0x5555558f3d60 "/dev/stdin", depend_ptr=0x0) at asm/nasm.c:1435
#6 0x00005555555a65e5 in main (argc=6, argv=0x7fffffffda88) at asm/nasm.c:566
source code:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// in nasmlib/bsi.c len = 68
int bsii(const char *string, const char **array, int size)
{
int i = -1, j = size; /* always, i < index < j */
while (j - i >= 2) {
int k = (i + j) / 2;
int l = nasm_stricmp(string, array[k]); <-----crash null str
if (l < 0) /* it's in the first half */
j = k;
...
// in asm/preproc.c len = 2214
static int parse_size(const char *str) {
static const char *size_names[] =
{ "byte", "dword", "oword", "qword", "tword", "word", "yword" };
static const int sizes[] =
{ 0, 1, 4, 16, 8, 10, 2, 32 };
return sizes[bsii(str, size_names, ARRAY_SIZE(size_names))+1]; <--- crash null str
}
poc
1 | %define dword |
根据asm语义,poc的语义将dword定义为null
,而在第二句中,将val
定义为dword类型,在此出现了语义的重复,导致了在解析dword的过程中,将dword理解为null
。
1 | // at asm/preproc.c:2471 |
1 | pwndbg> p *head |
head->expansion == null
问题应该出现在hash_findix()
函数中,因为define dword之后没有对应的字符串,hash_findix()
函数将expansion
赋值为空,导致函数返回时返回了空的thead
。
preproc.c
poc导致程序crash在于:1
2
3
4
5
6
7
8
9
10
11
12
13//preproc.c at line 4230
head = (SMacro *)hash_findix(&smacros, mname);
//preproc.c at line 4243
list_for_each(m, head)
if (!mstrcmp(m->name, mname, m->casesense))
break;
//preproc.c at line 4256
if (!m->expansion) {
...
tline = delete_Token(tline);
continue;
因为在正确的宏定义当中,%define ABC abc
将abc定义为ABC。但是,由于poc中%define dword
没有定义值,所以,在hash_findix()
中取的的值中head->expansion
为空,在if条件分支里,进行了删除操作,之后继续执行。因此在此处返回值变为null。
hash_findix()
hash_findix(struct hash_table *hash, const char *str)
根据输入的字符串取一个(SMacro *)类型的值。即取出宏定义是对应的宏。该值会包含一些宏的信息,但是由于在宏定义是没有宏的值进行定义,所以expansion
为空。