Che cosa è un buon modo per simulare O_NOFOLLOW su sistemi senza questa opzione?
-
04-10-2019 - |
Domanda
Mi piacerebbe essere tranquillamente in grado di simulare con open
O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW
e O_CREAT | O_WRONLY | O_APPEND | O_NOFOLLOW
su sistemi che non O_NOFOLLOW
supporto. Posso in qualche modo ottenere quello che sto chiedendo con:
struct stat lst;
if (lstat(filename, &lst) != -1 && S_ISLNK(lst.st_mode)) {
errno = ELOOP;
return -1;
}
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, mode);
ma poi ho introdurre una condizione di competizione e, eventualmente, un problema di sicurezza.
ho pensato forse la creazione di un file fittizio con solo l'utente di essere in grado di scrivere, un po 'come touch
ing filename
, facendo il controllo lstat
, e quindi utilizzando chmod
dopo finisco di scrivere (per correggere i bit del modo file), ma io potrebbe essere che si affaccia qualcosa di importante (ad esempio se il file in filename
esiste, non è un file normale, o è già un link simbolico).
Cosa ne pensi?
Soluzione
La tua proposta ha ancora una condizione di competizione:
- Mallory crea il collegamento che vuole a seguire;
-
open()
il legame conO_CREAT
; - Mallory sostituisce il collegamento con un file regolare;
- Tu fai il test
lstat()
, che passa (non un collegamento); - Mallory sostituisce nuovamente il file regolare con il collegamento.
È possibile risolvere questo problema per il caso non O_TRUNC
chiamando fstat()
sul descrittore di file aperto come pure lstat()
sulla strada, e di garantire che i membri .st_dev
e .st_ino
sono gli stessi.
Tuttavia, questo non funziona se si sta utilizzando O_TRUNC
- per il momento che hai scoperto l'inganno, è troppo tardi -. Mallory ti ha già indotto di troncare uno dei tuoi file importanti
Credo che il modo tradizionale di eliminare la buca senza supporto O_NOFOLLOW
è:
- Creare una directory temporanea con modalità
700
. Errore (o tentativi) semkdir()
fallisce a causa di directory esistente; - Crea il tuo nuovo file all'interno della directory temporanea;
- Usa
rename()
per spostare atomicamente il file temporaneo per il nome di destinazione; - Rimuovere la directory temporanea.