Ontwikkelaars werken aan herschrijven van sudo en su naar Rust

Een team van ontwikkelaars is bezig met het herschrijven van Linux-superusercommando's sudo en su. Die worden herschreven van C naar Rust. Dat zou veiliger moeten zijn, specifiek op het gebied van geheugenveiligheid.

Het project heet sudo-rs en kan worden gevolgd op GitHub. Het doel is aanvankelijk om een Rust-versie van de tool te maken die 'de meeste basissudo-commando's' kan vervangen. De ontwikkelaars hebben ook een roadmap online gezet. In de eerste fase werkt sudo-rs alleen op Linux, later moeten daar ook andere Unix-systemen aan worden toegevoegd.

De eerste stappen na de voorbereidende fase zijn om authenticatie via Pluggable authentication modules toe te voegen, een sudogebruikersbeleid te maken en om een eerste test op Ubuntu 22.04 te draaien. Pas in de tweede fase moet er su-implementatie worden toegevoegd en worden er meer beveiligingsaspecten toegevoegd. In de laatste stap worden er enterprisefeatures toegevoegd zoals ondersteuning voor LDAP, hostnamematching, auditing en passwd- en Kerberos-authenticatie.

Het project wordt uitgevoerd door het Prossimo Project, een samenwerkingsverband tussen de Nederlandse softwareontwikkelaar Tweede Golf en Rust-ontwikkelaar Ferrous Systems. De makers krijgen een donatie van AWS om het project te doen. De makers zeggen dat er meerdere redenen zijn om juist sudo om te schrijven naar het veiligere Rust. Zo wordt de tool veel gebruikt op belangrijke en kritieke systemen en heeft de functie zelf ook een kritiek doel. Daarnaast is sudo nu in C geschreven, wat volgens de makers extra veel risico oplevert voor geheugenproblemen.

Door Tijs Hofmans

Nieuwscoördinator

01-05-2023 • 09:03

130

Submitter: TheVivaldi

Reacties (130)

130
129
62
11
0
51

Sorteer op:

Weergave:

@TijsZonderH Een van de eigenaren van Tweede golf hier. Kleine correctie: Tweede golf is een software ontwikkelaar, geen beveiligingsbedrijf. En net als Ferrous Systems een Rust specialist, al communiceren wij dat wat minder primair.

We doen de ontwikkeling in een mixed team met engineers van ons en Ferrous Systems, 50-50.
Is dit een verkennend project voor jullie om meer zich te krijgen op het porteren naar Rust en misschien wel om meer code (andere programma's) om te schrijven voor dit platform in de toekomst?
Ik werk bij Tweede golf (maar niet op dit Sudo project). We hebben heel veel projecten die we in Rust doen!
De verkennende fase zit er al lang op en doen zelf erg veel met Rust.

We hebben veel op onze github staan: https://github.com/tweedegolf
Maar sommige van onze projecten staan ook in andere organisaties.
Zo zijn we ook bezig met NTP en PTP in Rust: https://github.com/pendulum-project

Zelf ben ik al ruim drie jaar (bijna) fulltime embedded firmware aan het schrijven in Rust en ik wil niet meer terug naar C of C++.
Is tweede golf een referentie naar een zeker bedrijf met een soort van noordelijke golf? :)
Eerlijk gezegd heb ik geen idee wat je bedoelt.
De naam is een referentie naar de tweede internet golf nadat de dotcom bubble barstte. Natuurlijk nu niet zo relevant meer.
Ik doelde op Northwave :)
Wat doet su(do) nou eigenlijk, technisch gezien

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?

[Reactie gewijzigd door Gamebuster op 22 juli 2024 16:38]

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]

Sudo gaat wel iets verder dan alleen dit. Je verhaal klopt voor de standaard sudo/wheel gebruiker die volledige root-rechten krijgt.

Maar het is ook mogelijk om via sudo een gebruiker rechten te geven voor een specifiek commando.
Zo kan je bijvoorbeeld developers rechten geven de webserver & database-server te herstarten, maar verder niks.
Inderdaad, maar dit is niet veel meer dan een whitelist uitlezen uit een configuratiebestand en die matchen met het commando dat opgegeven is (en aan de gebruiker/groep/etc. natuurlijk).

Er zit een hele hoop code omheen om te zorgen dat de juiste authenticatiemodi worden gebruikt, om de config goed te parsen, om goed te kunnen werken in speciale omgevingen, om verschillende implementaties van exec te gebruiken, enzovoorts, maar onder de streep is het een uitgebreide versie van "slim su implementeren".

Dat is juist het mooie aan sudo, eigenlijk is het een heel simpel programma dat heel compleet is uitgewerkt. Hoe simpeler het programma is, hoe minder logicafouten er in kunnen sluipen en hoe veiliger het programma uiteindelijk wordt.

De su-aanpak werkt ook gewoon heel goed, je ziet bijvoorbeeld in de broncode (van de Windows-XP-versie) van runas.exe dat ze een soortgelijk model gebruiken.

De sudo-versie van Windows (UAC) is echter een stuk complexer omdat die direct integreert met het Windows-authenticatiesysteem (waar Linux daar PAM als losse API voor heeft).
Heh, wat?
<Numa> Using this program requires you to be able to type an emoji. Most attack code is of such poor quality that they are unable to run commands named with emoji. This makes the program secure.
Dus die Numa' s emoji applicatie heeft SUID bit opstaan en voert gewoonweg uit wat je er als argument aan geeft als root. En die persoon beweert dat het veilig is omdat de meeste attack code geen emojis accepteert?

Interessante manier om een gigantisch groot security-gat in je systeem te hebben. Ik denk dat Numa eigenlijk zelfs gewoonweg een trojan bij iedereen aan het proberen te installeren is. Die 'software' hoort dus helemaal niet in package managers te komen. Het is malware.

Ik neem aan dat dit het enige interessante aan de blog is:
Command::new(program).args(args).uid(0).gid(0).exec().into()
En ik neem aan dat die .uid(0) en .gid(0) hetzelfde zijn als (= een Rust binding zijn voor) setuid(0) en setgid(0) in POSIX C. Rust voegt dus eigenlijk helemaal niets toe (kan ook niet, je moet die syscalls hoe dan ook ergens gebruiken). De Rust implementatie doet exact hetzelfde als de C implementatie.

[Reactie gewijzigd door Verwijderd op 22 juli 2024 16:38]

Ik denk dat weinig virussen zullen proberen om 🥺 uit te voeren om root te verkrijgen, maar in theorie is het mogelijk. Ik zou het ook niet op mijn machine installeren, al was het maar omdat de emoji lastig te typen is (control + ; en dan "plead" en dan spactie i.p.v. sudo).

Het blog dan ook niet bedoeld als serieus advies, meer als uitleg van hoe het systeem werkt, en hoe simpel de functionaliteit die daadwerkelijk je proces verheft eigenlijk is.

Rust doet inderdaad hetzelfde als C in dit geval, en dat zal het ook gaan doen bij het oorspronkelijke sudo-project. Onder de streep is su/sudo niet meer dan setuid en setgid aanroepen na wat checks, je kunt het lastig heel anders gaan doen. Rust abstraheert dit door de group/user-ID-wijzigingen in te bouwen in de standaardlibrary voor het uitvoeren van processen in plaats van het losse functiecalls te maken.

Het grote voordeel zit hem eigenlijk in iets waar ik zelf hierboven niet veel over heb gezegd, maar wat wel een risico is: tijdens het bepalen van het juiste commando om uit te voeren wordt er een reeks string-operaties gedaan om de execve-call goed te laten verlopen. Strings is een van de plekken waar Rust (en C++, en de meeste andere talen) een stuk veiliger in zijn dan C, helemaal als die strings een arbitraire lengte hebben die de gebruiker zelf kan opgeven.

Door de hele code heen zitten xmalloc/xcallocs verstopt die allemaal los beheerd moeten worden en het zou niet de eerste keer zijn dat een C-programma daardoor in de problemen komt. Zie bijvoorbeeld deze kwetsbaarheid waarbij een heap overflow iedereen toegang gaf, of deze waar een fout in het parsen van whitespace leidde tot een kwetsbaarheid waarmee bestanden kunnen worden overschreven.

Die Numa is trouwens geen echt persoon, dat is een denkbeeldig karakter dat de auteur gebruikt voor haar Socratische blogstijl.
Het lijkt me vrij duidelijk dat je dat niet al te serieus moet nemen. :) Er staat nogal wat context omheen als er een risico bestond dat het op zichzelf ambigu zou zijn. ;)
Hey, uitleg! Bedankt! Die blog is leuk, ik ga ook emoji commands aanmaken

[Reactie gewijzigd door Gamebuster op 22 juli 2024 16:38]

Ik heb hier nog ergens de broncode liggen van een tool genaamd 'brt & rni'. De eerste afkorting stond voor Be RooT, de tweede voor Root Not Included. Ik heb het ooit geschreven tijdens mijn studietijd als vervanging voor een andere su replacement dat daar algemeen gebruikt werd.

Good times :) .
Technisch gezien doet sudo het volgende:

Authenticatie: Wanneer je sudo gebruikt, wordt meestal om je wachtwoord gevraagd. Dit is om te controleren of jij de bevoegdheid hebt om het commando uit te voeren. Deze authenticatie wordt doorgaans geconfigureerd in het /etc/sudoers-bestand of via de visudo-editor.

Autorisatie: sudo controleert of de huidige gebruiker gemachtigd is om het gevraagde commando uit te voeren. De configuratie in het /etc/sudoers-bestand bepaalt welke gebruikers welke commando's mogen uitvoeren en met welke bevoegdheden.

Uitvoeren: Als de gebruiker geauthenticeerd en geautoriseerd is, voert sudo het gevraagde commando uit met de beveiligingsrechten van de doelgebruiker (meestal root).

Logging: sudo houdt een log bij van alle commando's die met sudo zijn uitgevoerd, zodat systeembeheerders kunnen bijhouden welke acties zijn uitgevoerd en door wie.

Een alternatief voor sudo is het su (substitute user) commando. su stelt je in staat om van gebruiker te wisselen in een terminalsessie, waarbij je het wachtwoord van de doelgebruiker moet invoeren. In tegenstelling tot sudo, verleent su je de rechten van de andere gebruiker voor de gehele sessie, en niet slechts voor één enkel commando.

Een ander alternatief is doas, dat voorkomt in sommige BSD-systemen. doas is ontworpen om eenvoudiger te configureren en lichter te zijn dan sudo, maar biedt vergelijkbare functionaliteit.
M.a.w., hoe doet su(do) dat? Hoe ziet een sudo-alternatief eruit?
sudo is een 'setuid root' binary. Dat betekent dat die draait met alle rechten van de almachtige 'root'-gebruiker, ook als je die aan aanroept als gewone gebruiker. Als root kun je alles doen wat je wil.
su werkt vergelijkbaar.

Het praktische verschil tussen 'su' en 'sudo' is dat je met 'su' echt alles mag zonder verdere beperkingen, terwijl je 'sudo' nog kan inperken zodat de gebruiker alleen bepaalde commando's met root-rechten kan uitvoeren.
En dat su het root-wachtwoord vraagt, terwijl sudo je eigen wachtwoord wilt hebben.
Dat laatste is heel handig om mensen root-rechten te geven zonder ze het root-wachtwoord te geven.

[Reactie gewijzigd door hackerhater op 22 juli 2024 16:38]

Hier ben ik ook wel benieuwd naar. Hoe ontsnapt sudo uit die beperkte omgeving om dingen als een hogere user uit te voeren? En waarom kunnen andere toepassingen dat niet? Is het een applicatie (want zo ja, dan zou je verwachten dat andere applicaties dat ook zouden moeten kunnen) of zit in de shell "ingebakken" dat hij bij su geen applicatie gestart moet worden maar dat hij iets in de kernel moet aanroepen oid?
Het 'suid' bestandspermissie bepaalt dat die applicatie uitgevoerd wordt met het account van de bestandseigenaar. Voor su(do), passwd, etc. is dat root (uid=0).
Men moet technisch gezien met de SUID bit (of hier) op de (su of sudo) binary gezet, setuid() of seteuid() en setgid() of setegid() doen, en dan uiteraard de normale fork() en execv(), of wat je ook wil doen onder de UID van de eigenaar van de binary (su of sudo hebben zoals je al aangaf als eigenaar root). Applicaties zoals gdm2 (GNOME Display Manager) en login zullen ook zoiets doen wanneer je inlogged als een bepaalde gebruiker. The passwd binary heeft dit ook opstaan zodat het passwords van accounts kan wijzigen.

[Reactie gewijzigd door Verwijderd op 22 juli 2024 16:38]

Lees de 'fine manual'

man sudo
sudo, sudoedit — execute a command as another user
man su:
su - run a command with substitute user and group ID
su allows commands to be run with a substitute user and group ID.

When called with no user specified, su defaults to running an
interactive shell as root. When user is specified, additional arguments
can be supplied, in which case they are passed to the shell.

[Reactie gewijzigd door 12_0_13 op 22 juli 2024 16:38]

Ik dacht altijd dat het een actie uitvoeren is als superuser, namelijk door su(superuser)do "superuser do" oftewel voer een command uit als root.
Een wijze collega hamerde er in het begin van mijn baan steeds op om alles wat je nog niet kent, even na te lezen in de 'man' pages. Superleerzaam gebleken :)
Maar dan moet je wel eerst Linux hebben draaien. Als een Windows gebruiker de vraag stelt dan help verwijzen naar "man" niet veel.
Verwijderd @Z801 mei 2023 11:16
wsl --install Ubuntu en dan kan jij op een standaard Windows ook meegenieten van man pages.
Herhaal. Dan moet je wel eerst Linux draaiend hebben.
Live usb, virtual of op drive geïnstalleerd.
Er wordt met wsl windows subsystem for linux bedoeld:
https://learn.microsoft.com/en-us/windows/wsl/about

Is geen Linux, maar een subsysteem wat je kan installeren vanuit Windows.
Weet ik. Maar vereist nog steeds een Linux install.
Links om of rechtsom je moet Linix hebben draaien om "man" te gebruiken.
Nope. Google op "man <commando>" en je komt de manual pagina tegen. https://linux.die.net heeft nagenoeg alle man-pagina's online beschikbaar.
"man sudo" geeft op google anders precies het juiste resultaat O-)
su , on the other hand, is an acronym for switch user or substitute user
Welke van de twee bedoel je? `su` zorgt ervoor dat je kan veranderen van user. Als die user `sudo` is wordt het: `sudo su -`. Als je gewoon iets wil draaien/uitvoeren als root is het `sudo <filename>` bijvoorbeeld.
`sudo su -`
sudo -s
de su staat niet voor superuser, maar voor set user. Het is eigenlijk een referentie naar de set user API van de linux kernel waar su en sudo gebruik van maken.

[Reactie gewijzigd door Jordy141 op 22 juli 2024 16:38]

Je wisselt ermee van account (su), of je voert een commando uit namens een andere user (sudo).
`su -u myuser /bin/bash` wisselt niet van account, maar voert een commando uit names een andere user...
Het verhoogt je privileges. Een beetje vergelijkbaar met admin/superuser zijn op Windows. Bij Linux (en ook bij Windows, maar niet 1-op-1 te vergelijken) is het gebruikelijk om altijd een aparte user aan te maken en via daar `sudo` aan te roepen. Bijvoorbeeld: mocht je een installatiescript (Bash-script) willen uitvoeren, dan kan het zijn dat daar hogere privileges voor nodig zijn. Dan dien je dat script dus uit te voeren door middel van het gebruik van `sudo`, omdat `sudo` wel de rechten heeft om bepaalde dingen te installeren, jij als gebruiker niet. `su` is voor het veranderen van user (`sudo su -` is dat voor het switchen naar de user root). Misschien kan je het ook een beetje vergelijken met role-based authorisation.
sudo is in feite een soort pipe naar een nieuwe Shell met access controls wie hem mag aanroepen. Verder doet hij geen privilege escalation omdat dit al in Linux ingebakken zit.

Run maar een keer: ls -l /usr/bin/sudo

Dan krijg je de volgende output:

-rwsr-xr-x 1 root root

Die s in dat lijstje permissions is een indicatie dat dit programma niet opgestart wordt namens de persoon die het programma aanriep maar namens de owner. Dat het de SetUID flag.
Nog 2 toevoegingen die ik in andere reacties niet duidelijk naar voren zie komen:

Zowel su als sudo worden vaak gezien als tools om root-rechten te krijgen. Strikt genomen is dat niet juist, in beide gevallen gaat het om veranderen naar een andere gebruiker. Daarbij is die andere gebruiker default de enige/eerste aanwezige: root. En ja, het gaat allemaal via root omdat die alles kan en mag.

Daarnaast is voor de gebruikers en beheerders relevant dat su vraagt om het wachtwoord van root (of het doel account) en dat sudo vraagt om het wachtwoord van het account waar je vandaan komt.

Daarbij heeft sudo iets meer configuratie nodig dan su: bij sudo moet je het wel mogen. Als dat niet is geconfigureerd dan mag en kan je het dus niet. Bij su moet je het (root) wachtwoord weten. Dat moet er dan ook wel zijn, wat lang niet altijd het geval is.
"xxx is not in the sudoers file. This incident will be reported" :+
Nog een toevoeging aan su en sudo wat er origineel niet echt uitgebreid in zat: Logging!. Nader bepaald: aansluiten bij specifieke logging voor security, beheer en debuggen en elk met eigen tools en aansluitingen. Vooral omdat bepaalde gegevens juist niet in de log van de ander terecht mogen komen.
Het aanroepen van de user-authenticatie gevolgd het vaststellen van de permissies.
Deze XKCD comic legt het precies uit: https://xkcd.com/149/
Technisch gezien:

Het sudo-commando moet een setuid-bitje hebben op de binary. Dit zorgt ervoor dat iedereen die het commando uitvoert het als de eigenaar van de binary opstart.

Effectief start je sudo dus altijd op als root gebruiker. (( als je het dus met -u andere_gebruiker gebruikt laat het commando z’n rechten terugvallen naar die gebruiker voordat het wordt uitgevoerd, op dezelfde manier hoe bijvoorbeeld de Apache-gebruiker dat doet om wel te kunnen luisteren op een lage poort (wat alleen root mag) en direct daarna de webserver daar aan koppelt.

Een belangrijk aspect van dit mechanisme is dat de stdout en stderr nog wel van de initiërende gebruiker zijn.

Dus $ sudo cat /etc/shadow > ./schaduw geeft de eigenaar van ./schaduw van de gebruiker die het aftrapt.
In de laatste Linux Kernels zit ondersteuning voor Rust ; zou deze ontwikkeling er dan voor zorgen dat het omdat het zo dicht op de "kernel" zit het "extra" veilig moet gaan zijn in de toekomst ?
Het idee is dat Rust een veiligere taal is, maar wel low level genoeg is om systeem applicaties in te schrijven.

Met name memory management is heel anders geregeld dan in C waardoor het moeilijker is om fouten in geheugen allocatie/deallocatie te maken.

https://blog.logrocket.co...-the-rust-borrow-checker/
Waarom dan niet C++? Ik ken Rust niet maar de grote problemen van C (i.e. dangling pointers; buffer overrun) zijn opgelost als je modern C++ gebruikt (e.g. smart pointers en std::vector).
Het probleem is dat hoewel C++ je aantal middelen geeft om het beter te doen, je je nog steeds enorm kan branden. Zo is alles voor de veiligheid slechts opt-in in plaats van opt-out zoals het zou moeten zijn. En zelfs wanneer je het goed probeert te doen en het moderne spul van C++ gebruikt, kan het nog steeds mis gaan.

Bijvoorbeeld, een nieuwe(re) API zoals std::array heeft zijn lengte geëncode in zijn type. Als je er dan in indext, zal die dan een bounds check doen? Antwoord is blijkbaar nee: https://godbolt.org/z/arEnq1nqc

En natuurlijk zou het in deze code beter zijn om de iterators te gebruiken, maar voor die keren dat je alsnog de index gebruikt kun je het nog steeds super verkeerd doen.

Vergelijk maar eens met de output van deze equivalente Rust code: https://godbolt.org/z/Wa7z1fe8f
In plaats van gewoon maar in random geheugen te lezen raakt de code in een panic.
Elke taal kan je misbruiken. Als je runtime bounds checking wil in C++ gebruik je 'at'. Nog beter is natuurlijk om niet hardcoded 5 te gebruiken maar uiteraard size(); iterators of range based for loops. Nog steeds kan je het dan in C++ kapot maken (e.g. modificatie gedurende iteratie) maar ik vraag me af of Rust ook hiertegen beschermd is want de runtime kosten kunnen hoog zijn dan.
Dit is natuurlijk alleen een voorbeeld. Maar het gebruik van bijv 'at' is weer opt-in. Je moet er maar net van weten. Maar ook in de situaties waarbij jij als programmeur denkt alles correct te hebben kun je fout zitten of een toekomstige refactor kan een impliciete assumption verbreken.

In Rust 'borrow't een iterator zijn container. Je kan je container dus niet gebruiken zolang je iterator in leven is. Dit is ook bepaald op compile time en je betaalt er geen runtime kosten voor.

Wat betreft de automatische bounds checks, de performance impact ervan is best klein. Cpu's zijn best snel in het vergelijken van twee integers en de branch predictor gaat er waarschijnlijk ook wel van uit dat de check slaagt. Alleen in hot loops kan het belangrijk zijn om die checks er uit te halen.

En dat kan op twee manieren. Je kan bijvoorbeeld de compiler overtuigen dat je array een bepaalde lengte heeft door een assert of early return te doen. Als de compiler overtuigd is, dan zal de check weg geoptimaliseerd worden. Het gebruik van een iterator is ook iets wat de compiler overtuigt, dus via de iterator krijg je ook geen bounds checks.

De tweede manier is de opt-out gebruiken. In unsafe kun je 'get_unchecked' gebruiken.
Elke taal kan je misbruiken.
Als beginner wil je niet in dezelfde valkuilen stappen omdat je de weg niet kent. Dat de veiligheid standaard aan staat, en juist niet uit, is heel fijn. Wil je zaken misbruiken, dan heb je nog steeds de vrijheid om je hele programma unsafe { ... } te maken.
De twee vergelijken toont dan weer een 'probleem' van Rust aan: er wordt onderliggend ongeveer twee keer zoveel uitgevoerd in Rust dan in de C++ implementatie.

Dat is meestal geen probleem. Maar C en C++ proberen programmeertalen te zijn die geen extra kostprijs introduceren.
The zero-overhead principle is a C++ design principle that states:

You don't pay for what you don't use.
What you do use is just as efficient as what you could reasonably write by hand.

In general, this means that no feature should be added to C++ that would impose any overhead, whether in time or space, greater than a programmer would introduce without using the feature.

The only two features in the language that do not follow the zero-overhead principle are runtime type identification and exceptions, and are why most compilers include a switch to turn them off.
Bij Rust kan je daar niet voor kiezen. Bij C++ kan je ervoor kiezen om een array implementatie te gebruiken die wel bounds checks doet (of je kan het gewoon telkens zelf doen).
Dat kan in Rust zeker wel, alleen moet je dat dan in een unsafe blok doen.

Daarbij, de Rust implementatie doet niet twee keer zo veel. Een extra integer compare is niks vergeleken met het formatten en printen van de values.
Daarbij is het ook zo dat de compiler de check er uit kan optimaliseren als het kan bewijzen dat de check niet nodig is.

Wat betreft dat zero-overhead principe, Rust houdt zich daar ook aan maar heeft er een andere mening over.
1. You don't pay for what you don't use.
2. What you do use is just as efficient as what you could reasonably write by hand.
De bounds check is een integraal onderdeel van Rust's safety. In normaal Rust is het niet toegestaan om UB te hebben. Dus het doen van een bounds check is onderdeel van het minimale wat je moet doen om veilig een array te indexen. Vanuit dat oogpunt blijft het principe staan. Access je geen array? Dan heb je geen bounds check. Doe je dat wel, dan zal de check er wel zijn (maar dat had je anders handmatig ook moeten doen). De compiler zal de check wegoptimaliseren wanneer dat kan dus het is ook net zo goed als wat je anders handmatig zou schrijven. Punt 1 en punt 2 staan.
Het probleem van C++ is dat het opgelost is als je het goed doet, en het is niet duidelijk te zien wanneer je het niet goed doet.

Rust is meer "opiniated" en heeft in de compiler ingebouwd dat je pointers niet kan delen als dat niet zou mogen. De "borrow-checker" die Rust heeft is een mooi stuk software die het eigenaarschap en lees en schrijfrechten van pointers bijhoudt.

C++ kan het allemaal goed doen maar dan moet je alsnog opletten.

(Dan heb je in Rust ook nog unsafe, dus je kan er omheen maar is wel stuk duidelijker afgebakend)

[Reactie gewijzigd door Dr. Horrible op 22 juli 2024 16:38]

Inderdaad. C++ is meer zoals een trein op een onbeveiligd spoor laten rijden. Dat kan heel lang goed gaan als de machinisten blijven opletten, maar als het niet goed gaat, dan zit je in de problemen. Op een beveiligd spoor (Rust) is de kans op ongelukken niet nul, maar wel minder.
Zig en Rust zijn gewoon leuk :)
C++ heeft zeker scherpe randen (e.g. templates; function overloading; exceptions) maar normaal gesproken heb je daar weinig last van. Ook Carmack is nu van standpunt dat C++ een betere taal is om grote games / applicatie in te schrijven dan C.
Maar toch zijn er ook grote namen voorstander van C, bijvoorbeeld Ikey Doherty.
Nee, dat is toeval. Sudo is een userspace applicatie die gebruik maakt van het authorisatie-/privilegemodel van Linux. Je kunt zo'n applicatie in allerlei talen schrijven, in dit geval Rust. Maar zie bv ook opendoas als voorbeeld van een alternatief.

De mogelijkheid om kernelmodules te laden die in Rust geschreven zijn is een ontwikkeling die hier compleet los van staat maar wel dezelfde redenen heeft, namelijk bepaalde eigenschappen van Rust.

[Reactie gewijzigd door gsmolders op 22 juli 2024 16:38]

Wat betekent het precies dat kernel support heeft voor rust? Worden kernel modules niet uiteindelijk toch gecompileerd naar binair net als bij C?
Ja dat begrijp ik ook niet dus als iemand het uit will leggen, graag
De Linux kernel is geschreven in C. Vraag je dus iets aan de kernel via een C API dan retourneert deze datastructuren (enums, arrays, structs etc) in C formaat. Als je een functie wilt aanroepen die niet geschreven is in Rust hoe stuur je dan de argumenten/parameters mee? Hoe weet Rust überhaupt hoe een C string eruit ziet?

Wil je dus met Rust iets uitvragen dan moet deze wel snappen wat voor data geretourneerd wordt en hoe dat te interpreteren. Dat is wat deze "bindings" doen, ze maken het mogelijk om via Rust met de datastructuren/syscalls/APIs van de Linux kernel te werken en dat "primitieve" datastructuren een op een mappen. Een C Enum is een Rust Enum etc.

https://rust-for-linux.github.io/docs/kernel/

Dit is wel een beetje kort door de bocht, maar is wel waar het op neerkomt.
Betekend ook dat er "bindings" zijn voor Rust. IE: datastructuren kun je uitwisselen tussen Rust en C.
Het eindresultaat is binair, maar Rust code verplicht je om het delen van geheugen/variabelen beter te omschrijven waardoor de compiler automatisch kan bepalen of je code geen bugs heeft. Waar je in C een werkende binary met runtime problemen krijgt krijg je bij Rust een compiler fout.

Linux support betekent inderdaad dat er een Rust API voor drivers is en het kernel build proces met Rust code overweg kan.

[Reactie gewijzigd door bzzzt op 22 juli 2024 16:38]

Omdat rust voor zover ik zie/begrijp wordt gecompileerd tot objecten (binaries zoals libraries en executables en dergelijke) hoeft de kernel voor dergelijke applicaties geen aparte ondersteuning te hebben voor de source, de executables moeten aan het linux object model voldoen. De ondersteuning voor rust in de linux kernel (source) is er om vanuit de kernel ook rust-code te kunnen gebruiken, bijvoorbeeld als gelinkte objecten, kernel modules of hoe je dat ook noemt.

In meer detail: Linux als distributie is in de regel gnu-linux waarbij linux de kernel is en gnu de basis set aan applicaties. De commando's/programma's su en sudo zitten in het gnu-deel. Dat zijn in de regel allemaal (kleine) losse programma's en die kunnen ieder voor zich worden vervangen. Dat gebeurt hier met su en sudo.
In de laatste Linux Kernels zit ondersteuning voor Rust ; zou deze ontwikkeling er dan voor zorgen dat het omdat het zo dicht op de "kernel" zit het "extra" veilig moet gaan zijn in de toekomst?
Sterker nog, dat zijn dezelfde gasten: Prossimo. Zie ook deze blogpost op memorysafery.org: https://www.memorysafety....linux-just-the-beginning/
De herschrijving van sudo in Rust kan interessant zijn voor ontwikkelaars en AWS, maar het roept vragen op over de lange termijn onderhoudbaarheid als er zoveel verschillende programmeertalen betrokken zijn rondom systemen. Veel ontwikkelaars zijn waarschijnlijk niet enthousiast om oudere, minder gebruikte programma's om te zetten naar Rust.

Ik ben benieuwd naar welke onbekende kwetsbaarheden zullen verdwijnen na de implementatie van de nieuwe sudo/su in Rust. Het is de vraag of ze een manier kunnen vinden om dit bij te houden en te beoordelen.
Veel ontwikkelaars zijn erg gehecht aan hun favoriete programmeertaal wat op zich niet vreemd is als je er al jaren mee werkt en er heel productief mee bent geworden.
Helaas krijgen mensen dan wel de neiging de zwakheden enigszins goed te praten.

Het is een beetje als autogordels verplichten: mensen vinden het eerst omslachtig, willen niet en vinden het de schuld van de chauffeur als die botst, maar uiteindelijk is er geen verkeersmaatregel geweest die meer slachtoffers heeft voorkomen.
Een halve eeuw 'use after free' en 'bounds checking' lekken zou toch moeten leiden tot een meer structurele oplossing dan iedere keer de programmeur de schuld geven en snel te patchen.

Ik denk dat het ondoenlijk is per kwetsbaarheid te bepalen of Rust helpt en heb niet de illusie dat Rust 100% veilig is. De vraag is ook wie dat zou moeten beoordelen en met welk doel.
Ik denk dat het ondoenlijk is per kwetsbaarheid te bepalen of Rust helpt
Dat is wel wat Microsoft al heeft geprobeerd:
As we’ve seen, roughly 70% of the security issues that the MSRC assigns a CVE to are memory safety issues. This means that if that software had been written in Rust, 70% of these security issues would most likely have been eliminated
Google heeft iets vergelijkbaars gedaan, maar is minder expliciet dus ga ik creatief editten:
For more than a decade, memory safety vulnerabilities have consistently represented more than 65% of vulnerabilities across products, and across the industry.
(...)
To date, there have been zero memory safety vulnerabilities discovered in Android’s Rust code.

[Reactie gewijzigd door 84hannes op 22 juli 2024 16:38]

'most likely' klinkt nou niet echt als betrouwbare data.

Als je in Rust bouwt ben je waarschijnlijk met code bezig die aan hoge veiligheidseisen moet voldoen. Ook als je voorheen C gebruikte zal die code zwaarder zijn gereviewed op kwetsbaarheden en is het minder waarschijnlijk dat er allerlei beginnersfouten in zitten. Een vergelijking tussen Rust en C zal dan minder voordeel tonen dan gemiddeld. Dan is die 70% waarschijnlijk de bottom line.
'most likely' klinkt nou niet echt als betrouwbare data.
Most likely omdat er altijd een edge case te bedenken is waarbij de code bijvoorbeeld unsafe is, maar zo complex wordt gemaakt dat een geheugenfout alsnog door de review heen sneakt. Of omdat er een fout in de borrow checker van Rust zit die misbruikt wordt. Je kunt nooit 100% zekerheid geven, ook niet mer Rust.
Als je in Rust bouwt ben je waarschijnlijk met code bezig die aan hoge veiligheidseisen moet voldoen.
Voor hoge veiligheidseisen kun je soms ook terugvallen op Java/Kotlin/C# of andere varianten die volledig geautomatiseerd geheugenbeheer hebben. Ik denk eerder aan performance. Browsers, drivers, runtimes etc. Die hebben inderdaad flinke overlap met veiligheidskritische toepassingen, maar dat lijkt me niet de reden om voor C te gaan.
VM talen met een garbage collector hebben dan wel een enorme bak meer overhead en draaien vaak moeizamer op low-end hardware. Juist al die IoT apparaten zouden heel veilig moeten zijn maar daar past geen volledige Java/.NET stack op.
Dat is precies wat ik bedoel, C/C++ kies je primair voor prestaties, slechts secundair voor veiligheid als je heel goed weet wat je doet.
Ik weet niet of die prestaties zo belangrijk zijn voor de meeste C/C++ apps. Aangezien dat de standaard ontwikkeltalen van Unix en later Windows waren lijkt het er ook op dat veel mensen dat aangeleerd hebben omdat dat de eerste keus was om applicaties te schijven. Performance en/of veiligheid is dan helemaal geen factor. Een taal die naadloos aansluit bij je ecosysteem is dat wel.

Als het echt snel moet is de taal al lang niet relevant meer: AI/ML mensen gebruiken allemaal Python als bootloader voor GPU code ;)
Met prestaties bedoel ik ook niet zoveel mogelijk bewerkingen per seconde. Als je naar mijn en jouw voorbeelden kijkt zie je dat minimale latency/jitter en minimaal geheugengebruik minstens zo belangrijk is. Dan is C# niet je vriend, en Python ook niet de eerste keus, ook niet in combinatie met een GPU.
100% veilig lijkt me inderdaad een illusie, maar zoals je al zegt: het is zoiets als met die autogordels. Ook mét gordel kun je nog best in het ziekenhuis belanden of erger, maar mét gordel is wél beter. Dus liever Rust dan minder veiligheid.

[Reactie gewijzigd door TheVivaldi op 22 juli 2024 16:38]

Beveiligingsbugs komen natuurlijk achteraf aan het licht, en zijn vaak subtiele gaten in het geheugenbeheer.

Door een bufferoverflow te triggeren met een combinatie van inputs kun je vervolgens ongwenste code uitvoeren.

Rust kan tijdens compileren deze fouten detecteren, een C compiler niet (altijd).

Maar om te zeggen dat Rust alle bugs kan detecteren; nee, zelfs een index overflow kan run-time nog fout gaan.
Het gaat ook niet alleen om detecteren maar om code veiliger te maken als onderdeel van het ontwerp van de taal door onveilige constructies simpelweg niet toe te staan.
Ik denk dat we hetzelfde zeggen. Onveilige constructies (dat zijn security bugs) detecteert de compiler toch in Rust?
Rust voegt ook runtime code toe, specifiek voor het detecteren van out of bounds toegang. (je kan een array index niet controleren zolang je niet weet hoe groot de array is)
Weet ik, maar zoals ik al schreef: zelfs een index overflow kan run-time nog fout gaan.
Als de compiler code toevoegt om dat geval te detecteren kan het toch niet meer misgaan?
Klopt, runt-time stopt het programma dan.

Ik had gehoopt toen ik met Rust begon dat dit ook compile time kon worden afgevangen. Maar ik realiseer me dat dat teveel beperkingen zou opleggen.
Ik begrijp niet dat ze iets volledig gaan herschrijven wat al 40 jaar zonder problemen werkt.

Zitten er geheugen issues in sudo? Volgens mij niet.
Zitten er ernstige bugs in sudo? Volgens mij niet.


Rust zal vast en zeker een goede programmeertaal zijn, maar volgens mij kunnen de programmeurs zich beter focussen op het vervangen van code die wel kapot is, en niet op zaken die prima werken.
Zitten er ernstige bugs in sudo? Volgens mij niet.
https://www.zdnet.com/art...s-gain-root-level-access/
Maar het schrijven van nieuwe software hoeft toch niet te betekenen dat de bugs verdwenen zijn of er nieuwe voor in de plaats komen?

En gevonden bugs worden dus gepatched.
Het schrijven van nieuwe code waarin een hele klasse van veelvoorkomende problemen domweg niet meer mogelijk is kan wel degelijk meerwaarde hebben.

(ik ben niet specifiek pro-Rust, maar het heeft in in ieder geval potentie om de frequentie van bugs te verminderen)
Er zal in de oude C code veel functies zitten voor legacy. Als je toch voor braking changes gaat, maakt de taal niet meer uit.

Nu heeft Tweede golf samen met Ferrous Systems gekozen voor Rust. Het had ook opnieuw geschreven kunnen worden in C of C++ of elke andere taal die direct naar binair kan compilen.

Ik ken de specifieke code SU/SUDO niet heel goed maar kan goed geloven dat door de jaren heen een draak van een applicatie is geworden om te patchen. Dat soms bij 0 beginnen sneller en veiliger is. Omdat in 40 jaar er genoeg API calls van Linux/Unix zijn veranderd.

Dan hebben wij het nog niet over de RUST compiler tegenover meeste C compilers, RUST heeft meer checks op bepaalde fouten die je als ontwikkelaar kan maken dan C. Wat zorgt voor minder runtime errors bij edge cases. En er zijn genoeg edge cases bij Linux aangezien het extreem veel gebruikt word. Zeker in serverland.
Verwijderd @Tjidde1 mei 2023 12:19
De 'API calls' van Linux/Unix noemt POSIX en de relevante zijn setuid, setguid, fork en execv maar misschien ook getpwnam.

Volgens mij zijn geen van die POSIX calls gewijzigd de afgelopen ~ 40 jaar en zijn ze vrijwel identiek voor zo goed als alle POSIX systemen.

Het is ook maar de vraag of Rust het 40 jaar zal volhouden als programmeertaal die nog veel gebruikt zal worden in de jaren van de toekomst. Dat staat voor C wel ongeveer vast. Vooral omdat gigantisch veel UNIX software in C geschreven is en het weinig denkbaar is dat dat allemaal in een andere programmeertaal zal herschreven worden (tot op het punt dat de oude implementaties volledig vergeten zullen zijn).

Een andere programmeertaal die steeds minder gebruikt wordt en die ooit veel populairder was dan Rust nu is, is Perl. Dus misschien is Rust nu wel aan populariteit aan het winnen. Bedenk dan wat er met Perl aan het gebeuren is.

Fortran en COBOL zijn dan weer voorbeelden waar C naar kan kijken. Ik vermoed dat C over 40 jaar zo'n beetje zoals Fortran nu is, zal zijn. Nog steeds gebruikt. Maar niet erg veel meer.

We zullen zien. Tot over 40 jaar wanneer ik 82 ben en in mijn rolstoel zal zitten mekkeren dat in mijnen tijd alles beter was.
Maar het schrijven van nieuwe software hoeft toch niet te betekenen dat de bugs verdwenen zijn of er nieuwe voor in de plaats komen?

En gevonden bugs worden dus gepatched.
Complete waanzin idd, vnl tech fetish. Als manager zou ik dit nooit toe staan...
Daarom moet je ook niet een compleet stuk software in een keer opnieuw schrijven, maar dat eerst stapsgewijs doen waarbij de meest kritieke delen als eerste aan de beurt zijn.
Als je van programmeertaal verandert, heb je meestal niet zoveel keus dan het helemaal herschrijven.

Overigens is sudo natuurlijk ook niet het grootste project qua code. Ik denk dat de meeste kwetsbaarheden nog zitten in het hele PAM verhaal en dat is een stuk lastiger aan te pakken.

[Reactie gewijzigd door GekkePrutser op 22 juli 2024 16:38]

Firefox wordt/werd stapsgewijs herschreven van C/C++ naar Rust nadat het eerste plan om in één keer over te stappen op Servo te ambitieus bleek.
Daar kan dat, omdat het niet uit een enkele binairy bestaat, maar o.a. meerdere dll's met elk hun eigen doel. Het is daardoor makkelijker om een andere DLL in te laden, waarvan de code is vervangen door een andere programmeertaal.
DLL's? Dus Firefox werkt ineens niet meer op een ander OS dan Windows? Denk dat je niet helemaal snapt wat een dll is.
Dynamic linked library.
Net zoals snappen wat een voorbeeld is en dat je het niet voor elk os implementatie apart gaat benoemen. :Y)
Overigens is sudo natuurlijk ook niet het grootste project qua code. Ik denk dat de meeste kwetsbaarheden nog zitten in het hele PAM verhaal en dat is een stuk lastiger aan te pakken.
PAM is een grote spaghetti code, die de beheerder ook zelf eenvoudig verkeerd in kan stellen. BSD_Auth is veel simpeler, en ook nog eens veel minder LOC.
Ik weet het, vandaar inderdaad :)

BSD heeft ook PAM trouwens, alleen die schijnt iets beter van kwaliteit te zijn dan Linux PAM. Maar dat geldt niet per se voor de plugin modules natuurlijk.

[Reactie gewijzigd door GekkePrutser op 22 juli 2024 16:38]

OpenPAM; openpam.org lijkt erop dat alle BSDs (inclusief macOS, behalve OpenBSD) het gebruiken. https://en.wikipedia.org/wiki/OpenPAM

Het gevaar om verkeerd te configureren lijkt me hetzelfde.

Mocht iemand nog interesse hebben in een op papier veiliger sudo alternatief, kijk eens naar (open)doas. Kan wel veel minder dan sudo maar wel de basis (KISS), en veel minder LOC. Geschreven in C.

(Al is LOC net zoiets als CVEs vergelijken, nattevingerwerk.)
Er wordt een vraag gesteld die wordt beantwoord met een recent voorbeeld van een ernstige bug in sudo. Je kan dit zien als dat de laatste bug in sudo nu is opgelost of als bewijs dat er nieuwe bugs gevonden zullen worden. In dat tweede geval is er antwoord gegeven op de vraag.

Er wordt niets gezegd in de reactie over of het verstandig is om dan de software in een nieuwe taal te schrijven.
Dat was ook mijn gedachte. Een code review is wellicht net zo handig.

Van de andere kant, is het af en toe opnieuw beginnen aan een project helemaal zo gek niet
- geen legacy code die je “achteraf” anders had gedaan
- gebruik maken van nieuwere technieken (/ rust) die eenvoudiger of veilig zijn

Stel: in c zit een veiligheidsprobleem waar je als programmeur continu rekening mee moet houden met drie extra controles bij elke keer dat je een functie gebruik. Dan kun je de code controleren op die functie en aanpassen. Als die elke jaar gebeurt, dan (i) heb je steeds tijdig onveilige code, en (ii) terugkerend werk. Als in Rust dat soort problemen (veel) minder zitten als je code veiliger en en kost het onderhoud minder werk
Als het onderhoud per jaar 7 dagen kost maar een rewrite kost bijv 1 man jaar dan wordt de rewrite pas na 52 jaar rendabel.

Daarnaast wordt het volgende antwoord veel gebruikt, in zulke situaties
Als die elke ... gebeurt, dan (i) heb je steeds tijdig onveilige code, en (ii) terugkerend werk. Als in ... dat soort problemen (veel) minder zitten als je code veiliger en en kost het onderhoud minder werk
Maar een rewrite betekent dat je twee producten hebt, elk met hun eigen tech debt. Tenslotte het oude product verdwijnt niet van de 1 op de andere dag.
Vergeet niet dat het aan de development kant misschien pas na 52 jaar rendabel wordt, maar dat elke keer als er een CVE gevonden wordt, dan er ook duizenden engineers bezig zijn met patchen van deze systemen. En dat de impact heel veel groter kan zijn door die ene binary te herschrijven naar de standaarden van vandaag. Los van de schade door misbruik als zo een CVE misbruikt wordt, ben benieuwd hoeveel man uren dat zou schelen op een jaar over de wereld.
Dat ook. En bovendien: wat is “rendabel”? Toevallig wordt er nu door betaalde ontwikkelaars aan gewerkt, maar niet bij elke software is dat het geval.
Ik snap het ook niet helemaal. Voor een nieuwe applicatie snap ik dat Rust veiliger dan C kan zijn. Maar ik zie niet waarom een nieuwe tool in Rust veiliger zou zijn dan een tool in C die al jaren volwassen is en langzamerhand wel grondig gedebugged.
Er zijn de afgelopen decenia echt al wel vaker code reviews e.d. gedaan en toch komen er telkens weer issues naar boven die soms al vanaf het begin erin zitten (en dus ook mogelijk actief misbruikt zijn). Dat bewijst, mijns inziens, dat de code dusdanig slecht leesbaar is, dat een hele opensource community en grote groepen beveiligingsexperts dit soort issues niet kunnen vinden.

Door de code opnieuw te schrijven, met al die info in het achterhoofd, in een taal waarin een groot deel van de issues überhaupt niet kan voorkomen, is daardoor (naar mijn mening) van zeer grote meerwaarde.
Dat iets al 40 jaar zonder problemen werkt betekent toch niet dat je nooit kritisch naar je code kijkt en met het oog op de toekomst veranderingen gaat doorvoeren? De switch naar Rust zal waarschijnlijk een betere basis leggen voor de komende 40 jaar.
Dan ga je er vanuit dat veranderingen altijd verbeteringen zijn, maar dat zal de komende 40 jaar moeten uitwijzen.
Er zit wel zeker ontwikkeling in deze tools: Ze moeten ook aansluiten op zaken zoals mfa en zo. Origineel was su zeker niet modulair maar tegenwoordig is het wel zo handig dat ze aansluit op pam-modules bijvoorbeeld.

Daarna kan iedereen zijn/haar best doen met het maken van pam-modules om de volgende mfa toegang toe te voegen.

En ja, de beheerder zal ook het nodige willen kunnen configureren in sudo-bestanden om een bepaalde mate van mfa af te dwingen.
Rust heeft één groot manco: het is geen C en zal C dus nooit echt kunnen vervangen. Dit staat wat mij betreft los van de discussie of de ene programmeertaal nu veiliger is dan de andere.

Een aantal features van Rust die Rust volgens de developers zo robuust maken kunnen voor de toepassingen die vaak in C geschreven worden juist een blocker zijn. Denk aan strong typing. De kracht van een void pointer bijvoorbeeld zit hem nu juist in het feit dat C weakly typed is. Dus om een structure van een willekeurig type toe te voegen aan een lijst wordt de pointer eerst naar 'void *' gecast om vervolgens in een lijst van void pointers toegevoegd te worden. Op het moment dat er iets met die structure gedaan moet worden haalt het programma hem weer uit de lijst, controleert het type ervan en cast die void pointer dan weer terug naar het juiste type. Daar is niets inherent 'unsafe' aan, maar probeer dit eens met Rust te doen zonder een unsafe clause. De laatste keer dat ik iets met Rust deed ging dat niet.

Een ander ding waar je voor moet waken is de hype dat de programmeertaal Rust inherent safer is dan C. Dat is een drogreden. De onveiligheid zit hem niet in de programmeertaal zelf, maar in het slechte programmeerwerk dat ermee gedaan wordt. Helaas is dat vaak het paradepaardje waar mensen die enthousiast zijn over Rust, waar ik geen moeite mee heb, ieder zijn ding, meekomen wanneer ze jou ervan te proberen te overtuigen om ook naar Rust over te stappen en dat is iets waar ik wel moeite mee heb. Geen probleem dat je me probeert te overtuigen, maar kom dan wel met argumenten die daadwerkelijk kloppen. Je kunt een programmeertaal niet slecht noemen omdat mensen, ongeacht hun talenten, er slechte programmatuur mee kunnen schrijven. Dan voldoet geen enkele programmeertaal meer.
Het gaat er niet om dat je met een taal wel of geen slechte programmatuur kan schrijven. Het gaat er om dat het makkelijker is om correcte programmatuur te schrijven en dat slechte code zo vroeg mogelijk in een ontwikkelproces wordt 'afgekeurd'.
De onveiligheid zit hem niet in de programmeertaal zelf, maar in het slechte programmeerwerk dat ermee gedaan wordt.
Ik vind dit argument niet zo sterk. Stel je voor dat je een kruispunt voor de deur hebt waar elke week een ernstig ongeluk gebeurt. Accepteer jij het dan als de gemeente zegt dat dat niet door het kruispunt komt, maar door de slechte chauffeurs die daar rijden?

Of, in de woorden van @bzzzt :
Een halve eeuw 'use after free' en 'bounds checking' lekken zou toch moeten leiden tot een meer structurele oplossing dan iedere keer de programmeur de schuld geven en snel te patchen.
Als de programmeur zijn werk niet goed gedaan heeft (en een vergissing is inderdaad makkelijk gemaakt), dan is dat nog steeds geen argument om dat op de kwaliteit van de programmeertaal te gooien.

De structurele oplossing lijkt me dan toch eerder dat de programmeur beter opgeleid wordt om ervoor te zorgen dat hij zijn werk beter kan doen. Overstappen naar een andere programmeertaal gaat daarbij echt niet helpen, hooguit wanneer de drempel voor het overstappen redelijk hoog is en het ook een andere manier van denken vereist (wat toegegeven, bij Rust ook enigszins het geval is).

Dat is hetzelfde soort beargumentatie als ervoor pleiten dat array indices in C eigenlijk een unsigned integer zouden moeten zijn omdat geen enkele zichzelf respecterende ontwikkelaar negatieve indices in een array zou gebruiken als 0 het begin van je array aanduidt. Nog even los van het feit dat er genoeg redenen zijn om waar nodig juist wel negatieve indices in een array te gebruiken, klopt het ook nog eens niet: array index 0 is technisch gesproken het midden van je array, niet het begin. We hanteren de conventie dat het het begin van de array is, maar de C compiler "denkt" daar anders over. Die vertaalt het uiteindelijk gewoon naar rekenkundige bewerkingen op een pointer.
We hanteren de conventie dat het het begin van de array is, maar de C compiler "denkt" daar anders over
De C compiler denkt daar net zo over, in die zin dat de waarde die aan malloc teruggeeft het begin, niet het midden, van het gealloceerde geheugen geeft. Maar je hebt gelijk, je zou dat kunnen herdefiniëren en dan kun je negatieve indexen gebruiken, de compiler zal je niet actief tegen werken.
De structurele oplossing lijkt me dan toch eerder dat de programmeur beter opgeleid wordt om ervoor te zorgen dat hij zijn werk beter kan doen.
We hebben het hier over een specifiek kruispunt waar bovenevenredig veel ongelukken gebeuren, en jouw voorstel is om alle chauffeurs die daar wel eens komen betere rijlessen te geven? Ik kom dit soort adviezen in de praktijk regelmatig tegen, maar ik zal ze nooit snappen.

Maar uiteindelijk komt het steeds terug op hetzelfde argument. Een perfecte ontwikkelaar zal in C perfecte code schrijven. Geen speld tussen te krijgen.

[Reactie gewijzigd door 84hannes op 22 juli 2024 16:38]

C is wel degelijk strongly typed, inclusief de void pointer. Stop er maar eens een integer in.
Ik snap niet waarom er niet voor Go is gekozen. su en sudo zijn userspace applicaties die geen low-level hardware-calls of eigen memory management nodig hebben.

Er wordt gedaan of Rust beter is dan C of C++, maar door de mogelijkheid van eigen memory management en de unsafe keyword, kan er net zo onveilige viezigheden als C en C++ gedaan worden.
Er wordt gedaan of Rust beter is dan C of C++, maar door de mogelijkheid van eigen memory management en de unsafe keyword, kan er net zo onveilige viezigheden als C en C++ gedaan worden.
Als je eerste gedachte is dat je alles wat Rust biedt opzij moet gaan zetten om unsafe te gaan werken heb je totaal niet begrepen wat de bedoeling is.

Het heeft geen zin een taal 100% dicht te spijkeren als dat ten koste van de toepassing gaat. Voordeel van 'unsafe' is dat het gelijk opvalt dat het om code gaat die extra gecontroleerd moet worden.
r wordt gedaan of Rust beter is dan C of C++, maar door de mogelijkheid van eigen memory management en de unsafe keyword, kan er net zo onveilige viezigheden als C en C++ gedaan worden.
In elke taal, ook Go, kun je onveilige dingen doen. Het punt is dat onveilig de default mode is bij C/C++, en een uitzondering bij de meeste talen.
De eerste stappen na de voorbereidende fase zijn om authenticatie via Pluggable authentication modules toe te voegen, een sudogebruikersbeleid te maken en om een eerste test op Ubuntu 22.04 te draaien.
Ik neem aan dat dit "Linux PAM" moet zijn ipv "PAM"? Ik vraag mij overigens ook af waarom dit onder Ubuntu getest moet worden ipv een meer relevant voor AWS distro zoals CoreOS? Op die manier kan men ook kiezen voor een versie bij init installatie, of misschien begrijp ik het doel niet van deze exercitie en is het een voorzet voor een Linux geschreven in Rust ipv C/C++?
Je hebt ook Doas, OpenBSD’s alternatief voor Sudo die je ook op Linux kunt gebruiken. De configuratie daarvan is een stuk simpeler, de meeste mensen hebben niet meer nodig.
Ja, dat klopt. doas is een alternatief voor sudo dat oorspronkelijk is ontwikkeld voor OpenBSD, maar het kan ook op Linux worden gebruikt. Het belangrijkste doel van doas is om een eenvoudiger en lichtgewicht alternatief te bieden voor sudo met een eenvoudigere configuratie.

De configuratie van doas is inderdaad eenvoudiger dan die van sudo. In plaats van het /etc/sudoers-bestand, gebruikt doas een apart configuratiebestand, meestal /etc/doas.conf. Dit bestand heeft een eenvoudiger en beknopter formaat, waardoor het gemakkelijker is om te begrijpen en te beheren.

Voor veel gebruikers zijn de mogelijkheden van doas voldoende om hun behoeften te dekken. Het biedt de kernfunctionaliteit om commando's uit te voeren als een andere gebruiker (meestal root) met verhoogde privileges. Als je op zoek bent naar een eenvoudiger en lichter alternatief voor sudo, kan doas inderdaad een goede keuze zijn.
. Rust is een programmeertaal die zich richt op veiligheid, concurrentie en prestaties. Het helpt veelvoorkomende bugs zoals bufferoverflows en andere geheugengerelateerde fouten te voorkomen, die tot beveiligingsproblemen kunnen leiden.

Het is echter belangrijk op te merken dat het herschrijven van een programma zoals sudo of su in Rust niet automatisch garandeert dat het veiliger is. Een goede coderingspraktijk en grondige codecontrole zijn nog steeds essentieel om beveiligingsproblemen te voorkomen. Desalniettemin kan het herschrijven van dergelijke tools in Rust helpen bij het minimaliseren van potentiële geheugenveiligheidsproblemen, wat een stap voorwaarts zou kunnen zijn op het gebied van beveiliging.
copy paste gpt much?

Op dit item kan niet meer gereageerd worden.