Aggiornamento dinamico del software - Dynamic software updating
In informatica , l'aggiornamento del software dinamico ( DSU ) è un campo di ricerca di pertinenza di riqualificazione programmi mentre sono in esecuzione. La DSU non è attualmente ampiamente utilizzata nell'industria. Tuttavia, i ricercatori hanno sviluppato un'ampia varietà di sistemi e tecniche per implementare la DSU. Questi sistemi vengono comunemente testati su programmi del mondo reale.
Gli attuali sistemi operativi e linguaggi di programmazione in genere non sono progettati pensando alla DSU. In quanto tali, le implementazioni DSU comunemente utilizzano strumenti esistenti o implementano compilatori speciali . Questi compilatori conservano la semantica del programma originale, ma strumentano il codice sorgente o il codice oggetto per produrre un programma aggiornabile dinamicamente. I ricercatori confrontano le varianti dei programmi compatibili con DSU con il programma originale per valutare la sicurezza e le prestazioni generali.
introduzione
Qualsiasi programma in esecuzione può essere pensato come una tupla , dove è lo stato del programma corrente ed è il codice del programma corrente. I sistemi dinamici di aggiornamento del software trasformano un programma in esecuzione in una nuova versione . Per fare ciò, lo Stato deve trasformarsi nella rappresentazione che si aspetta. Ciò richiede una funzione di trasformatore di stato . Pertanto, DSU trasforma un programma in . Un aggiornamento è considerato valido se e solo se il programma in esecuzione può essere ridotto ad una tupla di punti raggiungibile dal punto di partenza della nuova versione del programma ,.
La posizione in un programma in cui si verifica un aggiornamento dinamico viene definita punto di aggiornamento . Le implementazioni esistenti di DSU variano ampiamente nel trattamento dei punti di aggiornamento. In alcuni sistemi, come UpStare e PoLUS , può verificarsi un aggiornamento in qualsiasi momento durante l'esecuzione. Il compilatore di Ginseng tenterà di dedurre buone posizioni per i punti di aggiornamento, ma può anche utilizzare punti di aggiornamento specificati dal programmatore. Kitsune ed Ekiden richiedono agli sviluppatori di specificare e nominare manualmente tutti i punti di aggiornamento.
I sistemi di aggiornamento differiscono nei tipi di modifiche al programma che supportano. Ad esempio, Ksplice supporta solo le modifiche al codice nelle funzioni e non supporta le modifiche alla rappresentazione dello stato. Questo perché Ksplice prende di mira principalmente le modifiche alla sicurezza, piuttosto che gli aggiornamenti generali. Al contrario, Ekiden può aggiornare un programma a qualsiasi altro programma in grado di essere eseguito, anche uno scritto in un linguaggio di programmazione diverso. I progettisti di sistemi possono ottenere prestazioni preziose o garanzie di sicurezza limitando la portata degli aggiornamenti. Ad esempio, qualsiasi controllo di sicurezza degli aggiornamenti limita l'ambito degli aggiornamenti agli aggiornamenti che superano tale controllo di sicurezza. Il meccanismo utilizzato per trasformare il codice e lo stato influenza i tipi di aggiornamenti supportati da un sistema.
I sistemi DSU, come strumenti, possono anche essere valutati in base alla loro facilità d'uso e chiarezza per gli sviluppatori. Molti sistemi DSU, come Ginseng , richiedono che i programmi superino varie analisi statiche. Sebbene queste analisi dimostrino le proprietà dei programmi che sono utili per la DSU, sono per natura sofisticate e difficili da capire. I sistemi DSU che non utilizzano un'analisi statica potrebbero richiedere l'uso di un compilatore specializzato. Alcuni sistemi DSU non richiedono né analisi statiche né compilatori speciali.
I programmi aggiornati da un sistema DSU sono indicati come programmi di destinazione . Le pubblicazioni accademiche dei sistemi DSU includono comunemente diversi programmi target come casi di studio. vsftpd , OpenSSH , PostgreSQL , Tor , Apache , GNU Zebra , memcached e Redis sono tutti obiettivi di aggiornamento dinamico per vari sistemi. Poiché pochi programmi sono scritti pensando al supporto per l'aggiornamento dinamico, il retrofit dei programmi esistenti è un mezzo prezioso per valutare un sistema DSU per l'uso pratico.
Campi correlati
Lo spazio problematico affrontato dall'aggiornamento dinamico può essere pensato come un'intersezione di molti altri. Gli esempi includono checkpoint , collegamento dinamico e persistenza . Ad esempio, un database che deve essere compatibile con le versioni precedenti del formato di file su disco, deve eseguire lo stesso tipo di trasformazione dello stato previsto da un sistema di aggiornamento dinamico. Allo stesso modo, un programma che ha un'architettura a plugin, deve essere in grado di caricare ed eseguire nuovo codice in fase di runtime.
Talvolta tecniche simili vengono impiegate anche allo scopo di eliminare il codice morto dinamico per rimuovere il codice condizionatamente inattivo o irraggiungibile al caricamento o in fase di esecuzione e ricombinare il codice rimanente per ridurre al minimo il suo footprint di memoria o migliorare la velocità.
Storia
Il primo precursore dell'aggiornamento dinamico del software sono i sistemi ridondanti . In un ambiente ridondante, esistono sistemi di riserva pronti a prendere il controllo dei calcoli attivi in caso di guasto del sistema principale. Questi sistemi contengono una macchina principale e un hot spare . L'hot spare verrebbe periodicamente seminato con un checkpoint del sistema primario. In caso di guasto, subentrerebbe l'hot spare e la macchina principale diventerebbe il nuovo hot spare. Questo modello può essere generalizzato all'aggiornamento. In caso di aggiornamento, l'hot spare si attiverebbe, il sistema principale si aggiornerà e quindi il sistema aggiornato riprenderà il controllo.
Il vero sistema di aggiornamento del software dinamico prima è Dymos ( Dy NAMIC Mo dification S ystem). Presentato nel 1983 nella tesi di dottorato di Insup Lee, DYMOS era un sistema completamente integrato che aveva accesso a un'interfaccia utente interattiva, un compilatore e runtime per una variante Modula e un codice sorgente. Ciò ha consentito a DYMOS di verificare il tipo di aggiornamenti rispetto al programma esistente.
Implementazione
I sistemi DSU devono caricare il nuovo codice in un programma in esecuzione e trasformare lo stato esistente in un formato comprensibile dal nuovo codice. Poiché molti casi d'uso motivazionali di DSU sono critici in termini di tempo (ad esempio, la distribuzione di una correzione per la sicurezza su un sistema attivo e vulnerabile), i sistemi DSU devono fornire un'adeguata disponibilità di aggiornamento . Alcuni sistemi DSU tentano anche di garantire che gli aggiornamenti siano sicuri prima di applicarli.
Non esiste una soluzione canonica a nessuno di questi problemi. In genere, un sistema DSU che funziona bene in un'area problematica lo fa a un compromesso con gli altri. Ad esempio, il test empirico degli aggiornamenti dinamici indica che aumentando il numero di punti di aggiornamento si ottiene un numero maggiore di aggiornamenti non sicuri.
Trasformazione del codice
La maggior parte dei sistemi DSU utilizza le subroutine come unità di codice per gli aggiornamenti; tuttavia, i sistemi DSU più recenti implementano aggiornamenti dell'intero programma.
Se il programma di destinazione è implementato in un linguaggio della macchina virtuale , la VM può utilizzare l'infrastruttura esistente per caricare nuovo codice, poiché le macchine virtuali moderne supportano il caricamento del runtime per altri casi d'uso oltre a DSU (principalmente debug ). La JVM HotSpot supporta il caricamento del codice runtime e i sistemi DSU destinati a Java (linguaggio di programmazione) possono utilizzare questa funzione.
Nei linguaggi nativi come C o C ++ , i sistemi DSU possono utilizzare compilatori specializzati che inseriscono riferimenti indiretti nel programma. Al momento dell'aggiornamento, questo riferimento indiretto viene aggiornato in modo da puntare alla versione più recente. Se un sistema DSU non utilizza un compilatore per inserire staticamente questi riferimenti indiretti, li inserisce in fase di esecuzione con riscrittura binaria . La riscrittura binaria è il processo di scrittura di codice di basso livello nell'immagine di memoria di un programma nativo in esecuzione per reindirizzare le funzioni. Sebbene ciò non richieda un'analisi statica di un programma, è altamente dipendente dalla piattaforma.
Ekiden e Kitsune caricano il nuovo codice del programma avviando un programma completamente nuovo, tramite fork-exec o caricamento dinamico . Lo stato del programma esistente viene quindi trasferito nel nuovo spazio del programma.
Trasformazione dello stato
Durante un aggiornamento, lo stato del programma deve essere trasformato dalla rappresentazione originale alla rappresentazione della nuova versione. Questo è indicato come trasformazione dello stato . Una funzione che trasforma un oggetto di stato o un gruppo di oggetti viene definita funzione di trasformatore o trasformatore di stato .
I sistemi DSU possono tentare di sintetizzare le funzioni del trasformatore o richiedere che lo sviluppatore le fornisca manualmente. Alcuni sistemi mescolano questi approcci, deducendo alcuni elementi dei trasformatori mentre richiedono l'input dello sviluppatore su altri.
Queste funzioni del trasformatore possono essere applicate pigramente allo stato del programma, quando si accede a ogni parte dello stato della vecchia versione, oppure trasformando con impazienza tutti gli stati al momento dell'aggiornamento. La trasformazione lenta garantisce che l'aggiornamento venga completato in tempo costante, ma incorre anche in un sovraccarico di stato costante sull'accesso agli oggetti. La trasformazione desiderosa comporta maggiori spese al momento dell'aggiornamento, richiedendo al sistema di fermare il mondo mentre tutti i trasformatori funzionano. Tuttavia, l'entusiasmo della trasformazione consente ai compilatori di ottimizzare completamente l'accesso allo stato, evitando il sovraccarico di stato stazionario associato alla trasformazione lenta.
Aggiorna la sicurezza
La maggior parte dei sistemi DSU tenta di mostrare alcune proprietà di sicurezza per gli aggiornamenti. La variante più comune del controllo di sicurezza è l'indipendenza dal tipo, in cui un aggiornamento è considerato sicuro se non risulta in un nuovo codice che opera su una vecchia rappresentazione dello stato o viceversa.
La sicurezza del tipo viene in genere verificata mostrando una delle due proprietà, sicurezza dell'attività o sicurezza contro la libertà . Un programma è considerato sicuro per l'attività se non esiste alcuna funzione aggiornata nello stack di chiamate al momento dell'aggiornamento. Ciò dimostra la sicurezza perché il controllo non può mai tornare al vecchio codice che avrebbe accesso a nuove rappresentazioni di dati.
Contro-Freeness è un altro modo per dimostrare l'indipendenza dai tipi, in cui una sezione di codice è considerata sicura se non accede allo stato di un dato tipo in un modo che richiede la conoscenza della rappresentazione del tipo. Si può dire che questo codice non accede allo stato concretamente , mentre può accedere allo stato in modo astratto . È possibile dimostrare o smentire la contro libertà per tutti i tipi in qualsiasi sezione di codice e il sistema DSU Ginseng lo utilizza per dimostrare la sicurezza dei tipi. Se una funzione si è dimostrata priva di contro , può essere aggiornata anche se è live sullo stack, poiché non causerà un errore di tipo accedendo allo stato utilizzando la vecchia rappresentazione.
L'analisi empirica della contro-libertà e della sicurezza dell'attività svolta da Hayden e tutti mostrano che entrambe le tecniche consentono gli aggiornamenti più corretti e negano gli aggiornamenti più errati. Tuttavia, la selezione manuale dei punti di aggiornamento genera zero errori di aggiornamento e consente comunque la disponibilità di aggiornamenti frequenti.
Sistemi esistenti
DYMOS
DYMOS è notevole in quanto è stato il primo sistema DSU proposto. DYMOS consiste in un ambiente completamente integrato per programmi scritti in un derivato di Modula , che fornisce al sistema l'accesso a un interprete di comandi, codice sorgente, compilatore e ambiente di runtime, simile a un REPL . In DYMOS, gli aggiornamenti vengono avviati da un utente che esegue un comando nell'ambiente interattivo. Questo comando include direttive che specificano quando può verificarsi un aggiornamento, chiamate quando-condizioni . Le informazioni a disposizione di DYMOS consentono di imporre la protezione dai tipi degli aggiornamenti rispetto al programma di destinazione in esecuzione.
Ksplice, kpatch e kGraft
Ksplice è un sistema DSU che prende di mira solo il kernel Linux , rendendosi uno dei sistemi DSU specializzati che supportano un kernel del sistema operativo come programma di destinazione. Ksplice utilizza a livello sorgente diff per determinare i cambiamenti tra le versioni attuali e aggiornate del kernel di Linux, e quindi utilizza la riscrittura binario per inserire le modifiche nel kernel in esecuzione. Ksplice è stato mantenuto da un'impresa commerciale fondata dai suoi autori originali, Ksplice Inc., che è stata acquisita da Oracle Corporation nel luglio 2011. Ksplice è utilizzato su base commerciale ed esclusivamente nella distribuzione Oracle Linux .
SUSE ha sviluppato kGraft come alternativa open source per il patching del kernel live e Red Hat ha fatto lo stesso con kpatch . Entrambi consentono di applicare modifiche a livello di funzione a un kernel Linux in esecuzione, facendo affidamento sui meccanismi di patching in tempo reale stabiliti da ftrace . La differenza principale tra kGraft e kpatch è il modo in cui garantiscono la coerenza di runtime delle sezioni di codice aggiornate mentre vengono applicate le patch a caldo . kGraft e kpatch sono stati presentati per l'inclusione nella mainline del kernel Linux rispettivamente nell'aprile 2014 e nel maggio 2014, e le basi minimaliste per il live patching sono state fuse nella mainline del kernel Linux nella versione 4.0 del kernel, rilasciata il 12 aprile 2015.
Dall'aprile 2015, sono in corso lavori sul porting di kpatch e kGraft sul core di patch live comune fornito dalla linea principale del kernel Linux. Tuttavia, l'implementazione dei meccanismi di coerenza a livello di funzione, necessari per transizioni sicure tra la versione originale e quella corretta delle funzioni, è stata ritardata perché gli stack di chiamate forniti dal kernel Linux possono essere inaffidabili in situazioni che coinvolgono codice assembly senza gli stack frame appropriati ; di conseguenza, il lavoro di porting rimane in corso a settembre 2015. Nel tentativo di migliorare l'affidabilità degli stack di chiamate del kernel, è stata sviluppata anche un'utilità dello spazio utente dello stacktool per il controllo dell'integrità con lo scopo di controllare i file oggetto in fase di compilazione del kernel e assicurando che lo stack di chiamate sia sempre mantenuto; apre anche la possibilità di ottenere stack di chiamate più affidabili come parte dei messaggi oops del kernel .
Ginseng
Il ginseng è un sistema DSU generico. È l'unico sistema DSU ad utilizzare la tecnica di sicurezza contro la libertà , che gli consente di aggiornare le funzioni che sono attive nello stack purché non effettuino accessi concreti a tipi aggiornati.
Ginseng è implementato come compilatore da sorgente a sorgente scritto utilizzando il framework C Intermediate Language in OCaml . Questo compilatore inserisce riferimenti indiretti a tutte le chiamate di funzione e agli accessi ai tipi, consentendo a Ginseng di trasformare pigramente lo stato al costo di imporre un overhead a tempo costante per l'intera esecuzione del programma. Il compilatore di Ginseng dimostra le proprietà contro-libertà dell'intero programma iniziale e delle patch dinamiche.
Le versioni successive di Ginseng supportano anche una nozione di sicurezza transazionale. Ciò consente agli sviluppatori di annotare una sequenza di chiamate di funzione come un'unità logica, impedendo agli aggiornamenti di violare la semantica del programma in modi che non sono rilevabili né dalla sicurezza dell'attività né dalla sicurezza contro la libertà . Ad esempio, in due versioni di OpenSSH esaminate dagli autori di Ginseng, un importante codice di verifica dell'utente veniva spostato tra due funzioni chiamate in sequenza. Se la prima versione della prima funzione è stata eseguita, si è verificato un aggiornamento e la nuova versione della seconda funzione è stata eseguita, la verifica non verrà mai eseguita. Contrassegnare questa sezione come una transazione garantisce che un aggiornamento non impedirà il verificarsi della verifica.
UpStare
UpStare è un sistema DSU che utilizza un meccanismo di aggiornamento unico, la ricostruzione dello stack . Per aggiornare un programma con UpStare, uno sviluppatore specifica una mappatura tra tutti i possibili stack frame. UpStare è in grado di utilizzare questa mappatura per aggiornare immediatamente il programma in qualsiasi momento, con qualsiasi numero di thread e con qualsiasi funzione presente sullo stack.
PoLUS
Pólus è un sistema binario DSU-riscrittura per C . È in grado di aggiornare i programmi non modificati in qualsiasi momento della loro esecuzione. Per aggiornare le funzioni, riscrive il preludio a una funzione di destinazione per reindirizzare a una nuova funzione, concatenando questi reindirizzamenti su più versioni. Ciò evita il sovraccarico di stato stazionario nelle funzioni che non sono state aggiornate.
Katana
Katana è un sistema di ricerca che fornisce un aggiornamento dinamico limitato (simile a Ksplice e ai suoi fork) per i binari ELF in modalità utente . Il modello di patch Katana opera a livello di oggetti ELF e quindi ha la capacità di essere indipendente dal linguaggio fintanto che l'obiettivo della compilazione è ELF.
Kitsune ed Ekiden
Ekiden e Kitsune sono due varianti di un unico sistema DSU che implementa lo stile dello stato di trasferimento dei DSU per programmi scritti in C . Piuttosto che aggiornare le funzioni all'interno di un singolo programma, Ekiden e Kitsune eseguono aggiornamenti su interi programmi, trasferendo lo stato necessario tra le due esecuzioni. Mentre Ekiden esegue questo avviando un nuovo programma utilizzando l' idioma UNIX di fork-exec , serializzando lo stato del programma di destinazione e trasferendolo, Kitsune utilizza il collegamento dinamico per eseguire il trasferimento di stato "sul posto". Kitsune è derivato dal codice base di Ekiden e può essere considerato una versione successiva di Ekiden.
Ekiden e Kitsune si distinguono anche per il fatto che sono implementati principalmente come librerie a livello di applicazione, piuttosto che come runtime o compilatori specializzati. Pertanto, per utilizzare Ekiden o Kitsune, uno sviluppatore di applicazioni deve contrassegnare manualmente lo stato che deve essere trasferito e selezionare manualmente i punti nel programma in cui può verificarsi un aggiornamento. Per facilitare questo processo, Kitsune include un compilatore specializzato che implementa un linguaggio specifico del dominio per la scrittura dei trasformatori di stato.
Erlang
Erlang supporta l'aggiornamento dinamico del software, anche se viene comunemente chiamato " caricamento del codice a caldo ". Erlang non richiede garanzie di sicurezza sugli aggiornamenti, ma la cultura di Erlang suggerisce che gli sviluppatori scrivano in uno stile difensivo che gestirà con garbo gli errori di tipo generati dall'aggiornamento.
Pymoult
Pymoult è una piattaforma di prototipazione per l'aggiornamento dinamico scritto in Python. Raccoglie molte tecniche da altri sistemi, consentendo la loro combinazione e configurazione. L'obiettivo di questa piattaforma è consentire agli sviluppatori di scegliere le tecniche di aggiornamento che ritengono più appropriate alle loro esigenze. Ad esempio, si può combinare l'aggiornamento pigro dello stato come in Ginseng mentre si cambia l'intero codice dell'applicazione come in Kitsune o Ekiden.
Microsoft Visual C ++
Microsoft utilizza la tecnologia di patching interna per Microsoft Visual C ++ che supporta l'applicazione di patch alle singole funzioni C ++ mantenendo la correttezza funzionale delle patch. Attualmente le applicazioni note sono SQL Server nel database SQL di Azure.