2012-02-15 17 views
6

Ho un processo con autorizzazioni 4750. Esistono due utenti nel mio sistema Linux. L'utente root e l'utente appz. Il processo eredita le autorizzazioni di un gestore di processi eseguito come utente "appz".modo corretto di eseguire i programmi setuid in C

Ho due routine di base:

void do_root (void) 
{ 
     int status; 
     status = seteuid (euid); 
     if (status < 0) { 
     exit (status); 
     }  
} 

/* undo root permissions */ 
void undo_root (void) 
{ 
int status; 
     status = seteuid (ruid); 
     if (status < 0) { 
       exit (status); 
     } 
     status = setuid(ruid); 
     if (status < 0) { 
       exit (status); 
     } 
} 

Il mio flusso è la seguente:

int main() { 
undo_root(); 
do some stuff; 
do_root(); 
bind(port 80); //needs root perm 
undo_root(); 
while(1) { 

    accept commads() 
    if (commands needs root user access) 
    { 
     do_root(); 
     execute(); 
     undo_root(); 

    } 

} 

Come si può vedere che voglio per eseguire alcuni comandi come root. Sto provando a rilasciare temporaneamente le autorizzazioni e se le attività richiedono l'accesso come root, eseguo il comando tra una chiamata do_root e undo_root.

Tuttavia, sembra che il mio programma non funzioni.

Qual è il modo canonico per farlo?

+0

Invece di uscire solo quando seteuid non riesce, chiamare perror() e il tuo programma ti dirà perché non funziona. –

+4

Dopo aver eliminato i permessi di root, non puoi riaverli !! – Petesh

+0

Tecnicamente, è il file che contiene il programma che ha il permesso 4750, non il processo. Non dirai direttamente che i permessi sono 'root: group: 4750' - è un'inferenza sicura? –

risposta

5

alla vecchia scuola è quello sia do_root e undo_root utilizzare setreuid() per scambiare ruid e euid:

setreuid(geteuid(), getuid()); 

Questo è perfettamente accettabile se il programma è abbastanza piccolo per fare un controllo di sicurezza completo .

Il modo new-school è molto più complesso e coinvolge fork() ingannare un bambino che accetta direttive per cosa fare come root e quindi fare setuid (getuid()) per rilasciare root in modo permanente nel genitore. il bambino è responsabile della convalida di tutte le direttive che riceve. Per un programma abbastanza grande, questo elimina la quantità di codice che deve essere controllata dalla sicurezza e consente all'utente di gestire il processo con controllo del lavoro o ucciderlo, ecc.

+0

cosa intendi? Basta copiare e incollare il codice in entrambe le funzioni? – cateof

+0

Sì. __________ – Joshua

2

La pagina di setuid uomo dice il seguente:

... un programma di set-user-ID root che desiderano abbandonare temporaneamente radice privilegi, assumere l'identità di un utente non-root, e poi riguadagnare privilegi di root in seguito non può usare setuid()

Il che significa che non è possibile utilizzare setuid(). Devi usare seteuid() e, possibilmente, setreuid(). Vedi Setuid Program Example per maggiori dettagli.

+0

Il mio programma si basa esattamente su questa pagina GNU. Invece di do_setuid, inizialmente ho fatto do_root. – cateof

+0

@cateof: Vedo che usi la funzione 'setuid' nel codice che hai postato. Questo è un biglietto di sola andata. –

5

C'è un documento "Setuid Demystified" di Hao Chen, David Wagner e Drew Dean. È stato presentato a USENIX 2002. Descrive come lo setuid() e le transizioni funzionano in modo molto dettagliato (corretto dal 2002). Vale la pena leggerlo (più volte - devo aspettare un anno o due per rileggerlo).

Fondamentalmente, come Petesh osservato in un commento, quando un processo con EUID 0 fa setuid(nuid) con nuid != 0, non c'è modo di nuovo al root (EUID 0) privilegi. E, in effetti, è vitale che sia così. Altrimenti, quando effettui il login, il processo root che ti accede non ti può limitare ai tuoi stessi privilegi: potresti tornare a root. L'UID salvato complica le cose, ma non credo che influenzi la trappola a senso unico di EUID 0 facendo setuid().