Клиент Openssh навсегда блокируется, если stderr перенаправляется на stdout

Существует обходной путь и простая загрузка (Linux Flavor )ISO. Вы можете использовать Live Flavor любой ОС Linux, такой как CentOS, Kali Linux, Ubuntu и т. д....

2
28.05.2019, 19:17
2 ответа

Why is this happening?

Это cat, которое необходимо завершить до того, как оболочка доберется до echo. Это «блокировка навсегда», потому что catживет.

Is there a workaround?

В Bash я бы использовал подстановку процесса для запуска cat, который не блокируется. Когда catубрано, легко echo OK, только если все действительно в порядке (с &&или$?). Пример:

ssh -f … > >(cat -A) 2>&1 && echo OK; echo "The script goes on."

Теперь catработает до и после того, как sshпереходит в фоновый режим, но сценарий продолжается, как только sshэто делает (или как только sshдает сбой без перехода в фоновый режим ).

1
27.01.2020, 21:58

Когда ssh -f«переходит в фоновый режим» после подключения и аутентификации на хосте, он будет продолжать удерживать открытые дескрипторы своих исходных stdin, stdout и stderr, поэтому, если эти дескрипторы были подключены через каналы к другим процессам (, так как его stdout + stderr в вашем примере для cat -A), это будет иметь эффект сохранения этих процессов, даже если они больше не нужны.

sshдемонизирует себя, вызывая библиотечную функцию daemon(3), но вызывает ее с помощью noclose = 1, предотвращая перенаправление stdin/stderr/stdout из /dev/null.

Это было частично исправлено в последних версияхopenssh(для основного процесса управления --стандартного ввода и стандартного вывода в 2010 , стандартного вывода в 2016 ; для процесса сеанса --стандартный вывод в 2017 ), но если вам нужно запустить более старый ssh ​​или вам нужно, чтобы он также перестал цепляться за стандартный вывод, единственным «решением» может быть использование LD_PRELOADхак, который переопределяет функцию daemon(3)оболочкой, которая вызывает оригинал с помощью noclose = 0.

$ cat daemon-force-close.c
#define _GNU_SOURCE
#include <unistd.h>
#include <dlfcn.h>
#include <err.h>

int daemon(int nochdir, int noclose){
        static int (*orig)(int, int);
        if(!orig && !(*(void**)&orig = dlsym(RTLD_NEXT, "daemon")))
                errx(1, "%s", dlerror());
        return orig(nochdir, 0);
}

$ cc -shared -Wall -O2 daemon-force-close.c -ldl -o daemon-force-close.so

$ LD_PRELOAD=./daemon-force-close.so \
   ssh -Nf dummy@localhost -MS./ctlsock 2>&1 | cat -A
dummy@localhost's password:
$
[no Ctrl-C needed]
$ ssh -S ~/w/c/ctlsock dummy@localhost
Last login: Tue May 28 21:04:26 2019 from ::1
...
3
27.01.2020, 21:58

Теги

Похожие вопросы