在分叉进程中调用 Execve 的问题

Issues Calling Execve In Forked Process

我正在尝试创建一个非常基本的 telnet 服务器来练习内存损坏攻击。当我尝试发出命令时,在第一次迭代中没有任何反应。第二次迭代我在服务器端打印了多个错误的文件描述符错误。在客户端,一切似乎都很好。我得到了所有必需的提示。这是我的相关代码:

int piper[2];
pipe(piper);

...

     while (1) {
        n = write(newsockfd,"Enter a command...\n",21);
                if (n < 0) error("ERROR writing to socket");
                bzero(buffer,4096);
                n = read(newsockfd,buffer,4095);
                strcpy(command, buffer);
                pid_t childpid;
                childpid = fork();
                if(childpid == -1) {
                    perror("Failed to fork");
                    return 1;
                }
                if(childpid == 0) { //child
                    printf("I am child %ld\n", (long)getpid());
                    if(dup2(piper[1], 1) < 0) {
                        perror("Failed to pipe in child process");
                    }
                    else {
                        close(piper[0]);
                        close(piper[1]);
                        char *args[] = {command, NULL};
                        execve(command, args, NULL);
                    }
                }
                else { // parent
                    if(dup2(piper[0], 0) < 0) {
                        perror("Failed to pipe in parent process");
                    }
                    else {
                        // read command output from child
                        while(fgets(command_out, sizeof(command_out), stdin)) {
                            printf("%s", command_out);
                        }
                    }
                }
            }

如果我在我的客户端中输入 /bin/ls,我会在我的服务器上输出以下内容:

I am child 26748

我第二次这样做时,我将以下内容输出到我的服务器:

Failed to pipe in parent process: Bad file descriptor

0I am child 26749

Failed to pipe in child process: Bad file descriptor

有可能在子进程中关闭管道也会在父进程中关闭它。考虑在 while 循环的开头移动你的 piper(pipe)。为了安全起见,在文件循环结束时关闭管道,不要忘记测试关闭的 return 值。

实际上 read 在输入的末尾放置一个换行符,因此您的命令可能是例如 testprog 但实际上,当使用 read() 时,它是 testprog\n 所以你必须摆脱添加的换行符,否则 execve() 将期望程序名称中包含换行符。

#define STDIN 0
int n = read(STDIN, command, 4096);
command[n - 1] = '[=10=]';   // get rid of newline

char *args = { command, NULL };
execve(buf, &args[0], NULL);