ssh session close -> kill running process

Fórumok

Próbáltam rákeresni, de valahogy mindenkinek az a kérdése, hogy hogy oldja meg, hogy ne lője ki az ssh a folyamatot, amikor kilép vagy megszakad. Nekem meg pont az a problémám, hogy a picsáért nem lövi ki?

Egy bash script fut, normál esetben amíg él a session, addig az alsó állapot van, majd amikor megszakad az ssh, akkor nem kilövi, hanem felkerül a systemd alá...

systemd─┬─acpid
        ├─agetty
....
        ├─mgmt-host-onlin───sleep
....
        ├─sshd───sshd───sshd───mgmt-host-onlin───sleep

....

Wtf, miért?

Plusz infó, hogy mindezek mellett az a furi, hogy az sshd nélkül közvetlen a systemd alatt futó script bár ott van mint process, nem is zombi, látszólag fut is, de gyakorlatilag nem (írnia kéne egy fájlba, de nem ír).

Hozzászólások

Szerkesztve: 2021. 06. 22., k – 16:44

Mivel a systemd az init. Ezert az oszzes elarvult processz hozza kerul. Igy mukodik a unix.

Az sshd serveraliveinternval parameterekkel szabalyoznam hogy disconnectalja az elarvult sessionokat, amik meg fogjak kapni a HUP signalt. 

A scriptnek meg regalnia kell a HUP-ra. Amivel normal esetben jol kezel. De ha nem te irtad, akkor nohup vagy trap dologkra keress ra. Vagy egyszeruen futo scriptet probalj HUP signallal megkillelni, es nezd mit csinal ra.

"Mivel a systemd az init. Ezert az oszzes elarvult processz hozza kerul."

És ez miért magyarázat rögtön a problémára?

"Igy mukodik a unix."

Szerintem meg nem, mert ha a szülő ki lesz lőve, akkor az összes childnak is ki kéne dögölnie, amelyik meg nem áll le vagy nem tud leállni, abból lesz a zombi, de fixme.

"Az sshd serveraliveinternval parameterekkel szabalyoznam hogy disconnectalja az elarvult sessionokat, amik meg fogjak kapni a HUP signalt."

ServerAliveInterval kliens oldali konfig, ClientAliveInterval a szerver oldali... Amivel nincs is probléma, hiszen az SSH sessionök eltűnnek, csak a benne futó cucc nem. Amellett hogy semmit nem tenne hozzá, mondjuk hogy a kliens oldalra nincs befolyásom (jelenleg van, de ez most mindegy, mert a cél az, hogy kihajítsa a kapcsolatot és mindent ami fut.

"A scriptnek meg regalnia kell a HUP-ra."

Szerintem blődség. Szóval ha valaki direkt ki akar cseszni velem, akkor elindít egy végtelen scriptet, ami nem reagál a HUP-ra, sem semmilyen más signalra, fut a végtelenbe és nem tudom kilőni?

Továbbá kérdés, hogy ha a systemd alatt a script tovább fut, akkor miért nem fut?

"Sose a gép a hülye."

"Szerintem meg nem, mert ha a szülő ki lesz lőve, akkor az összes childnak is ki kéne dögölnie, amelyik meg nem áll le vagy nem tud leállni, abból lesz a zombi, de fixme."

Ha a child hallgat a SIGHUP-ra, akkor ki lesz lőve, amúgy nem. Nem ebből lesz a zombi, hanem ebből árva (orphan) lesz, amit hamarosan adoptál az init. Zombi akkor lesz, ha ő maga leáll, csak a szülő nem olvassa be az exit kódját.

"Szerintem blődség. Szóval ha valaki direkt ki akar cseszni velem, akkor elindít egy végtelen scriptet, ami nem reagál a HUP-ra, sem semmilyen más signalra, fut a végtelenbe és nem tudom kilőni?"

SIGKILLre biztos reagálni fog, mert azt nem lehet elkapni. Ha valaki nohuppal indít valamit, az még nem kicseszés.

Köszi az infókat.

Csak a tisztánlátás végett:

- az SSH szerverben egy ForceCommand van, jelenleg ez a script, ami pillanatnyilag annyit csinál, hogy egy végtelen ciklusban (while true) beír egy sort a /tmp/alive.txt-be + sleep X másodperc. Nincs nohup és semmi egyéb sem.

- az SSH-ra fellép a kliens, a scriptnek addig kell futnia, amíg él a kapcsolat

- ha a kliens akármi miatt eltűnik, legyen az hálózati hiba, vagy én kilövöm force az ottani ssh klienst, akkor az említett jelenség van, tehát az ssh eltűnik, a futó script bemegy a systemd alá, és elvileg fut, gyakorlatilag nem ír a fájlba innentől.

Amit szeretnék, hogy ami fut az SSH sessionbe, bármi is legyen az, legyen kilőve ha a session megszakadt.

"Sose a gép a hülye."

Sose használtam a ForceComamndot, de gyanítom, az olyan dolgokra van kitalálva, ami megáll magától, úgyhogy lehet, hogy az SSH maga nem gondosodik ennek leállításáról. Amúgy ennek mi értelme van, hogy valamit ssh bejelentkezéskor végtelenségig futtassunk? Ha ezt valami auditra használod, azt nem túl nehéz kijátszani.

Ha már mégis ilyet akarsz, indítsd .bashrc-ből (vagy ami shell indul, annak a megfelelő fájljából).

A ForceCommand a leírás szerint annyi, hogy ezt futtatja bejelentkezéskor, nem a shellt és a nem a user által megadott commandot, ez így rendben is van, egyéb dologra nincs szükség.

Pont nem a végtelenségig kellene futnia, hanem addig, amíg él az SSH session. Nem audit, egy technikai SSH lesz, amire a kliensek kulccsal automatán fognak belépni.

Ha feltesszük hogy az indított cucc nem bugos és nem lehet belőle kijutni vagy egyéb dolgot elindítani, akkor ez a ForceCommand kiváló egy korlátozott felhasználónak egyéb beállítás (ChrootDir és környezet létrehozása) nélkül.

"Sose a gép a hülye."

Ha nincs terminál (lásd ssh -t és -T), akkor a távoli gyerek csak attól fog meghalni, mert megpróbál beleolvasni az stdinbe, és ott EOF-ot kap, vagy megpróbál beleírni az stdout/stderr-be, és hibát (meg by default SIGPIPE-ot) kap. Ha a távoli gyerek nem olvas és nem ír, vagy eleve át van irányítva a /dev/null-ra mindene, akkor így nem fog leállni, csak ha explicite küldesz neki egy signalt.

Ha van terminál, akkor az más eset, mert ott a terminál fő processze fog kapni SIGHUP-ot, amivel aztán vagy kezd valamit, vagy nem. A shellek jellemzően szoktak, de ha eleve nem futtatsz shellt, akkor a programodnak kell eléggé okosnak lennie. Az külön plusz lépéseket igényel a shellből terminál alól indított programoknál, hogy túl tudják élni a shell távozását (lásd még hogyan írjunk daemonokat), tehát alapból a shell takarít. Amúgy nem tudom, hogy terminál használata esetén elkerülhető-e a shell funkcionalitás (úgy tippelném, hogy nem), azaz okés-e, hogy shell helyett eleve egy random programot indítasz az sshd alatt, ami nincs felkészítve arra a feladatra, amit egy shell a terminálon beállít induláskor. Nem lennék meglepve, ha a Ctrl-c és társai nem működnének korrektül ilyen esetekben. És persze a SIGHUP-ot is korrektül kéne kezelnie a random programnak.

scripted nezze meg hogy a parent process mi es ha nem az sshd akkor lepjen ki a loopbol

neked aztan fura humorod van...

Ez teljesen normális:

Ha egy process indít egy child process-t, értelemszerűen a child process parentje az első process lesz aki indította. Ha az első process elhal, a child process "orphaned" státuszba kerül.

Amint "orphaned" státuszba kerül, a linux kernel automatikusan elindít egy "reparenting" folyamatot. Ilyenkor alapesetben az init process kapja meg a "parent" státuszt a child process-hez. Ez utóbbit, hogy ilyen esetben kihez kerül a child, meg is lehet határozni (subreaper process).

Ha a reparenting megtörtént, akkor az új parent felelőssége, hogy a child process-t megfelelően lezárja. Mert hiába crash-el el, vagy lép ki a child process, egészen addig ott marad, míg a parent nem olvassa ki a return value-t (megfelelően lekezelve a SIGCHLD-et). Ha ez soha nem történik meg, ők lesznek a Zombie (defunct) processek

// Happy debugging, suckers
#define true (rand() > 10)

Hú, köszi a részletes leírást! :) Ezzel kapcsolatban csak az a kérdésem, hogy miért nem fut a script tovább (miután átkerült a systemd alá, nem ír a fájlba)?

Akkor csak annyi maradt, hogy hogy lehet ezt elkerülni, hogy ne történjen ez? Elsősorban SSH szinten, mert szerintem az lenne a megfelelő út, ha ez nem megoldható, akkor másodsorban a scriptben. Közben egyébként keresgettem tovább, és ezt találtam: https://stackoverflow.com/questions/33713680/ssh-force-command-executio…

"The ForceCommand option runs without a PTY unless the client requests one."

Szóval lehet, hogy ez a egész amiatt van, hogy nincs PTY? Lehetne, hogy mégis legyen?

"Sose a gép a hülye."

Ahogy fentebb írták, strace -el nézz bele a processekbe, hogy pontosan mire és kire várnak. A systemd nem fogja kezelni az orphan process-t, ő meghagyja zombinak ;)

De egy gyors tipp: az ssh szerintem normális körülmények között megáll és erről küld signal-t a scriptednek (ha az sshd elveszti a handler-t, akkor egy SIGHUP -al megemlékezik róla), hogy lépjen ki, de ezt a scripted nem teszi meg.

valahogy így:

function sighup_handler() {
 ...
 exit 1
}

trap 'sighup_handler' 1

// Happy debugging, suckers
#define true (rand() > 10)

Az a baj, hogy nem jut el idáig, tehát nem küld. Itt egy demo script:

#!/bin/bash

RUN=1
SLEEPPID=-1

function stop() {
    echo "`date` stop" | tee -a /tmp/mgmtnew.log
    RUN=0
    kill -9 $SLEEPPID
}

trap "stop" SIGHUP SIGQUIT SIGTERM SIGINT SIGUSR1

while [[ $RUN -eq 1 ]]; do
    echo "`date` check-in" | tee -a /tmp/mgmtnew.log
    sleep 3 &
    SLEEPPID=$!
    wait $SLEEPPID
done

echo "`date` exited" | tee -a /tmp/mgmtnew.log

Soha nem láttam a logban sem stop, sem exit sort....

 

De már azt is ki próbáltam, hogy mi történik ha mást indítok: ugyanez.

ForceCommand cat /dev/zero > /dev/null
 

És ugyanúgy "fut" tovább a cat a systemd alatt a session lezárása után.

"Sose a gép a hülye."

Itt, eszerint az látszik, hogy a script továbbra is fut, 3 másodpercenként lefut aminek le kell.

Más, ettől független, további érdekesség: Nincs ForceCommand, beállítottam a user shelljének ezt a scriptet. A jelenség ugyanaz, mint forcecommand-dal.

"Sose a gép a hülye."

Szóval... Igen, az a probléma, hogy nincs TTY. Nem tudom miért, így nem öli meg a subprocesst az ssh amikor bezárja a sessiont.

Adtam az SSH kliensnek egy -t kapcsolót.

"Pseudo-terminal will not be allocated because stdin is not a terminal."

Adtam neki -tt kapcsolót (force). Így lett terminálja a loginnál, és le is áll a process amikor bármilyen oknál fogva leáll a session.

De ez így akkor is nagyon gáz szerintem....

"Sose a gép a hülye."

a tty hiánya fölött elsiklottam, pedig ez mindent megmagyaráz. ilyenkor jön be a background/foreground process group / session -ök és hasonszőrű társaik :D de itt már nem mennék bele mély mesébe, mert annál komplexebb a szituáció, de van rá magyarázat :)

// Happy debugging, suckers
#define true (rand() > 10)

Szia, a systemd-logind user sessionök v230 óta tudják ezt. A felhasználó munkamenete után bezárják az összes folyamatot amit a user indított (a user által indított daemonokat is). 

Lásd ezt: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=825394

Ahhoz, hogy egy ssh login systemd-logind session legyen kapcsold be a PAM-ot. (UsePAM=yes az sshd.conf-ban). Elvileg minden distróban alapból benne van az a PAM script ami által így alapból az ssh sessionök automatikusan systemd-logind sessionök is lesznek.

A KillUserProcesses az true-ra van állítva a longind.conf-ban?

https://manpages.debian.org/testing/systemd/logind.conf.5.en.html

A KillOnlyUsers, KillExcludeUsers beállítások nem tiltják a kívánt felhasználóra a működést?

EDIT:

Be van kapcsolva by default

upstream ssh-ban a UsePAM alapértelmezett értéke no.