在派生过程中调用Execve的问题

时间:2019-04-13 02:20:46

标签: c pipe fork exec dup2

我正在尝试创建一个非常基本的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

1 个答案:

答案 0 :(得分:2)

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

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

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

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