Další lokální zranitelností Linuxu je ssh-keysign-pwn. Uživatel si může přečíst obsah souborů, ke kterým má právo ke čtení pouze root, například soubory s SSH klíči nebo /etc/shadow. V upstreamu již opraveno [oss-security mailing list].
Singularity (YouTube) je nejnovější otevřený film od Blender Studia. Jedná se o jejich první 4K HDR film.
Vyšla hra Život Není Krásný: Poslední Exekuce (Steam, ProtonDB). Kreslená point & click adventura ze staré školy plná černého humoru a nekorektního násilí. Vžijte se do role zpustlého exekutora Vladimíra Brehowského a projděte s ním jeho poslední pracovní den. Hra volně navazuje na sérii Život Není Krásný.
Společnost Red Hat představila Fedora Hummingbird, tj. linuxovou distribuci s nativním kontejnerovým designem určenou pro vývojáře využívající AI agenty.
Hru The Legend of Zelda: Twilight Princess od společnosti Nintendo si lze nově díky projektu Dusklight (původně Dusk) a reverznímu inženýrství zahrát i na počítačích a mobilních zařízeních. Vyžadována je kopie původní hry (textury, modely, hudba, zvukové efekty, …). Ukázka na YouTube. Projekt byl zahájen v srpnu 2020.
Byla vydána nová major verze 29.0 programovacího jazyka Erlang (Wikipedie) a související platformy OTP (Open Telecom Platform, Wikipedie). Detailní přehled novinek na GitHubu.
Po zranitelnostech Copy Fail a Dirty Frag přichází zranitelnost Fragnesia. Další lokální eskalace práv na Linuxu. Zatím v upstreamu neopravena. Přiřazeno ji bylo CVE-2026-46300.
Sovereign Tech Agency (Wikipedie) prostřednictvím svého fondu Sovereign Tech Fund podpoří KDE částkou 1 285 200 eur.
Google na včerejší akci The Android Show | I/O Edition 2026 (YouTube) představil celou řadu novinek: Gemini Intelligence, notebooky Googlebook, novou generaci Android Auto, …
Evropská komise by do léta mohla předložit návrh normy omezující používání sociálních sítí dětmi v zájmu jejich bezpečí na internetu. Prohlásila to včera předsedkyně EK Ursula von der Leyenová, podle níž řada zemí Evropské unie volá po zavedení věkové hranice pro sociální sítě. EU částečně řeší bezpečnost dětí v digitálním prostředí v již platném nařízení o digitálních službách (DSA), podle německé političky to však není dostatečné a
… více »bool Shell::popen3(const string& command, pid_t* pid, Pipes3 pipes)
{
if (!pid) return false;
pid_t cpid;
int p_stdin[2], p_stdout[2], p_stderr[2];
if (pipe(p_stdin) || pipe(p_stdout) || pipe(p_stderr)) goto cleanup;
cpid = fork();
if (cpid < 0) goto cleanup;
if (cpid == 0)
{
//child process
close(p_stdin[P_WRITE]);
dup2(p_stdin[P_READ], STDIN_FILENO);
close(p_stdout[P_READ]);
dup2(p_stdout[P_WRITE], STDOUT_FILENO);
close(p_stderr[P_READ]);
dup2(p_stderr[P_WRITE], STDERR_FILENO);
execl("/bin/sh", "sh", "-c", command.c_str(), NULL);
exit(-1);
}
*pid = cpid;
pipes[P_IN] = fdopen(p_stdin[P_WRITE], "w");
pipes[P_OUT] = fdopen(p_stdout[P_READ], "r");
pipes[P_ERR] = fdopen(p_stderr[P_READ], "r");
return true;
cleanup:
close(p_stdin[P_READ]); close(p_stdin[P_WRITE]);
close(p_stdout[P_READ]); close(p_stdout[P_WRITE]);
close(p_stderr[P_READ]); close(p_stderr[P_WRITE]);
return false;
}
Celá funkce pracuje celkom dobře, akorát je problém s ukončením child processu.Řešení dotazu:
Po zavolání téhle funkce čtu stdin/stderr výstup child programu a nějak ho zpracovávám.
Můj (rodičovský) proces se tak zasekne na volání fgets/fgetc apod.Tohle čtete jak? Správně to musíte číst oboje najednou, tj. přes select() ... ideálně, pokud budete chtít i zapisovat, tak musíte selectovat všechny 3 roury, jinak může dojít k deadlocku mezi libovolnýma dvěma: např. Vy čekáte na výstup potomka a ten čeká na vstup od Vás, nebo potomek chce zapisovat do stderr, ale ten blokuje, protože má plný buffer, protože nečtete rouru stderr, protože jste zablokován čtením roury stdout. Všechny tyto problémy řeší zmíněný select(). Ad ukončení procesu potomka: Pokud potomek skončí (i neočekávaně), dostanete při čtení EOF (pokud se opravdu pokoušíte číst a nejste v deadlocku, viz výše) a při zápisu EPIPE (a signál SIGPIPE, který standardně Váš proces zabije, takže je vhodné to mít ošetřené). Ad zombie: Když potomek skončí, přejde do stavu zombie automaticky a zůstane v něm dokud si nevyzvednete jeho exit status pomocí nějakého volání z rodiny wait(). Při skončení potomka dostanete taky signál SIGCHLD, abyste věděl, že si máte status vyzvednout, záleží pak na logice Vaší aplikace, jestli to udělá hned, nebo v rámci např. čtecího cyklu. Management procesů je obecně netriviální záležitost. To ještě neřešíte např. ukončení potomků potomka (/bin/sh pouští další procesy), případně korektní ukončení (zabití) potomků, pokud se Vaše aplikace rozhodne skončit/spadne...
select() a zkusil implementovat, ale chová se to teď nějak úplně divně.
timeout.tv_sec = 5;
timeout.tv_usec = 0;
bool go_on = true;
while (go_on)
{
FD_ZERO(&set_r);
FD_SET(fileno(pipes[P_OUT]), &set_r);
nfds = max(nfds, fileno(pipes[P_OUT]));
FD_SET(fileno(pipes[P_ERR]), &set_r);
nfds = max(nfds, fileno(pipes[P_ERR]));
timeout.tv_sec = 1;
timeout.tv_usec = 0;
cout << "select: " << (success = select(nfds, &set_r, NULL, NULL, &timeout)) << "\n";
if (success == -1) return false;
go_on = false;
while (FD_ISSET(fileno(pipes[P_OUT]), &set_r))
{
fgets(buffer_r, BUF_LEN, pipes[P_OUT]);
out << "[stdout] " << buffer_r;
go_on = true;
}
if (FD_ISSET(fileno(pipes[P_ERR]), &set_r))
{
fgets(buffer_r, BUF_LEN, pipes[P_ERR]);
out << "[stderr] " << buffer_r << "\n";
go_on = true;
}
}
Tento kód vypíše pouze první řádku výstupu child procesu, potom už select() jen nulu,
ačkoli když přesto čtu stdin, jsou tam znaky k přečtení.
(Stdin zatím neuvažuju, dokud nerozchodím alespoň stdout a stderr.)
)

Srovnejte si select(2) a pselect(2), pokud chcete řešit souběh s nastavováním obsluh signálů.
Mimochodem timeout můžete nechat na nekončnu, protože příchodem signálu bude volání přerušeno a select() vrátí -1 a errno bude EINTR.
Já signály vůbec nezpracovávám
se už žádný signál neodešle
Tak jde o signály, nebo ne?
Když chcípne potomek, tak čtecí konec roury vrací EOF, na což samozřejmě select() zareaguje tím, že v množině čtecích deskriptorů se objeví připravený deskriptor, ze kterého read() vrátí 0.
Select při čtení z ukončeného procesu označí fd jako že z něj de číst, ale při čtení dostanete přečteno 0 bajtů = EOF.Mně se select() po skončení child procesu zasekne, pokud *timeout == NULL. Mám ověřené, že to je právě volání select(), na kterém se to zarazí.
Signál CHLD Vám přijde pokud ho neignorujete (nastavíte si handler).Je nějaký zásadní důvod, proč bych to měl dělat? Polling afaik ničemu nevadí. CPU nevytěžuje.
Mně se select() po skončení child procesu zasekne, pokud *timeout == NULL. Mám ověřené, že to je právě volání select(), na kterém se to zarazí.To je asi tím že neselectujete chybové stavy (třetí fdset).
Je nějaký zásadní důvod, proč bych to měl dělat? Polling afaik ničemu nevadí. CPU nevytěžuje.Maskujete si tím chybové chování.
To je asi tím že neselectujete chybové stavy (třetí fdset).Zkusil jsem do
exceptfds dát stind a stdout pajpy, ale select() se při *timeout = NULL stále zasekává.exceptfds jinak? Z man select to není úplně zřejmý...Maskujete si tím chybové chování.Sledovat, jestli
select() nevrací -1 nestačí?
exceptfds taky sleduju pro případný errory... no tak snad už to je plně košér
takže selectem neodlišim stav, kdy child potřebuje něco čístJelikož jsou mezitím různé buffery a potenciálně nemusí být příjemce ani na stejném stroji, tak to opravdu nepoznáte. Ale nedovedu si představit situaci kde byste něco takového využil. Normální duplexní protokoly fungují na principu požadavek a odpověď.
exceptfds taky sleduju pro případný errory... no tak snad už to je plně košérKdyž tak pro jistotu ještě ukažte jednou ten kód. Nezdá se mi, že by měl druhý fdset nějaký vliv na funkci prvního a třetího.
Když tak pro jistotu ještě ukažte jednou ten kód. Nezdá se mi, že by měl druhý fdset nějaký vliv na funkci prvního a třetího.Ok, ale upozorňuju, že ten kód je stále dost neučesanej, možná tam jsou proměnný navíc, instream(stdin) vyhodim, musim dodělat error handling při otevřených pajpách, ...atd.
bool Shell::issue(const string& command, ostream& out, istream& in, int* retvalue, bool* normal_exit)
{
if (!retvalue) return false; //ep_nodep
if (!normal_exit) return false;
if (command.empty()) return false;
Pipes3 pipes;
pid_t pid, w;
fd_set set_r, set_w, set_err;
int nfds = 0;
struct timeval timeout;
int success;
char buffer_r[BUF_LEN];
string buffer_w;
int bytes;
int child_status;
string prefix = command.substr(0, command.find_first_of(' '));
stringstream ss;
if (!popen3(command, &pid, pipes)) return false;
// interrogate child process output/(input)
bool go_on = true;
while (go_on)
{
FD_ZERO(&set_r);
FD_SET(pipes[P_OUT], &set_r);
nfds = max(nfds, pipes[P_OUT]);
FD_SET(pipes[P_ERR], &set_r);
nfds = max(nfds, pipes[P_ERR]);
FD_ZERO(&set_w);
FD_SET(pipes[P_IN], &set_w);
nfds = max(nfds, pipes[P_IN]);
FD_ZERO(&set_err);
FD_SET(pipes[P_OUT], &set_err);
FD_SET(pipes[P_ERR], &set_err);
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
if(select(nfds+1, &set_r, &set_w, &set_err, /*&timeout*/NULL) == -1 ) /* TODO: error */;
if (FD_ISSET(pipes[P_OUT], &set_err)) /*error*/;
if (FD_ISSET(pipes[P_ERR], &set_err)) /*error*/;
//if (FD_ISSET(pipes[P_IN], &set_w)) /*always*/;
if (FD_ISSET(pipes[P_OUT], &set_r))
{
bytes = read(pipes[P_OUT], buffer_r, BUF_LEN);
buffer_r[bytes] = '\0';
ss << buffer_r;
while (ss.good())
{
ss.getline(buffer_r, BUF_LEN);
if ((ss.gcount() > 0) && (strlen(buffer_r) > 0)) out << " [" << prefix << "] " << buffer_r << "\n";
}
ss.clear(); /* TODO: jeste nejak vyprazdnit stringstream*/
}
if (FD_ISSET(pipes[P_ERR], &set_r))
{
bytes = read(pipes[P_ERR], buffer_r, BUF_LEN);
buffer_r[bytes] = '\0';
ss << buffer_r;
while (ss.good())
{
ss.getline(buffer_r, BUF_LEN);
if ((ss.gcount() > 0) && (strlen(buffer_r) > 0)) out << " [" << prefix << "] " << buffer_r << "\n";
}
ss.clear();
}
/*if (FD_ISSET(fileno(pipes[P_IN]), &set_w))
{
/// TODO: oddelat stdin
}*/
w = waitpid(pid, &child_status, WNOHANG|WUNTRACED|WCONTINUED);
if (w == -1)
{
//TODO: error handling
go_on = false;
} else if (w != 0)
{
if (WIFEXITED(child_status))
{
*retvalue = WEXITSTATUS(child_status);
*normal_exit = true;
go_on = false;
} else if (WIFSIGNALED(child_status))
{
*retvalue = WTERMSIG(child_status);
*normal_exit = false;
go_on = false;
}
}
}
pclose3(pipes);
return true;
}
Nejspíš budu taky moct přehodit celou waitpid část až za smyčku, páč timeout může nyní být nekonečný.
/*error*/, protože ignorování chyby může být zdroj potíží úplně jinde. Když jsme u toho, vidím, že se snažíte o C++, tak co třeba zkusit občas něco thrownout?
Nejspíš budu taky moct přehodit celou waitpid část až za smyčku, páč timeout může nyní být nekonečný.Z principu věci by to mělo být až za smyčkou, protože smyčka by měla skončit až skončí proces (nebo při chybě). Podobně tak je možno naplnit všechny fdsety coby vzor před smyčkou a uvnitř smyčky inicializovat pracovní fdsety pomocí memcpy (select je zmodifikuje, takže inicializaci se nevyhnete, jen je to takto rychlejší). Poslední věc co by asi stála za zvážení je odsunout něco do separátních podprogramů, na mě je tam už moc lokálních proměnných.
Na error kontrolujte i P_IN.Ok, na to jsem zapomněl...
Když jsme u toho, vidím, že se snažíte o C++, tak co třeba zkusit občas něco thrownout?Hm, to bych případně mohl taky. Na jiných místech programu exceptions používám, takže proč ne... ještě ten error handling nějak vymyslim a zvážím to.
Podobně tak je možno naplnit všechny fdsety coby vzor před smyčkou a uvnitř smyčky inicializovat pracovní fdsety pomocí memcpy (select je zmodifikuje, takže inicializaci se nevyhnete, jen je to takto rychlejší).Jj, měl jsem tam dřív něco jako tmp_set_r a další, ale oddělal jsem je, protože jsem při hledání chyb podezříval kde co. Zas to dám zpátky.
Poslední věc co by asi stála za zvážení je odsunout něco do separátních podprogramů, na mě je tam už moc lokálních proměnných.Tjn, je toho tam trochu moc, taky už mi to vadí. Nějak to časem pořešim.
Popravdě řečeno by se mi asi nejvíc líbilo řešení, kdy funkce by vracely nějakou malou "úspěchovou" třídu,Smysl výjimek je v tom, že nemusíte vracet nic (a obvykle to co říkáte je pokryto více typy výjimek). Kód pak není přecpán if-y a navíc se obrací logika ignorace chyby - pokud s ní nic neuděláte tak program skončí, verzus pokud ignorujete návratovou hodnotu, tak se nestane nic.
Mít tak víc volnýho času, věčný to problém...Ten mám taky. Proto se snažím dokumentovat a psát pořádně hned od prvního řádku, abych pak po půl roce neměl chuť se za ten bordel nakopat do zadku.
Chtěl jsem tim říct, že obcházíte něco, co "nefunguje" jak by mělo.Maskujete si tím chybové chování.Sledovat, jestli select() nevrací -1 nestačí?
Tiskni
Sdílej: