Проблемы при чтении ввода из канала - PullRequest
0 голосов
/ 24 января 2019

Я написал простую программу на 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", он успешно запустил оболочку и отобразил знак $ как обычную оболочку, как видно на рисунке.

enter image description here

Затем я сделал следующее: я создал сервер, используя nc -l 12345, и запустил nc localhost 12345 | ./exec.Это сработало, но по какой-то причине я не могу понять, знак $ на этот раз не отображался.Я не мог понять причину этого.(демонстрирующие изображения прилагаются)

enter image description here enter image description here

Теперь вот самая странная вещь.Когда я пытаюсь передать путь программы и больше ввода через канал сразу, кажется, что выполненный процесс просто игнорирует ввод и закрывается.Например:

enter image description here

Но, если я запускаю следующее, оно работает точно так же, как и при выводе nc: enter image description here

Итак, в заключение мои вопросы:

  1. Я не понимаю, почему исполняемая оболочка не печатает знак приглашения $ при чтении вводаиз трубы вместо стандартного ввода.
  2. Почему исполняемая программа не считывает ввод с канала, когда ввод уже существует и не ожидает?Кажется, он работает только в тех случаях, когда канал остается открытым после выполнения команды.

1 Ответ

0 голосов
/ 24 января 2019

Как уже упоминалось в AlexP, знак приглашения отображается только тогда, когда ввод поступает с терминала.

Второй вопрос был хитрее: когда вы вызываете libc-функцию scanf, ее реализация не только потребляет /bin/sh из канала, но также сохраняет следующий входной сигнал ls его внутренние буферы. Эти внутренние буферы будут перезаписаны на execve, поэтому оболочка ничего не получит.

Вот ваш скрипт без 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

Я рекомендую эту прекрасную статью о буферизации для дальнейшего чтения.

...