mboost-dp1

Shutterstock

Google støtter Linux-projekt: Android og Chrome OS skal være sværere at hacke

- Via CNET -

I flere årtier har Google gjort brug af programmeringssproget C i forbindelse med operativsystemet Linux, men nu arbejder it-virksomheden målrettet på at bruge Rust-kode for at modvirke hacking.

Ifølge CNET finansierer Google i øjeblikket et projekt, hvis formål er at øge sikkerheden mod hacking.

Projektet består endvidere i at anvende programmeringssproget Rust til at skrive kode i den såkaldte Linuxkerne (Linux kernel), som svarer til hjertet bag operativsystemet.

Hvis projektet lykkes, vil det betyde en modernisering af sikkerheden bag internettet og smartphones samt et markant teknologisk skift i den open-source-software, der danner grundlaget for Googles Android- og Chrome-operativsystemer.





Gå til bund
Gravatar #1 - linos
20. jun. 2021 05:06
Det er et ret interessant projekt - men vil tilføjelse af Rust ikke mere "tilføje sikkerhed" ved at lade programmeringssproget tage sig af thread/memory-safe kode, frem for selv at skulle gøre det?

Ret mig hvis jeg tager fejl, men C er et ret low-level high-level programmerings sprog, ikke? Altså... Det er ikke super meget mere end en mere menneske-læsbar assembly (og nogle biblioteker), vel? Så så længe man har forståelse for virkemåden på forskellige arkitekturer, og ved hvad man laver, er C vel ikke mere usikkert end Rust? Så hvad Rust gør, er at gøre det nemmere for folk at skrive thread/memory-safe kode, end med C, ikke? Hvis den antagelse er korrekt, er det vel næppe at det der allerede er i Linux-kernel bliver omskrevet til Rust for at gøre den mere sikker, men nærmere at fremtidige kontributioner ikke behøver at skrives med samme ekspertise, som kernel-kode kræver med C. Og hvis det passer, er det vel næppe en revolution i forhold til sikkerhed på servere og så videre, men mere at det er nemmere at bidrage, eller hvad?

Det er nok ret nemt at se ud fra ovenstående at jeg ikke er udvikler. Jeg har kodet lidt på hobbyplan, mest scripts, men har skrevet få små programmer, og har kodet lidt assembly på en microcontroller (single-core), og PLC (selv om det mest er ret forskelligt fra måden at programmere anden hardware (Omron PLC kunne man dog kode i noget der kunne minde en anelse om en parallel til assembly, før de skiftede til en ny version af deres programmeringssoftware. Det var ret intuitivt, og enormt meget hurtigere end at lave ladder-diagrammer).
Gravatar #2 - AppleSheep
20. jun. 2021 07:22
Goddag hr. elektriker. Har du også fiflet lidt med kode til Hitachi PLC'er? Det minder også meget om en ultra light udgave af assembler, så hudt jeg visker. Det er fanme mange år siden jeg har leget med den slags :)
Gravatar #3 - linos
21. jun. 2021 06:06
Goddag, hr. får. Det har jeg ikke, nej. Jeg har kun arbejdet med Omron og Siemens, og Omron er klart min favorit. De kan godt nok lave komponenter der kan klare både mekaniske og elektriske tæsk (jaja - de er dyrere, men tjener sig selv ind med en faktor 10 ved at mindske nedbrud).
"Så hudt jeg visker", det plejede min matematiklærer at sige, haha. Og elektriker blev til epileptrikker. Hun var sgu spøjs :D
Ikke desto mindre kunne det da være interessant nok at rode med sådan en Hitachi PLC!
Gad egentligt vide om der eksisterer lignende sprog til Arduino, og den slags. Jeg ved godt at de kan kodes i assembly, men PLC-"assembly", er mere fokuseret på at manipulere ind- og udgange
Gravatar #4 - larsp
21. jun. 2021 07:44
#1 Ja, i det store og hele korrekt angående C og rust.

Men det er faktisk en ret stor ting at rust compileren kan garantere memory access sikkerhed og sikker multithreading. Selv erfarne C udviklere kan have en dårlig dag og snige sikkerhedsfejl ind man ikke lige opdager, og i store kollaborative C projekter som Linux kernelen er det en monumental opgave at checke al koden.

Rust er næsten en form for "have your cake and eat it" deal, fordi det plejer at koste runtime performance at have den slags sikkerhedsgarantier. Rust kan levere både optimal performance og data sikkerhed på samme tid. Man betaler så med et noget mere udfordrende sprog at arbejde med og længere tid for kompilering.
Gravatar #5 - linos
21. jun. 2021 08:42
#4 Tak for svaret.
Det er jo fantastisk når den slags kan lade sig gøre! Jeg havde en idé om at det ikke ville koste (meget) runtime performance, ellers tror jeg Linus ville have sat sig på tværs, haha. Men det er ikke noget jeg vidste med nogen former for sikkerhed.
Nu ved jeg faktisk ikke om han også tilføjer til kernel mere, eller om han er så tralvt beskæftiget med at gennemgå commits at han ikke har tid til det, men jeg tvivler på vi kommer til at se *ham* arbejde i Rust, udover gennemgang.
Hvad thread/memory-safe kode angår, så kan jeg godt forestille mig at det ikke er nemt. Det tætteste jeg har været på at arbejde med det, var et program jeg skrev i C# til at kommunikere med en maskine over en seriel-port, hvor jeg var nødt til at arbejde med threading, hvilket var et mareridt at lære om, når jeg i forvejen kun kendte til single-core C++ programmering, fra mange år tidligere. Jeg prøvede ihærdigt at undgå at skulle kode til multithread, men hvis jeg husker ret, kommer seriel-data ind på tilfældige threads, så man kan vidst ikke slippe for det. Men det er en 7-8år siden nu, og har kun scriptet lidt siden ':D
Pointen er at C# er high-level, og der skulle man stadigvæk springe igennem en del hoops, for at kunne lave et sammenhængende program, så jeg kan kun forestille mig hvor besværligt det må være i lavere levels, og have så meget styr på alting at man ikke pludseligt tillader andre kerner/applikationer at tilgå data fra en anden kerne/applikation.
Gravatar #7 - arne_v
21. jun. 2021 17:35
#1

Der er lidt forskel på hobby og professionel her.

En hobby programmør vil normal skelne mellem "kode der virker" og "kode der ikke virker" mens en professionel vil skelne mellem "korrekt kode" og "ikke korekt kode".

"korrekt kode" vil altid være "kode der virker".

"kode der ikke virker" vil altid være "ikke korekt kode".

Problemet er "ikke korekt kode" som er "kode der virker".

Det er kode som i den sammnhæng hvor den testes virker fint, men som ikke er garanteret at virke i alle sammenhænge.

Mange concurrency problemer falder i den kategori.

Det virker fint i udvikling og test, men når de kommer ud i den virkelige verden så rammer de på et tidspunkt det sammenfald af faktorer der resulterer i fejl.

Hvis en hobby programmør får udpeget en fejl i vedkommendes kode, så er det meget sandsynligt at vedkommende siger "åh - det var jeg ikke klar over".

Hvis en professionel programmør får udpeget en fejl i vedkommendes kode, så er det meget sandsynligt at vedkommende siger "åh - det vidste jeg jo godt".

I professionel sammenhæng bliver fejl ikke lavet fordi udviklerne mangler viden om hvordan det skal gøres - fejl bliver lavet fordi udviklerne gør det rigtigt de fleste gange men en gang imellem glemmer at tænke på noget.
Gravatar #8 - arne_v
21. jun. 2021 18:05
#5

Multithreaded programmering i C# behøver ikke at være kompliceret.

Men man skal lave et bevist valg om at gøre det simpelt.

1) Ved et fast lille antal tråde start manuelt ellers brug en thread pool.
2) Brug lock på al tilgang til objekter der deles mellem tråde
3) Undgå for enhver pris Monitor Wait og Pulse*.
4) Gå generelt efter simpel kode og undgå "premature optimization"

Gravatar #9 - Claus Jørgensen
21. jun. 2021 20:17
#8

Og brug readonly så meget så muligt

Man kan ikke have data races hvis dataen ikke er mutable :p
Gravatar #10 - larsp
22. jun. 2021 14:11
#8 Uforsigtig brug af locks kan føre til dårlig performance, nestede locks og pludselig sidder man en uge og leder efter en nasty deadlock.

Jeg er stor fan af threadsafe queues til at overføre data eller opgaver til threads i stedet. Men det er muligvis et idiom der giver mere mening i embedded RTOS verdenen, hvor man har evigt levende threads (også kaldt tasks) der tager sig af distinkte opgaver, f.eks. buzzer, LED animationer, læse joystick, IO.
Gravatar #11 - arne_v
22. jun. 2021 15:14
#10

Undgå CLR locks fordi det giver dårlig performance er typisk "premature optimization".

Det koster ca. 50 nano-sekunder i overhead. I næsten alle sammenhæng er det ingenting.

Det kan naturligvis koste langt mere i manglende parallelisering, men det er jo ikke overhead - det er noget som er givet for at det skal virke korrekt.

CLR locks er reentrante så en tråd kan ikke deadlocke sig selv. I teorien kunne to tråde deadlocke hinanden. Men jeg har fulgt .NET fora på nettet i 18 år og jeg har aldrig hørt om nogen med et sådant problem. Det sker hele tiden i databaser, men den måde data strukturer i memory tilgåes på lægger tilsyneladende ikke op til problemet.

En thread safe queue er en glimrende ting. Men bemærk at det jo reelt er at lade en andens kode håndtere problemet fremfor ens egen kode. Men stadig en god ting fordi udvikleren bag den thread safe queue har formentlig bedre forståelse for concurrency problemer end gennemsnits udvikleren.
Gravatar #12 - arne_v
22. jun. 2021 15:21
#11

50 ns er på en moderne GHz general purpose CPU.

En custom "thingy" kan være meget langsommere.

Men en sådan "thingy" kører ikke .NET.
Gravatar #13 - larsp
22. jun. 2021 15:53
#11 Vedr. performance tænkte jeg på det at skulle vente på at få en lock fordi en anden holder den og er sløv til at frigive den igen. F.eks. log printing på en serielport. Kun en task må printe samtidigt. Beskytter man det med en mutex (lock) kan én tråd stå og vente mange millisekunder på at en anden tråd er færdig med at printe. Her giver det bedre performance at lægge log printe opgaven i en message queue.

Man kan hurtigt få lavet en deadlock race hvis man nester lock tagning og bytter om på rækkefølgen:

Tråd1: Mens lock A haves, tag lock B.

Tråd2: Mens lock B haves, tag lock A.

Kører ovenstående samtidigt er der deadlock. Den er muligvis ekstrem sjælden hvis det er hurtig afviklet kode, men så meget desto værre. Nested lock tagning er absolut fy-fy i min bog. Jeg løb ind i det fordi et uskyldigt udseende funktions kald viste sig at tage en lock.
Gravatar #14 - larsp
22. jun. 2021 16:07
#12 I FreeRTOS er en thread safe queue et første klasses synkroniseringsobjekt leveret af RTOS og en struktur de anbefaler at bruge til at koordinere tasks helt generelt. Også til deferred interrupt processering hvor man fra et hardware interrupt lægger en besked i en kø, som så vækker en tråd op der læser fra køen blokerende. Det er et rigtigt godt pattern.

Jeg blev faktisk overrasket over at en sådan kø ikke var en første klasses synkroniseringsmekanisme i andre sprog, og at man var nød til at finde den i libraries eller kode den selv (hvilket ikke er helt nemt).
Gravatar #15 - arne_v
22. jun. 2021 16:49
#14

Jeg kan godt lide queues.

:-)

Dog ActiveMQ/ArtemisMQ, RabbitMQ, Kafka type of queues.

Men det er jo på mange måder det samme bare tilpasset en anden kontekst.

De fleste OS har vel noget in memory kommunikation (Unix socket, Windows pipe, VMS mailbox etc.), men måske ikke så vel designet til multi-threaded brug som RTOS.

Men så er der jo bibliotekerne.

C# udviklere kan bruge System.Collections.Concurrent.ConcurrentQueue<T>.

Og Java udviklere kan bruge en java.util.concurrent.BlockingQueue<E> implementation.
Gravatar #16 - arne_v
22. jun. 2021 16:55
larsp (13) skrev:

#11 Vedr. performance tænkte jeg på det at skulle vente på at få en lock fordi en anden holder den og er sløv til at frigive den igen. F.eks. log printing på en serielport. Kun en task må printe samtidigt. Beskytter man det med en mutex (lock) kan én tråd stå og vente mange millisekunder på at en anden tråd er færdig med at printe. Her giver det bedre performance at lægge log printe opgaven i en message queue.


Ja. Men det kalder jeg at skifte fra en sync model til en async model.

larsp (13) skrev:

Man kan hurtigt få lavet en deadlock race hvis man nester lock tagning og bytter om på rækkefølgen:

Tråd1: Mens lock A haves, tag lock B.

Tråd2: Mens lock B haves, tag lock A.

Kører ovenstående samtidigt er der deadlock. Den er muligvis ekstrem sjælden hvis det er hurtig afviklet kode, men så meget desto værre. Nested lock tagning er absolut fy-fy i min bog. Jeg løb ind i det fordi et uskyldigt udseende funktions kald viste sig at tage en lock.


Det er ikke svært at lave et eksempel på det. Og man kan også Google eksmepler.

Men i virkelig C# kode er det et meget sjældent problem.

Og jeg kan ikke se at man skulle undgå lock af den grund.
Gravatar #17 - arne_v
22. jun. 2021 17:01
#16

En af grundene til at det ses så sjældent er formentligt at man tit vælger at bruge en højere lock.

Så ikke:

lock(a)
{
lock(b)
{
// update a and b
}
}

men:

private object ab = new object();
..
lock(ab)
{
// update a and b
}

og ikke:

lock(x[i])
{
lock(x[j])
{
// update x[i] and x[j]
}
}

men:

lock(x)
{
// update x[i] and x[j]
}

o.s.v..
Gravatar #18 - dugfrisk
22. jun. 2021 17:05
ingen havde blender
Gravatar #19 - arne_v
22. jun. 2021 17:07
#17

Højere locks begrænser selvfølgelig yderligere paralleliteten.

Men er det et problem??

Hvis ja så er man nødt til at gøre noget, men hvis nej så er der sikkert andre steder i koden hvor ens tid kan bruges bedre.
Gravatar #20 - larsp
23. jun. 2021 14:05
Ja, højere locks virker som en udemærket pragmatisk løsning.

Men en af forskellene er at du taler om locks til at sikre dataintegritet, hvor jeg taler mere om mutexer hvor en lock begrænser adgang til en resource hvor man ofte må holde låsen i længere tid. Det er her det begynder at blive tricky og man bør overveje queues.

Mutexen i FreeRTOS har iøvrigt en pudsig feature til at forbedre en situation de kalder priority inversion. Hvis en lavt prioriteret task holder en mutex, og en højt prioriteret task nu også vil have den, så får den lave task undtagelsesvist samme høje prioritet som den høje task, så den kan blive færdig i en fart og aflevere mutex. Ellers ville den høje task reelt have den lave prioritet mens det stod på.

Det slår mig også at deadlocks faktisk er en af de få ting Rust ikke kan beskytte imod, mig bekendt. Så selv med Rust til hjælp er det stadig vigtigt at have noget viden om multithreading.
Gravatar #21 - arne_v
23. jun. 2021 15:29
#20

Der er forskel på in-memory data-strukturer og hardware.

Men i .NET er der ikke nogen sammenhæng mellem hvad du låser på og hvad du ønsker at beskytte.

lock(x)
{
// brug x memory
}

og

lock(x)
{
// brug ikkex memory
}

og

lock(x)
{
// brug noget HW
}

virker helt ens for lock delen.

Forskellen er nok kun at tilgang til memory måles i nano sekunder mens tilgang til hardware måles i millisekunder/sekunder.
Gravatar #22 - arne_v
23. jun. 2021 15:31
#20

Den priority inversion feature giver faktisk god mening.

Åbenlys fordel ved et OS som er designet til real time formål.
Gravatar #23 - Claus Jørgensen
24. jun. 2021 10:14
#21

Er det ikke stadigvæk best practice at lock på et unrelated object?
Gravatar #24 - dugfrisk
24. jun. 2021 10:15
hvorfor forbedre noget, når man kan købe noget nyt?
Gravatar #25 - Claus Jørgensen
24. jun. 2021 11:39
dugfrisk (24) skrev:
hvorfor forbedre noget, når man kan købe noget nyt?
нет товарищ
Gravatar #26 - arne_v
24. jun. 2021 12:33
#23

Det er ihvertfald det mest almindelige. Altså i C#.

Engang tilbage i .NET 1.x dagene blev det hævdet at der var problemer med at locke på det objekt man faktisk arbejdede på.

Og lige siden har de fleste .NET udviklere undgået det.

I samme periode har Java udviklere rask væk locket på det objekt man faktisk arbejder på. Uden at der er set mange problemer.

Det er risiko for deadlock som bruges som begrundelse.

Men hvis to tråde ønsker at låse adgang til det samme objekt, så er separate lock objekter jo ikke lige løsningen.


Gravatar #27 - arne_v
24. jun. 2021 15:52
#26

En del af de mest relevante klasser har en SyncRoot property så man kan bruge:

lock(x.SyncRoot)
{
// bruge x
}

Men hvorfor det skulle være bedre end:

lock(x)
{
// bruge x
}

er ikke åbenlyst for mig.
Gå til top

Opret dig som bruger i dag

Det er gratis, og du binder dig ikke til noget.

Når du er oprettet som bruger, får du adgang til en lang række af sidens andre muligheder, såsom at udforme siden efter eget ønske og deltage i diskussionerne.

Opret Bruger Login