2011-12-14 4 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 ПРОМТ:

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 опустошает stdin таким образом, что /bin/sh получает EOF и promtly завершает работу без сообщения об ошибке.

Но как мне обойти это (без изменения программы, если это возможно, и не удалять gets, если нет), так что я получаю промах, даже если я подаю вход через трубу?

P.S. Я бегу это на FreeBSD (4.8) машины DS

+6

*** НИКОГДА *** использовать 'gets'. Он ** всегда ** открывает отверстие для предотвращения переполнения буфера. – ThiefMaster

+5

Я знаю;) ...это часть попытки переполнения буфера на компьютере в лаборатории безопасности моего университета. Чисто академический. = D –

ответ

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

Ах .. да, вы правы, (мне действительно удалось найти это решение, прежде чем увидела ваш пост, но спасибо за то, что вы его поставили). –

1

Не 100% уверен в этом (точной оболочки используется, и ОС может бросить эти ответы немного, я считаю, что FreeBSD использует GNU bash по умолчанию как /bin/sh?), но

  • sh может обнаружить, что его вход не является tty.

или

  • Ваша версия sh может перейти в не-интерактивном режиме, как, что и при вызове в качестве sh, ожидая login будет предварять - на argv[0] для него. Настройка execve ("/bin/sh", { "-sh", NULL}, NULL) может убедить ее, что она запускается как оболочка входа.
3

Использование execve("/bin/sh", 0, 0); является жестоким и необычным наказанием за раковину. Он не дает никаких аргументов или среды вообще - даже не его собственное имя программы, и даже такие обязательные переменные окружения, как PATH или HOME.

+2

хорошо ... да, я согласен полностью, но это просто используется в качестве эксперимента. Я бы никогда не использовал его во всем, что было бы похоже на полезную программу. –

Смежные вопросы