2012-05-09 15 views
8

So che le funzioni copy_to_user/copy_from_user, get_user/put_user sono a questo scopo.Come accedere alla memoria dello spazio utente dal kernel Linux?

La mia domanda è che, dato un indirizzo/puntatore dello spazio utente, come posso accedere ai dati indicati dall'indirizzo dal kernel in generale?

Posso immaginare che prima devo assicurarmi che la pagina contenente debba essere nella memoria fisica (invece che nel disco).

Qual è il prossimo passo? Posso usare *p, dove p è il puntatore che punta ad alcuni dati dello spazio utente, direttamente per fare riferimento ai dati?

Oppure devo prima richiamare kmap per mappare il frame di pagina fisico contenente lo spazio di indirizzo virtuale del kernel? Perché?

risposta

4

Il puntatore da solo non è sufficiente! Hai bisogno di sapere a quale processo quel puntatore "appartiene".

Quando il processo viene annullato, il puntatore punta nello spazio indirizzo di un altro processo. L'indirizzo potrebbe non essere più mappato, yadda yadda,

Se tale processo sarà il processo corrente quando si accede ai dati, è necessario utilizzare le funzioni copy_to_user/copy_from_user.

Se il processo può essere programmato, è possibile provare a mlock() la pagina in RAM e scoprire qual è l'indirizzo di ram fisico della pagina. Ogni volta che si desidera accedervi, si mappa quella pagina fisica in un indirizzo virtuale del kernel.

NOTA:

  • Un processo maligno può munlock() la pagina e indurti l'accesso a una pagina di RAM sbagliata.
  • Non sono sicuro che la semantica di mlock() richieda che la pagina della RAM di sottolineatura NON DEVE cambiare.
  • il kernel dovrebbe essere in grado di bloccare una pagina nella RAM, non ho familiarità con il sottosistema mm.
3

L'applicazione di spazio utente diversa ha una tabella di pagine diversa. 1) è necessario ottenere il pid del programma spaziale dell'utente. 2) addri di ricerca nella tabella della pagina del pid.

Di seguito è riportato un codice di esempio per tradurre l'indirizzo virtuale dello spazio utente in indirizzo fisico. Funziona con la piattaforma x86.

taskpid = find_get_pid(curpid); 
task = pid_task(taskpid, PIDTYPE_PID); 
mm = get_task_mm(task); 
down_read(&mm->mmap_sem); 

start_vaddr = vaddr; 
end_vaddr = 0xC0000000; 

while(start_vaddr < end_vaddr){ 
    u32 end; 

    end = ((start_vaddr + PMD_SIZE) & PMD_MASK); 

    if(end < start_vaddr || end > end_vaddr) 
     end = end_vaddr; 

    ret = walk_pgd(start_vaddr, end, mm); 
    if(ret != 0){ 
     printk("ret: %08x \n", ret); 
     break; 
    } 

    start_vaddr = end; 

} 

up_read(&mm->mmap_sem); 

paddr = ret; 
kaddr = __va(paddr); 
mmput(mm); 
+0

Buon punto e la logica del codice è bella. Ma immagino ci sia una tabella hash o una struttura dati simile che, dato un indirizzo virtuale, ti aiuti a localizzare velocemente la pagina fisica. C'è un difetto: kaddr = __va (paddr); Questa linea funziona solo quando il paddr risiede nella memoria insufficiente, giusto? – Infinite

+0

paddr significa indirizzo fisico, quindi, è sempre esistito in memoria. kaddr significa indirizzo del kernel. In Linux il kernel define è '#define __va (x) ((void *) ((unsigned long) (x) + PAGE_OFFSET))'. La mappatura della memoria di indirizzo del kernel non è complessa, solo un PAGE_OFFSET. (Dovrebbe essere 0xC0000000 in modalità x86). C'è un altro modo per ottenere l'indirizzo. L'applicazione userspace può accedere all'indirizzo del kernel con/proc//pagemap per ottenere informazioni sulla pagina. Se è possibile ottenere PFN, può anche ottenere l'indirizzo del kernel. – richliu

0

Avrai bisogno di follow un indirizzo per ottenere un corrispondente page struct (vedi follow_page per l'esempio). Successivamente, con la struttura page dovrai mapparla allo spazio indirizzo del kernel tramite kmap o kmap_atomic.

3

Potrebbe risultare utile.

Ripetiamo che l'argomento buff per i metodi di lettura e scrittura è un puntatore dello spazio utente. Pertanto, non può essere sottoposto a dereferenziamento diretto tramite il codice del kernel .Ci sono alcune ragioni per questo restrizione:

  • A seconda di quale architettura il driver è in esecuzione, e di come il kernel è stato configurato, il puntatore spazio utente potrebbe non essere valida fino ad esaurimento esecuzione in modalità kernel tutti. Potrebbe non esserci alcuna mappatura per quell'indirizzo o potrebbe puntare ad altri dati casuali.

  • Anche se il puntatore non significare la stessa cosa nello spazio del kernel, memoria utente-spazio è paging, e la memoria in questione potrebbe non essere residenti nella RAM quando la chiamata di sistema è fatta. Tentando di fare riferimento a , la memoria dello spazio utente direttamente potrebbe generare un errore di pagina, che è qualcosa che il codice del kernel non è autorizzato a fare. Il risultato sarebbe un "oops", che comporterebbe la morte del processo che ha reso la chiamata di sistema.

  • Il puntatore in questione è stato fornito da un programma utente, che potrebbe essere bacato o dannoso. Se il tuo autista cancella ciecamente un puntatore fornito dall'utente, fornisce una porta aperta che consente a un programma dello spazio utente di accedere o sovrascrivere la memoria ovunque nel sistema . Se non si desidera essere responsabili della compromissione della sicurezza dello dei sistemi degli utenti, non è mai possibile annullare direttamente un puntatore dello spazio utente .

Fonte: http://www.makelinux.net/ldd3/chp-3-sect-7

Detto questo, io stesso sono curioso di sapere che cosa succede se l'indirizzo user-space è davvero valida, e nessuna delle condizioni di cui sopra si applicano ...

Problemi correlati