Domanda

Sto scrivendo una macchina virtuale in C solo per divertimento. Lame, lo so, ma per fortuna sono in SO quindi speriamo nessuno potrà prendere in giro:)

ho scritto davvero un quick'n'dirty VM che legge le linee della (mia) ASM e fa cose. In questo momento, ho solo 3 istruzioni: add, jmp, end. Tutto va bene e in realtà è piuttosto fresco in grado di linee di alimentazione (facendo qualcosa di simile a write_line(&prog[1], "jmp", regA, regB, 0); e quindi eseguire il programma:

while (machine.code_pointer <= BOUNDS && DONE != true)
{
    run_line(&prog[machine.cp]);
}

Sto utilizzando una tabella di ricerca codice operativo (che non può essere efficiente, ma è elegante) in C e tutto sembra essere ok di lavoro.

La mia domanda è più di una domanda "best practice", ma io credo che ci sia una risposta corretta ad esso. Sto facendo la VM in grado di leggere i file binari (memorizzazione byte in unsigned char[]) ed eseguire il bytecode. La mia domanda è: è il lavoro del VM per assicurarsi che il bytecode è ben formate o è solo il lavoro del compilatore per assicurarsi che il file binario sputa fuori è ben formato ?

Chiedo solo questo, perché ciò che sarebbe accaduto se qualcuno modificare un file binario e roba (parti arbitrari cancellazione di esso, ecc) vite. Chiaramente, il programma sarebbe buggy e probabilmente non funzionale. E 'questo anche il problema del VM? Sono sicuro che la gente molto più intelligente di me ho capito soluzioni a questi problemi, sono solo curioso quello che sono!

È stato utile?

Soluzione

  

E 'il lavoro del VM per assicurarsi che il bytecode è ben formato o è solo il lavoro del compilatore per assicurarsi che il file binario sputa fuori è ben formato?

Si arriva a decidere.

Le migliori pratiche è quello di avere la VM fare un unico controllo prima dell'esecuzione, costo proporzionale alla dimensione del programma, che è sofisticato sufficienti per garantire che nulla traballante può accadere durante l'esecuzione. Poi durante l'esecuzione effettiva del bytecode, si esegue senza controlli. Tuttavia, l'idea di check-prima-running può richiedere un po 'di analisi molto sofisticata, e persino le macchine virtuali più attenti alle prestazioni spesso hanno alcuni controlli in fase di esecuzione. (Esempio: limiti di matrice)

Per un progetto hobby, mi piacerebbe mantenere le cose semplici e hanno il controllo di integrità VM ogni volta che si esegue un'istruzione. L'overhead per la maggior parte delle istruzioni non sarà troppo grande.

Altri suggerimenti

Lo stesso problema si pone in Java, e se ben ricordo, in quel caso la VM non hanno a che fare alcuni controlli per assicurarsi che il bytecode è ben formato. In tale situazione, in realtà è un problema serio a causa del potenziale per problemi di sicurezza: se qualcuno può alterare un file bytecode Java per contenere qualcosa che il compilatore non sarebbe mai uscita (come ad esempio l'accesso a una variabile private da un'altra classe), che potrebbe potenzialmente esporre dati sensibili che si terrà in memoria dell'applicazione, o potrebbe consentire all'applicazione di accedere ad un sito web che non dovrebbe essere consentito di, o qualcosa del genere. macchina virtuale di Java include un bytecode verificatore per assicurarsi che, per quanto possibile, che questo tipo di cose non accadono.

Ora, nel tuo caso, a meno che la vostra lingua in casa decolla e diventa popolare, l'aspetto della sicurezza è qualcosa che non c'è bisogno di preoccuparsi così tanto; dopo tutto, che sta per essere l'hacking i programmi, diverso da te? Eppure, io direi che è una buona idea per assicurarsi che il vostro VM almeno ha una strategia ragionevole per il fallimento, quando il bytecode non è valido. Come minimo, se incontra qualcosa che non capisce e non può processo, si deve rilevare che e fallire con un messaggio di errore, che renderà più facile il debug da parte vostra.

Le macchine virtuali che interpretano bytecode in genere hanno un modo di convalidare il loro contributo; per esempio, Java lancerà una VerifyError se il file di classe è in uno stato incoerente

Tuttavia, sembra che si sta implementando un processore, e dal momento che tendono ad essere di livello inferiore c'è meno modi in cui è possibile gestire per ottenere le cose in uno stato non valido rilevabile - dandogli un codice operativo non definito è un modo ovvio. processori reali segnaleranno che il processo ha tentato di eseguire un'istruzione illegale, e il sistema operativo si occuperà con esso (Linux uccide con SIGILL, per esempio)

Se siete preoccupati per qualcuno che ha modificato il file binario, allora c'è solo una risposta alla tua domanda: la VM deve fare la verifica. E 'l'unico modo in cui si ha la possibilità di rilevare la manomissione. Il compilatore crea solo binario. Non ha modo di rilevare valle manomissioni.

E 'senso avere il compilatore fare come controllo sanità mentale più possibile (dal momento che ha a che fare solo una volta), ma c'è sempre sta per essere questioni che non possono essere rilevati con l'analisi statica, come [tosse] pila troppopieno, errori di intervallo di matrice, e simili.

direi che sia legittimo per il vostro VM per lasciare che il fuoco del processore cattura emulato, a patto che l'attuazione VM in sé non va in crash. Come l'implementor VM, si arriva a impostare le regole. Ma se si vuole società di hardware virtuali praticamente a comprare il chip virtuale, dovrete fare qualcosa di un po 'più indulgente di errori: buone opzioni potrebbe essere quella di sollevare un'eccezione (più difficile da implementare) o resettare il processore (molto più facile). O forse semplicemente definire ogni codice operativo per essere valida, se non che alcuni sono "senza documenti" - fanno qualcosa non specificato, diverso da crash il vostro implementazione. Motivazione: (!). Se l'implementazione VM è di eseguire più istanze del guest contemporaneamente, sarebbe molto male se uno dei clienti sono stati in grado di provocare gli altri a fallire

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top