该机器代码如何防止缓冲区溢出?
How does this machine code prevent buffer-overrun?
以下是三个不同 .s 文件的一部分。 .c 文件已使用三个不同的选项进行编译:
- -fno-inline -fstack-protector-strong,
- -fno-inline -fsanitize=地址,
- -fno-inline -fno-stack-protector -zexecstack.
.s文件内容如下:
handle_read:
.LFB20:
.cfi_startproc
pushq %r12
.cfi_def_cfa_offset 16
.cfi_offset 12, -16
pushq %rbp
.cfi_def_cfa_offset 24
.cfi_offset 6, -24
movq %rsi, %r12
pushq %rbx
.cfi_def_cfa_offset 32
.cfi_offset 3, -32
movq 8(%rdi), %rbx
movq %rdi, %rbp
movq 160(%rbx), %rsi
movq 152(%rbx), %rdx
cmpq %rdx, %rsi
jb .L394
cmpq 00, %rdx
jbe .L421
handle_read:
.LASANPC20:
.LFB20:
.cfi_startproc
pushq %r15
.cfi_def_cfa_offset 16
.cfi_offset 15, -16
pushq %r14
.cfi_def_cfa_offset 24
.cfi_offset 14, -24
pushq %r13
.cfi_def_cfa_offset 32
.cfi_offset 13, -32
pushq %r12
.cfi_def_cfa_offset 40
.cfi_offset 12, -40
pushq %rbp
.cfi_def_cfa_offset 48
.cfi_offset 6, -48
movq %rdi, %rbp
addq , %rdi
pushq %rbx
.cfi_def_cfa_offset 56
.cfi_offset 3, -56
movq %rdi, %rax
shrq , %rax
subq , %rsp
.cfi_def_cfa_offset 80
cmpb [=10=], 2147450880(%rax)
jne .L1170
movq 8(%rbp), %rbx
leaq 160(%rbx), %r13
movq %r13, %r15
shrq , %r15
cmpb [=10=], 2147450880(%r15)
jne .L1171
leaq 152(%rbx), %r14
movq %rsi, %r12
movq 160(%rbx), %rsi
movq %r14, %rax
shrq , %rax
cmpb [=10=], 2147450880(%rax)
jne .L1172
movq 152(%rbx), %rdx
leaq 144(%rbx), %rcx
cmpq %rdx, %rsi
jb .L1054
cmpq 00, %rdx
jbe .L1055
movl $httpd_err400form, %eax
shrq , %rax
cmpb [=10=], 2147450880(%rax)
jne .L1173
movl $httpd_err400title, %eax
movq httpd_err400form(%rip), %r8
shrq , %rax
cmpb [=10=], 2147450880(%rax)
jne .L1174
handle_read:
.LFB20:
.cfi_startproc
pushq %r12
.cfi_def_cfa_offset 16
.cfi_offset 12, -16
pushq %rbp
.cfi_def_cfa_offset 24
.cfi_offset 6, -24
movq %rsi, %r12
pushq %rbx
.cfi_def_cfa_offset 32
.cfi_offset 3, -32
movq 8(%rdi), %rbx
movq %rdi, %rbp
movq 160(%rbx), %rsi
movq 152(%rbx), %rdx
cmpq %rdx, %rsi
jb .L384
cmpq 00, %rdx
jbe .L411
谁能告诉我这些代码是如何防止缓冲区溢出的?
您的 handle_read
函数最终不会在堆栈上分配任何内容,因此 -fstack-protector-strong
没有任何内容需要保护,因此此选项没有任何区别。 -zexecstack
选项在生成的 executable 中设置一个标志,告诉操作系统它应该允许存储在堆栈中的代码被执行。它对生成的程序集没有影响。
只有 -fsanitize=address
选项的效果会显示在您发布的生成的程序集输出中。它负责出现在生成的第二个程序集块中的 shrq , rXX; cmp [=14=], 2147450880(%rXX); jne .LXXXX
序列。这些指令在 "shadow memory" table 中查找函数访问的内存中的每个地址。 table 记录哪些位置已经分配,哪些还没有。如果插入的代码检测到程序正在尝试访问尚未分配的内存位置,它将导致程序退出并显示错误消息。
有关影子内存 table 工作原理以及 AddressSanitizer 一般工作原理的更多详细信息,您可以阅读作者的 Usenix 论文 AddressSanitizer: A Fast Address Sanity Checker.
以下是三个不同 .s 文件的一部分。 .c 文件已使用三个不同的选项进行编译:
- -fno-inline -fstack-protector-strong,
- -fno-inline -fsanitize=地址,
- -fno-inline -fno-stack-protector -zexecstack.
.s文件内容如下:
handle_read:
.LFB20:
.cfi_startproc
pushq %r12
.cfi_def_cfa_offset 16
.cfi_offset 12, -16
pushq %rbp
.cfi_def_cfa_offset 24
.cfi_offset 6, -24
movq %rsi, %r12
pushq %rbx
.cfi_def_cfa_offset 32
.cfi_offset 3, -32
movq 8(%rdi), %rbx
movq %rdi, %rbp
movq 160(%rbx), %rsi
movq 152(%rbx), %rdx
cmpq %rdx, %rsi
jb .L394
cmpq 00, %rdx
jbe .L421
handle_read:
.LASANPC20:
.LFB20:
.cfi_startproc
pushq %r15
.cfi_def_cfa_offset 16
.cfi_offset 15, -16
pushq %r14
.cfi_def_cfa_offset 24
.cfi_offset 14, -24
pushq %r13
.cfi_def_cfa_offset 32
.cfi_offset 13, -32
pushq %r12
.cfi_def_cfa_offset 40
.cfi_offset 12, -40
pushq %rbp
.cfi_def_cfa_offset 48
.cfi_offset 6, -48
movq %rdi, %rbp
addq , %rdi
pushq %rbx
.cfi_def_cfa_offset 56
.cfi_offset 3, -56
movq %rdi, %rax
shrq , %rax
subq , %rsp
.cfi_def_cfa_offset 80
cmpb [=10=], 2147450880(%rax)
jne .L1170
movq 8(%rbp), %rbx
leaq 160(%rbx), %r13
movq %r13, %r15
shrq , %r15
cmpb [=10=], 2147450880(%r15)
jne .L1171
leaq 152(%rbx), %r14
movq %rsi, %r12
movq 160(%rbx), %rsi
movq %r14, %rax
shrq , %rax
cmpb [=10=], 2147450880(%rax)
jne .L1172
movq 152(%rbx), %rdx
leaq 144(%rbx), %rcx
cmpq %rdx, %rsi
jb .L1054
cmpq 00, %rdx
jbe .L1055
movl $httpd_err400form, %eax
shrq , %rax
cmpb [=10=], 2147450880(%rax)
jne .L1173
movl $httpd_err400title, %eax
movq httpd_err400form(%rip), %r8
shrq , %rax
cmpb [=10=], 2147450880(%rax)
jne .L1174
handle_read:
.LFB20:
.cfi_startproc
pushq %r12
.cfi_def_cfa_offset 16
.cfi_offset 12, -16
pushq %rbp
.cfi_def_cfa_offset 24
.cfi_offset 6, -24
movq %rsi, %r12
pushq %rbx
.cfi_def_cfa_offset 32
.cfi_offset 3, -32
movq 8(%rdi), %rbx
movq %rdi, %rbp
movq 160(%rbx), %rsi
movq 152(%rbx), %rdx
cmpq %rdx, %rsi
jb .L384
cmpq 00, %rdx
jbe .L411
谁能告诉我这些代码是如何防止缓冲区溢出的?
您的 handle_read
函数最终不会在堆栈上分配任何内容,因此 -fstack-protector-strong
没有任何内容需要保护,因此此选项没有任何区别。 -zexecstack
选项在生成的 executable 中设置一个标志,告诉操作系统它应该允许存储在堆栈中的代码被执行。它对生成的程序集没有影响。
只有 -fsanitize=address
选项的效果会显示在您发布的生成的程序集输出中。它负责出现在生成的第二个程序集块中的 shrq , rXX; cmp [=14=], 2147450880(%rXX); jne .LXXXX
序列。这些指令在 "shadow memory" table 中查找函数访问的内存中的每个地址。 table 记录哪些位置已经分配,哪些还没有。如果插入的代码检测到程序正在尝试访问尚未分配的内存位置,它将导致程序退出并显示错误消息。
有关影子内存 table 工作原理以及 AddressSanitizer 一般工作原理的更多详细信息,您可以阅读作者的 Usenix 论文 AddressSanitizer: A Fast Address Sanity Checker.