【问题标题】:Execve problems when reading input from pipe从管道读取输入时执行问题
【发布时间】:2019-01-24 16:55:01
【问题描述】:

我编写了一个简单的 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 输出时的工作方式完全相同:

所以,结束我的问题:

  1. 我不明白为什么在从管道而不是标准输入读取输入时,执行的 shell 不打印$ 提示符。
  2. 当输入已经存在并且没有等待时,为什么执行的程序不会从管道中读取输入?它似乎只在命令执行后管道保持打开的情况下才有效。

【问题讨论】:

  • 如果标准输入不是终端,shell不会显示提示。

标签: linux pipe execve


【解决方案1】:

就像前面提到的 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] = '\0';

        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 进一步阅读。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-28
    • 1970-01-01
    • 2011-06-30
    相关资源
    最近更新 更多