从管道读取输入时执行问题
Execve problems when reading input from pipe
我写了一个简单的 C 程序来使用 execve 执行另一个程序。
exec.c:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char** argv) {
char path[128];
scanf("%s", path);
char* args[] = {path, NULL};
char* env[] = {NULL};
execve(path, args, env);
printf("error\n");
return 0;
}
我编译的:
gcc exec.c -o exec
并且在 运行 连接它并写入“/bin/sh”之后,它成功地 运行 shell 并像正常 $
一样显示符号 shell如图所示
然后我做了以下操作:我使用 nc -l 12345
和 运行 nc localhost 12345 | ./exec
创建了一个服务器。它起作用了,但是由于某些我无法理解的原因,这次 $
标志没有显示。我想不通这是为什么。 (附上演示图片)
现在,这是最奇怪的事情。
当我尝试通过管道一次传递程序路径和更多输入时,执行的进程似乎只是忽略输入并关闭。
例如:
但是,如果我 运行 以下它的工作方式与我通过管道传输 nc
输出时的工作方式完全相同:
所以,结束我的问题:
- 我不明白为什么执行的 shell 在从管道而不是标准输入读取输入时不打印
$
提示符号。
- 当输入已经存在且不等待时,为什么执行的程序不从管道读取输入?它似乎只在命令执行后管道保持打开状态的情况下才有效。
就像已经提到的 AlexP 一样,只有当输入来自终端时才会显示提示符号。
第二个问题比较棘手:当你调用 libc-function scanf
时,它的实现不仅会从管道中消耗 /bin/sh
,还会存储下一个输入 ls
它的内部缓冲区。这些内部缓冲区将被 execve
覆盖,因此 shell 什么也得不到。
这是你的脚本,没有 scanf 来验证这一点:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char** argv) {
char path[128];
read(0, path, 8); // consume `/bin/sh`
path[7] = '[=10=]';
char* args[] = {path, NULL};
char* env[] = {NULL};
execve(path, args, env);
printf("error\n");
return 0;
}
为什么带有 cat
的示例首先起作用?
那(可能)也是因为缓冲。尝试:
(echo /bin/sh; echo ls) | stdbuf -i0 ./exec
我推荐 this nice Article about buffering 进一步阅读。
我写了一个简单的 C 程序来使用 execve 执行另一个程序。
exec.c:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char** argv) {
char path[128];
scanf("%s", path);
char* args[] = {path, NULL};
char* env[] = {NULL};
execve(path, args, env);
printf("error\n");
return 0;
}
我编译的:
gcc exec.c -o exec
并且在 运行 连接它并写入“/bin/sh”之后,它成功地 运行 shell 并像正常 $
一样显示符号 shell如图所示
然后我做了以下操作:我使用 nc -l 12345
和 运行 nc localhost 12345 | ./exec
创建了一个服务器。它起作用了,但是由于某些我无法理解的原因,这次 $
标志没有显示。我想不通这是为什么。 (附上演示图片)
现在,这是最奇怪的事情。 当我尝试通过管道一次传递程序路径和更多输入时,执行的进程似乎只是忽略输入并关闭。 例如:
但是,如果我 运行 以下它的工作方式与我通过管道传输 nc
输出时的工作方式完全相同:
所以,结束我的问题:
- 我不明白为什么执行的 shell 在从管道而不是标准输入读取输入时不打印
$
提示符号。 - 当输入已经存在且不等待时,为什么执行的程序不从管道读取输入?它似乎只在命令执行后管道保持打开状态的情况下才有效。
就像已经提到的 AlexP 一样,只有当输入来自终端时才会显示提示符号。
第二个问题比较棘手:当你调用 libc-function scanf
时,它的实现不仅会从管道中消耗 /bin/sh
,还会存储下一个输入 ls
它的内部缓冲区。这些内部缓冲区将被 execve
覆盖,因此 shell 什么也得不到。
这是你的脚本,没有 scanf 来验证这一点:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char** argv) {
char path[128];
read(0, path, 8); // consume `/bin/sh`
path[7] = '[=10=]';
char* args[] = {path, NULL};
char* env[] = {NULL};
execve(path, args, env);
printf("error\n");
return 0;
}
为什么带有 cat
的示例首先起作用?
那(可能)也是因为缓冲。尝试:
(echo /bin/sh; echo ls) | stdbuf -i0 ./exec
我推荐 this nice Article about buffering 进一步阅读。