Løsninger på problemer vi ikke burde have (længere)

Sidste uge var ret fantastisk ude i DataMuseum.dk.

Vi har i lang tid arbejdet på at få vores Rational R1000/s400 maskine til at køre og stille og roligt har vi ædt os ind på problemerne.

Vi har hele tiden haft lidt email-kontakt med nogle fra det oprindelige Rational team, herunder en fyr fra Frankrig som lånte os tre bånd som vi kopierede og sendte tilbage for lang tid siden.

Nyheden om at vi nu havde konsolprocessoren til at køre igen fik franskmanden, der i mellemtiden var avanceret til Vicepresident, til at checke hvad det egentlig var han havde gemt nede i kælderen under Université Haute-Alsace.

Han blev mødt af beskeden "Det var godt du kom, for om to uger ryger det hele ud" og det var han ikke helt tilfreds med, men tog efter kort betænkningstid den beslutning, at hvis vi i datamuseum.dk var istand til at fixe et IOC board, var det nok smartere at alle stumperne var hos os, end at han blev ved med at gemme dem til et privat drømmeprojekt der næppe nogensinde blev tid til.

Uden varsel fik vi derfor pludselig en email fra Pierre-Alain Muller om at nu læssede han bilen og kom på besøg i datamuseum.dk for at hjælpe os.

Det blev til de to sjoveste dage jeg har oplevet længe og kulminerede med at vores R1000 bootede op med diskene fra hans R1000:

Illustration: Per Dalgas/Datamuseum.dk

Det er meget, meget svært kort at forklare hvor forskellig denne computers arkitektur er fra moderne computeres og hvor mange af de sikkerhedsproblemer som følger deraf, den er helt og aldeles fri for.

Vi kan starte med at den ikke lider af problemer med null-pointere, buffer-overflows og remote code-excution, fordi den i realiteten ikke har pointere, den er objektorienteret med typebeskyttelse i hardware.

Det er faktisk ikke engang den første computer der løste de problemer, Cambridge CAP, intels Iapx432, GE's 645 (den med Multics) og Linn's "Rekursiv" (Dem med grammofonen) er blot nogle af de mest kendte.

Men ingen af disse har været istand til at erobre en af de store pladser, for "hvis der ikke er en C-Compiler er det ligegyldigt".

Hvis man vil køre C-kode på rational maskinen, er den eneste mulighed at skrive en CPU simulator i Ada og lade den gøre det og det løser ikke rigtig nogen problemer.

Men!

Min gode ven Robert Watson har gået og fusket med "CHERI" projektet ovre i Cambridge og nu er der måske ved at gå hul på bylden.

CHERI handler kort og godt om at udstyre pointere med sikkerhedsseler og airbags.

I stedet for bare at være et tal der peger på et sted i en lineær hukommelsesarray, er pointere i CHERI en "capability", hvilket vil sige at pointeren ud over at pege på et sted i hukommelsen også indeholder hvilket område af hukommelsen den overhovedet pege i og at denne begrænsning håndhæves på hardwareniveau.

Det betyder at man godt kan køre C-kode, bare man aldrig prøver at cast'e et tal til en pointer, hvilket idoelogisk set aldrig bør forekomme til at begynde med, selv ikke i de dybeste kældre under operativsystemet.

Et er imidlertid teori, et andet praksis og derfor har Roberts gruppe portet FreeBSD til deres "CHERI" platform som proof-of-concept.

Det nye er at Robert har fået ₤190M, en rund halvanden milliard kroner, med det mål at producere en ARMv8-A chip med CHERI hardware, "Morello", som skal være klar i 7nm teknologi i 2021.

Tillykke til Robert og tak til Pierre-Alain

phk

Kommentarer (29)
sortSortér kommentarer
  • Ældste først
  • Nyeste først
  • Bedste først
Sune Marcher

bare man aldrig prøver at cast'e et tal til en pointer, hvilket idoelogisk set aldrig bør forekomme til at begynde med, selv ikke i de dybeste kældre under operativsystemet.

Hvordan laver man så det allermest low-level memory management kode i OS'et?

Starter man med en pointer-type der har lov at pege på hele hukommelsesområdet, og har man derefter mulighed for at lave mindre slices deraf, som ikke kan udvides tilbage til et større range?

  • 1
  • 0
Poul-Henning Kamp Blogger

Hvordan laver man så det allermest low-level memory management kode i OS'et?

Helt fundamentalt så har du kun en pointer når maskinen booter og den har lov til at være over hele hukommelsen.

Fra denne kan du så udstykke stadigt mere specialiserede pointere med "mindre capability.", dvs. færre privilegier (R/W/X) eller mindre lovligt område.

Men du kan aldrig forøge en pointers "capability" igen, hvis du skal have adgang til mere hukommelse, må du aflede en ny pointer med disse capabilities fra den oprindelige.

En ekstra bit i hukommelsen, bit 129, markere de lokationer der indeholder valide capabilities. Hvis du overskriver en sådan, slettets bit 129 automatisk.

  • 5
  • 0
Sune Marcher

Fra denne kan du så udstykke stadigt mere specialiserede pointere med "mindre capability.", dvs. færre privilegier (R/W/X) eller mindre lovligt område.


Interessant idé – encoder man så alle væsentlige oplysninger i hver pointer, og afskaffer ting som fx x86-style page tables?

Jeg går ud fra der er specielle registre til pointere, i stedet for at kunne addressere med GPRs?

Tak for svar – lader til jeg skal prøve at finde et 20min timeslot til at se videoen :)

  • 0
  • 0
Sune Marcher

Ahh, så lidt ligesom 286's protected-mode selector:offset pointere men lavet ordentligt?


Det lyder umiddelbart en del anderledes - 286 (og 386+ for den sags skyld) har selectors til descriptor tabeller, hvorimod alt information her er encoded i pointeren.

Og med hardware enforcement, lyder det til at der er specifikke pointer registre, hvorimod x86 har general-purpose registre der kan bruges både til pointere og aritmetik.

  • 0
  • 0
Louise Klint

Det er spændende læsning. (Selvom jeg ikke forstår det tekniske).

Forleden bragte DR et satireindslag om StatsPadden.

Det var i forbindelse med, at Google lister sine produkter ind mange steder i skolevæsenet, og så var spørgsmålet om ikke vi skulle udvikle ”et device” i offentligt regi i stedet.

StatsPadden blev lanceret som ”Ugens Dårligste Idé”, men det er ret morsomt.
Prøv at se indslaget (11:17 – 14:08):
https://www.dr.dk/tv/se/ugen-plus-det-loese-med-huxi-bach/ugen-plus-det-...

Jeg tænkte på, om padden ^^ eller tabletten (hvad hedder den egentlig, sådan en fætter?) mon var lånt ude hos DataMusen – Datamuseet?
Fordi den ser så spændende og solid ud.
Den ligner en bærbar til børn ”i gamle dage”.
(Men den er måske ikke så gammel?) Men super cool.

  • 0
  • 0
Ivan Skytte Jørgensen

Det lyder umiddelbart en del anderledes - 286 (og 386+ for den sags skyld) har selectors til descriptor tabeller, hvorimod alt information her er encoded i pointeren.

Jeg tænkte mere på at operationer via en pointer var underlagt kontrol ikke kun R/W/X men også grænse. I 286erens protected mode blev der checke både om man overhovedet havde adgang til hukoemmelsen ved at lave opslag i descriptor-tabellen når en selector blev lagt ind i et segmentregister, og derudover bounds-checket ved fetch/store/execute.

At udvider selve pointerne med capabilities or bounds giver nogle interessante muligheder, som langt overgår hvad 286-protected-mode kan. Men med en omkostning på 128-bit pointere. Hrmmm...

Videoen som PHK linkede til om CHERI var interessant. En af de ting jeg lagde mærke til var at de havde fået Clang til at understøtte det. Jeg erinder at Ivan Godard et sted nævner at et stort problem med Clangs LLVM var at der ikke blev skelnet mellem integers og pointere hvis de var lige store - det forsvandt i optimiseren. Gad vide hvordan Robert Watson løste det problem.

  • 0
  • 0
Kristian Thy
  • 3
  • 0
Louise Klint

Yes, tak!

Jeg tænkte også ”80’ies something”.
Den lignede lidt et forstørret bib-bib-spil, fordi tastaturet var skjult på tv-indslaget. Så det var lidt svært at se, hvordan eller hvilke funktioner den kunne mestre. Man kan regne på den og måske også spille lidt? Nu kan jeg se det – zoom på billedet: Den kan spille musik (piano, do-re-mi-fa-so-la-ti-do), skrive og regne, huske og quizze. Og man kan spille to sammen. En leg & lær-computer til børn.
(Synes også tastaturet ser lidt avanceret ud for damahls, hvis det er en slags touch og ikke knapper, men hvad ved jeg). Og så kan den køre på batterier, så den er bærbar – blæret. Det med ”cartridge” ved jeg ikke rigtig, hvordan fungerer. Skal den fodres med disketter eller sager?
Den gråbrune farve sender tankerne tilbage i tid, og det solide ydre signalerer på en eller anden vis kram. (Krogen til at lukke med, på tv-versionen, holder i længden, tror jeg. Anderledes end hvad, man kan få fra Kina i dag. Jeg ved ikke med indmaden).

Var også lidt bange for, at jeg ville blive leet ud, fordi den måske ikke er noget særligt, hvad ved jeg, eller jeg tog fejl eller noget andet, men det går nok. Jeg synes den er fin.

  • 2
  • 0
Jan Heisterberg

Måske er der læsere, som har arbejdet med it i mange år, men egentlig aldrig været helt nede på HW niveauet, og undrer sig over hvordan .....

Forleden ledte et spørgsmål om "machine code" mig til Youtube.
Det viser sig, at der findes videoer mellem 10 og 60 minutter om mange forskellige dele - lige fra hvordan laves AND, OR og lignende kredsløb med et par transistorer til et kit med stumper til at lave egen basale computer (jfr. videoer herunder).

Specielt vil jeg fremhæve:
God forklaring på CPUens virkemåde. https://www.youtube.com/watch?v=VBDoT8o4q00
og bog: www.but how do it know.com
og
How do CPUs read machine code? — 6502 part 2
https://www.youtube.com/watch?v=yl8vPW5hydQ&authuser=0
Nogle læsere vil måske have glæde af forgængeren
“Hello, world” from scratch on a 6502
https://www.youtube.com/watch?v=LnzuMJLZRdU

  • 1
  • 0
Thomas Toft

Det var i forbindelse med, at Google lister sine produkter ind mange steder i skolevæsenet

Google? De er stort set ingen steder der i forhold til hvor dybt Apple og Microsoft har snablen nede i skole IT. Prøv at sig "iPads forbudt" i en skoleklasse og se hvor mange minutter der går før du bliver fyret. For slet ikke at tale om Office pakken og købstvang af Windows bærbar...

  • 3
  • 0
Torben Mogensen Blogger

... bortset fra det med at blive checket i hardware

Ja, det kommer vi nok til at se mere af. Altså check og lignende, der udføres i hardware i stedet for software. Her er et par oplagte muligheder:

  • Kodepointere, der kun kan pege på funktioners entry-points.
  • Stack-frames, der automatisk overskrives med 0, når man forlader en funktion.

Men man bør også gøre noget ved de sidekanaler, der kan opstå ved speculative execution.

  • 1
  • 0
Martin Pedersen

Google? De er stort set ingen steder der i forhold til hvor dybt Apple og Microsoft har snablen nede i skole IT. Prøv at sig "iPads forbudt" i en skoleklasse og se hvor mange minutter der går før du bliver fyret. For slet ikke at tale om Office pakken og købstvang af Windows bærbar...


Den opfattelse tror jeg du skal til at ændre, for Google lister sig hurtigt ind nu. Blandt andet udleverer to store kommuner som Aalborg og Aarhus nu Chromebooks til alle deres skoleelever, så der er iPads og Office pakken totalt ligegyldig.

  • 2
  • 0
Ivan Skytte Jørgensen

Kodepointere, der kun kan pege på funktioners entry-points.


Jeg formoder at med kodepointere så mener du de programmør-tilgængelige pointere. Hvis du mener alle kodepointere så skal man tage hensyn til at compileren i nogle tilfælge gerne vil optimere f.eks. switch() til "computed goto" fordi det kan give nogle forbløffende performanceforbedringer. Der var en præsentation på Cppcon (kan desværre ikke finde videoen pt) hvor en havde tryllet lidt og overtalt compileren til at genere den optimale kode med direkte jumps mellem switch-cases.

Kodepointere, der kun kan pege på funktioners entry-points.
Stack-frames, der automatisk overskrives med 0, når man forlader en funktion.


Hvorfor ikke nulstille dem når man går ind i funktionen i stedet? Det ville gøre det muligt at optimere nul-initialisering af variabler væk, og sikre at stack-framen var bragt ind i L1 cache.

  • 0
  • 0
Torben Mogensen Blogger

Hvorfor ikke nulstille dem når man går ind i funktionen i stedet? Det ville gøre det muligt at optimere nul-initialisering af variabler væk, og sikre at stack-framen var bragt ind i L1 cache.

Ved at nulstille dem, når man forlader en frame, så hindrer man, at man efterlader information på stakken, som kan give læk af hemmeligheder. Men ellers har du ret: Automatisk nulinitialisering af stakvariable er også en fin ide.

Man kunne evt. have nogle særlige virtuelle sider til kaldstakken og lade hardwaren vedligeholde den invariant, at al adgang til pladser over stakpointeren returnerer 0, og at en ny frame er nulinitialiseret. Det kan vedligeholdes ved at slette en frame ved udgang (således at en ny frame er garanteret nulstillet) eller ved at nulstille en frame, når den oprettes og derudover lade tilgang til den forkerte side af stakpegepinden returnere 0, uanset, hvad der ellers ligger i lageret. Jeg tror, at det nemmeste er automatisk sletning ved nedlæggelse af frames, sådan at al (virtuelt) lager på den forkerte side af stakpegepinden er fysisk lige med nul.

Alternativt kan tilgang til lager på den forkerte side af stakpegepinden give en undtagelse. Det er uanset, om sletning sker ved oprettelse eller nedlæggelse af frames. Med 64-bit adresser er der nok virtuelt adresserum til at lade kode, stak, og andet lager ligger i faste forskellige dele af det virtuelle adresserum, så man altid på de første 2-3 bit af en pointer kan se, om den peger på stak, kode eller andet.

  • 0
  • 0
Torben Mogensen Blogger

Jeg formoder at med kodepointere så mener du de programmør-tilgængelige pointere.

I princippet, ja. Men hvis det skal checkes i hardware, er det nok svært at skelne mellem en compileroprettet hoptabel og en programmøroprettet ditto.

En mulig model kunne være, at der laves instruktioner, der markerer entry points til funktioner, retursteder, samt jump targets. Hvis en (direkte eller indirekte) call instruktion ikke rammer en entry-point instruktion, hvis et returhop ikke rammer en return-point instruktion, eller et (direkte eller indirekte) hop ikke rammer en jump-target instruktion, så rejses en undtagelse. En instruktion kan evt. være både jump target og entry point eller enhver kombination af de tre (eller evt. flere) kategorier, feks. ved en bitvektor i instruktionskoden.

Det får selvfølgelig koden til at fylde lidt mere, men det behøver ikke at koste noget særligt i tid -- det kan checkes under prefetch af instruktioner.

  • 1
  • 0
Michael Cederberg

CHERI handler kort og godt om at udstyre pointere med sikkerhedsseler og airbags.

Det problem er allerede løst. Vi har JVM/.Net style virtuelle maskiner. Vi har også sprog som Rust der også løser problemet. Der er selvfølgelig stadigvæk mange ting der stadigvæk kan forbedres, fx. er garbage collection nok ikke den smarteste memory management strategi for et operativsystem.

Disse kræver at man smider C/C++ i havnen og det vil såmænd ikke være så skidt. Personligt kan jeg sige at jeg glæder mig til den dag hvor jeg ved at jeg aldrig mere skal debugge en overskredet datastruktur eller call stack.

Jeg har svært ved at se ideen med at pointere lige pludseligt skal fylde mere end dobbelt så meget, når dette fint kan løses med software. Det her minder lidt for meget om segmenterne i Intel's 286 arkitektur (selvom det selvfølgelig er noget helt andet).

  • 0
  • 0
Ivan Skytte Jørgensen

Ved at nulstille dem, når man forlader en frame, så hindrer man, at man efterlader information på stakken, som kan give læk af hemmeligheder.


Ahh, så forstår jeg din præference for nulstilling ved indgang. Det beskytter selvf. mod at snuse til data i returenede funktionskalde, men der er stadig muligt at snuse bagvendt/opad i stakken. F.eks authenticate_user() har et kald til printf("Password match"), og man angriber printf-kaldet, som så kan snuse baglæns til hvor authenticate_user() har gemt det dekrypterede password.
Jeg tror desværre at den eneske løsning på de problemer at programmørerne er mere omhyggelige.

  • 0
  • 0
Ivan Skytte Jørgensen

En mulig model kunne være, at der laves instruktioner, der markerer entry points til funktioner, retursteder, samt jump targets.


Ikke nogen dårlig ide. CPUerne nu til dags er ret gode til at ignorere code-bytes som ingen effekt har (f.eks. "rep"-prefikset på "ret"). Så man kan have disse 4 muligheder:
1: umærket (giver fault/exception hvis det er target for jmp/call/ret)
2: markeret for target for call instruktioner (direkte eller indirekte)
3: markeret for target af indirekte jump
4: markeret for target for return-instruktion.

(2) skal også være tilladt at gå til med indirekte jumps - ellers vil dynamic relocation tabellener ikke længere kunne være den klassiske "jmp *(0x486567f9)" konstruktion, og istedet være et alm. call og koste 4/8 bytes mere på stakken.

Det ville ikke fylde meget i koden og formodentlig ingen performance-indvirking have.

  • 1
  • 0
Morten Bøgh

Pointere i mainframe-programmel har sikkerhedsseler og airbags. Det havde maskinen allerede i 1980 da jeg startede med at arbejde med mainframe: Hvis en pointer ramte udenfor programmets 'adresseringsrum', dvs det område som trådens maskininstruktioner var blevet tildelt af operativsystemet, blev tråden slået ned af operativsystemet med en 0c4-exception. En overliggende tråd fik så kontrollen igen, men vejen i undertråden var spærret. Indenfor eget adresseringsrum er der fri leg, og et program der farer vild, kan smadre som det nu vil - indtil det bliver stoppet af en exeption.
I de efterfølgende 40 år har forholdene inde i maskinen ændret sig radikalt. Tråde på mainframe kører i dag i sit eget adresseringsrum, og 0c4-teknikken er derfor lidt irrelevant. Omend man stadig kan have fornøjelse af en 0c4-exception hvis man roder i sine pointere.
Man kan gerne på mainframe kalde ind i andre adresseringsrum, men dette er voldsomt reguleret af operativsystemet i form af services.

RACF sikkerhedssystemet på mainframe regulerer adgang til de data man måtte komme i kontakt med ved fx. at gå over i adresseringsrummet for DB2. Dette er i dag en mere væsenligt beskyttelse end 0c4-adresse-kontrollen.

Ovenstående gælder når man arbejder på mainframe med z/OS maskinkode. Man kan også køre mainframe under Unix og Linux, og så er man ude i det vilde vesten hvor pointere kan give eksotiske oplevelser, omend RACF stadig hersker.

  • 0
  • 0
Sune Marcher

Pointere i mainframe-programmel har sikkerhedsseler og airbags.


De faciliteter du beskriver har x86 processorne haft siden 386 med paging – og mulighed for at markere heap/stack som Non-eXecutable siden engang i de tidlige 2000'ere.

Det er bare ikke nok beskyttelse, da man kan stykke exploit-kode sammen med ROP – der lyder Torben Mogensens forslag om "instruktioner, der markerer entry points til funktioner, retursteder, samt jump targets." som en interessant mitigation.

  • 2
  • 0
Log ind eller Opret konto for at kommentere