Edit: bedankt mensen, ik weet dat je er als andere gebruikers/admin/root dingen kan uitvoeren; de vraag is wat het technisch gezien doet. M.a.w., hoe doet su(do) dat? Hoe ziet een sudo-alternatief eruit?
Er zijn diverse implementaties van su, maar ze werken over het algemeen soortgelijk. Ik pak hier de versie van
su uit util-linux als referentie, aangezien dit de versie is die ik hier op Ubuntu draai; dit is dus wel su maar niet sudo. sudo doet ongeveer wat su doet, maar heeft nog een hele reeks opties om transparant dan wel niet transparant bepaalde commando's voor bepaalde groepen en gebruikers wel of niet uit te voeren.
Als allereerst worden de command line arguments ingelezen en wordt er bepaald wat er moet gebeuren. Daarna wordt het veilig inladen van de nodige configuratiebestanden klaargezet, en wordt het specifieke input device opgezocht zodat daar direct uit kan worden gelezen (zodat injectieaanvallen minder waarschijnlijk zijn en je niet je wachtwoord zomaar naar su kan pipen).
Vervolgens wordt de informatie van de huidige en de gewenste gebruiker opgevraagd en wordt die gevalideerd. Dit wordt gebruikt om de authenticatie uit te voeren (lees: het wachtwoord of je vingerafdruk of je smartcard wordt gevalideerd).
De juiste shell wordt vervolgens opgezocht, indien nodig, een call naar
initgroups() wordt gedaan om de groepenlijst bij te werken uit het bestandssysteem. De nodige resource limits (
zie bijvoorbeeld hier) worden voor de nieuwe gebruiker bijgewerkt en er wordt via PAM een sessie geopend zodat het systeem klaar is om van identiteit te wisselen.
Daarna wordt het proces geforkt, zodat er een kindproces is en een su-proces dat de boel in de gaten houdt en zodat de nodige oude data opgeschoond kan worden. Het kindproces wordt gebruikt om daadwerkelijk van user te wisselen.
Vervolgens roepen ze
setgid() en
setuid() aan. Deze APIs zijn alleen beschikbaar binnen binaries met een speciaal bestandssysteemattribuut (SUID voor setuid, SGID voor setgroupid). Ze vertellen de kernel om de proceslijst aan te passen en permissies en rechten zo aan te passen dat het proces vanaf dat moment het proces als een andere gebruiker en groep draait. su en tot zekere mate sudo draaien eigenlijk puur om het correct aanroepen van deze twee APIs.
Nu het proces als de bedoelde gebruiker draait, wordt het environment aangepast (zodat $HOME en dergelijke correct zijn) en verandert het programma de current directory naar de home directory.
Als er een commando is opgegeven wordt dat nu uitgevoerd, zo niet roept het programma de standaardshell aan via
execv(). execv vervangt het proces in het geheugen (laadt een nieuwe image in, roept de main() daarvan aan, doet alle geheugen en dergelijke van het huidige proces verdwijnent) en maakt dus geen child proces aan. Dit is waar su eindigt, tenzij execv mislukt en dan wordt er slechts een foutmelding geprint.
Je kunt je eigen su redelijk eenvoudig maken. Je moet de API aanroepen om de gebruiker te valideren, daarna de APIs voor UID en GID aanroepen, en je bent er eigenlijk al. Sterker nog, het valideren van gebruikers is technisch gezien optioneel! Als je binary de nodige attributen heeft, kun je direct setuid en setguid aanroepen!
Er komt bij de normale tools een hele hoop boekhoudwerk en C-API's kijken en de volgorde van dingen is extreem belangrijk; haal de volgorde door elkaar en je zou zomaar per ongeluk iedereen rootrechten kunnen geven!
Een wat uitgebreidere uitleg van hoe je dit in Rust zou kunnen implementeren kun je
hier vinden. Let wel, dit blog gebruikt nogal een... interessante stijl, als dat te veel is voor je kun je altijd nog de C-code van su en sudo lezen.
[Reactie gewijzigd door GertMenkel op 22 juli 2024 16:38]