2011-12-14 71 views
10

我有以下示例程序:execve(“/ bin/sh”,0,0);在管道

#include <stdio.h> 

int 
main(int argc, char ** argv){ 
    char buf[100]; 

    printf("Please enter your name: "); 
    fflush(stdout); 
    gets(buf); 
    printf("Hello \"%s\"\n", buf); 

    execve("/bin/sh", 0, 0); 
} 

我,当我运行没有它的作品,因为它应该任何管道,并返回一个sh PROMT:

bash$ ./a.out 
Please enter your name: warning: this program uses gets() which is unsafe. 
testName 
Hello "testName" 
$ exit 
bash$ 

但这不起作用在管道中,我想我知道这是为什么,但我无法找出解决方案。示例运行波纹管。

bash$ echo -e "testName\npwd" | ./a.out 
Please enter your name: warning: this program uses gets() which is unsafe. 
Hello "testName" 
bash$ 

我估计这事做与gets/bin/sh收到EOF和promtly没有一条错误信息退出这样的方式清空stdin的事实。

但是我怎样才能解决这个问题(如果可能的话,不要修改程序,如果不能删除gets),这样即使我通过管道提供输入,我也能得到一个提示?

P.S.我在一台FreeBSD(4.8)机器上运行这个程序DS

+6

***从不使用`gets`。它总是**打开缓冲区溢出安全漏洞。 – ThiefMaster 2011-12-14 17:53:21

+5

我知道;)...这是我大学安全实验室计算机上缓冲区溢出尝试的一部分。纯粹的学术。 = D – 2011-12-14 17:58:15

回答

10

你可以不喜欢这个任何修改运行程序:

(echo -e 'testName\n'; cat) | ./a.out 

这样可以确保你的程序的标准输入后不什么echo输出端。相反,cat将继续为您的程序提供输入。随后输入的来源是您的终端,因为这是cat读取的地方。

下面是一个例子会话:

bash-3.2$ cc stdin_shell.c 
bash-3.2$ (echo -e 'testName\n'; cat) | ./a.out 
Please enter your name: warning: this program uses gets(), which is unsafe. 
Hello "testName" 
pwd 
/home/user/stackoverflow/stdin_shell_question 
ls -l 
total 32 
-rwxr-xr-x 1 user group 9024 Dec 14 18:53 a.out 
-rw-r--r-- 1 user group 216 Dec 14 18:52 stdin_shell.c 
ps -p $$ 
    PID TTY   TIME CMD 
93759 ttys000 0:00.01 (sh) 
exit 

bash-3.2$ 

注意,由于壳的标准输入不连接到一个终端,sh认为它不是交互执行,因此不显示提示。不过,您可以正常输入命令。

+0

啊..是的,你是对的,(我确实设法在看到你的帖子之前找到这个解决方案,但是谢谢你把它放在这里)。 – 2011-12-14 18:20:53

1

不是100%确定的(使用精确的shell和操作系统可能会引发这些问题;我相信FreeBSD默认使用GNU bash作为/bin/sh? ),但是

  • sh可能正在检测到其输入不是tty。

  • 你的sh版本可能会进入非交互模式一样,也好象叫为sh,预计login会在前面加上一个-argv[0]它。设置execve ("/bin/sh", { "-sh", NULL}, NULL)可能会说服它正在作为登录shell运行。
3

使用execve("/bin/sh", 0, 0);对壳来说是一种残忍和不寻常的惩罚。它根本没有任何参数或环境 - 甚至没有自己的程序名称,甚至没有像PATH或HOME这样的强制性环境变量。