Linux 使用 setrlimit() 设置堆栈大小并引发堆栈溢出/段错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4118016/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Set stack size with setrlimit() and provoke a stack overflow/segfault
提问by tur1ng
In the given example below I try to set the stacksize to 1kb.
在下面给出的示例中,我尝试将堆栈大小设置为 1kb。
Why is it now possible to allocate an array of ints on the stack with size 8kb
in foo()
?
为什么现在可以在堆栈上分配大小为8kb
in的整数数组foo()
?
#include <stdio.h>
#include <sys/resource.h>
void foo(void);
int main() {
struct rlimit lim = {1024, 1024};
if (setrlimit(RLIMIT_STACK, &lim) == -1)
return 1;
foo();
return 0;
}
void foo() {
unsigned ints[2048];
printf("foo: %u\n", ints[2047]=42);
}
采纳答案by ninjalj
The limit is set immediately but only checked when trying to allocate a new stack or trying to grow the existing stack. A grep for RLIMIT_STACK (or a LXR identifier search) on the kernel sources should tell.
该限制会立即设置,但仅在尝试分配新堆栈或尝试增加现有堆栈时进行检查。内核源代码上的RLIMIT_STACK(或 LXR 标识符搜索)的 grep应该会告诉你。
Apparently, the initial size of the stack is whatever is needed to the filename + env strings + arg strings plus some extra pages allocated on setup_arg_pages
(20 pages in 2.6.33 1,2, 128 Kb on 2.6.34 3).
显然,堆栈的初始大小是文件名 + env 字符串 + arg 字符串以及分配的一些额外页面setup_arg_pages
(2.6.33 1、2、 2.6.34 3上的20 页中的 20 页)所需的任何大小。
In summary:
总之:
initial stack size = MIN(size for filename + arg strings + env strings + extra pages, MAX(size for filename + arg strings + env strings, RLIMIT_STACK))
where
在哪里
size for filename + arg strings + env strings <= MAX(ARG_MAX(32 pages), RLIMIT_STACK/4)
Additionally, kernels with Ingo Molnar's exec-shield
patch (Fedora, Ubuntu, ...) have an additional EXEC_STACK_BIAS "(2MB more to cover randomization effects.)", see the call to the new function over_stack_limit()
from acct_stack_growth()
([Ubuntu1], [Ubuntu2], [Ubuntu3]).
此外,带有 Ingo Molnarexec-shield
补丁的内核(Fedora、Ubuntu 等)有一个额外的 EXEC_STACK_BIAS “(多 2MB 来覆盖随机化效果。)”,请参阅over_stack_limit()
来自acct_stack_growth()
( [Ubuntu1]、[Ubuntu2]、[ Ubuntu3])。
I've edited the original program to show this:
我已经编辑了原始程序以显示这一点:
#include <stdio.h>
#include <sys/resource.h>
void foo(void);
int main(int argc, char *argv[]) {
struct rlimit lim = {1, 1};
if (argc > 1 && argv[1][0] == '-' && argv[1][8]=='l') {
printf("limiting stack size\n");
if (setrlimit(RLIMIT_STACK, &lim) == -1) {
printf("rlimit failed\n");
return 1;
}
}
foo();
return 0;
}
void foo() {
unsigned ints[32768];
printf("foo: %u\n", ints[2047]=42);
}
Which results in:
结果是:
$./rl
foo: 42
$./rl -l
limiting stack size
Segmentation fault
$
回答by pmg
I think setrlimit
moves the "resource pointers" but doesn't apply the new limits until you exec
a new copy of the program.
我认为setrlimit
移动“资源指针”,但exec
在程序的新副本之前不会应用新的限制。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/resource.h>
void foo(int chk) {
unsigned ints[2048];
ints[2047] = 42;
printf("foo %d: %u\n", chk, ints[2047]);
}
int main(int argc, char **argv) {
char *newarg[] = { "argv[0]", "one", "two" };
char *newenv[] = { NULL };
struct rlimit lim;
newarg[0] = argv[0];
getrlimit(RLIMIT_STACK, &lim);
printf("lim: %d / %d\n", (int)lim.rlim_cur, (int)lim.rlim_max);
switch (argc) {
case 1: /* first call from command line */
lim.rlim_cur = 65536;
lim.rlim_max = 65536;
if (setrlimit(RLIMIT_STACK, &lim) == -1) return EXIT_FAILURE;
newarg[2] = NULL;
foo(1);
execve(argv[0], newarg, newenv);
break;
case 2: /* second call */
lim.rlim_cur = 1024;
lim.rlim_max = 1024;
if (setrlimit(RLIMIT_STACK, &lim) == -1) return EXIT_FAILURE;
foo(2);
execve(argv[0], newarg, newenv);
break;
default: /* third call */
foo(3);
break;
}
return 0;
}
And a test run:
并进行测试运行:
$ ./a.out lim: 8388608 / -1 foo 1: 42 lim: 65536 / 65536 foo 2: 42 Killed
Why the process gets killed before printing the limits (and before calling foo), I don't know.
为什么进程在打印限制之前(以及在调用 foo 之前)被终止,我不知道。