2009-02-25 13 views
7

La definizione del UNIX open() funzione quando utilizzato con la bandiera O_CREAT è che richiede un terzo argomento di nome modalità al fine di impostare i privilegi dei file.Unix O_CREAT bandiera senza modalità specificata

Cosa succede se la modalità non è specificata?

int file; 
static const char filename[] = "test.test"; 

if ((file = open(filename, O_RDWR | O_CREAT | O_TRUNC)) == 1) 
{ 
    perror("Error opening file."); 
    exit(EXIT_FAILURE); 
} 

close(file); 

Cosa succede con il file creato utilizzando tali flag? Sul mio sistema ottengo:

-r--r-s--- 1 hyperboreean hyperboreean  0 2009-02-25 01:40 test.test 

Una teoria è che la funzione aperta appare sullo stack e controlli per il parametro mode e finisce con un numero intero casuale che trova.

Che cosa dice lo standard?

+0

Questo è il motivo per cui i prototipi di funzione sono stati inventati. – womble

+1

Il tuo commento non ha senso. – SoapBox

+0

Non lo è, anzi. E nemmeno il downvote. – cdonner

risposta

1

iperboreo, il tuo sospetto potrebbe non essere così lontano dal marchio. Speravo di trovare la risposta in Kernighan Ritchie. Sfortunatamente, non l'ho fatto. Penso che il parametro permessi sia richiesto con il flag O_CREAT, e se non lo fornisci, open() estrae un valore casuale dallo stack, che ovviamente passa inosservato in C.

Modifica: per " casuale "Intendo non prevedibile. Probabilmente sta recuperando parte dell'indirizzo di ritorno, che si trova in cima ai parametri sullo stack.

2

Buona domanda. Il valore mode verrà modificato dal umask del processo. Pertanto, se non si invia esplicitamente un numero mode ain un'operazione O_CREAT e se ciò comporta l'utilizzo di bit casuali per la modalità, tali bit casuali verranno modificati dallo umask.

Vorrei poter essere più preciso e preciso, ma sono d'accordo con cdonner che vengono utilizzati valori "casuali", insieme allo umask.

Edit: Una cosa che si potrebbe provare è quella di utilizzare dtruss o capriata o qualche altra struttura per tracciare le chiamate di sistema, e guardare il valore di mode in fase di esecuzione per vedere se si utilizza qualcosa di sensato, o se è solo casuale bit modificati dal umask, ad esempio.

+0

Nel mio test usando ptrace() , È solo qualcosa apparentemente casuale, anche se nel mio caso è sempre un 11 bit (12 bit con il numero iniziale 0 per indicare ottale) che inizia con 2777. –

+0

Il valore 02777 è interessante perché implica mondo scrivibile con il set-gid po. Bene, solo un altro motivo per cui la creazione di un file senza la modalità è pericolosa. –

8

Lo standard POSIX (IEEE 1003.1: 2008) prototipi open() come:

int open(const char *path, int oflag, ...); 

La sezione che descrive il comportamento di O_CREAT non dice che cosa accadrà se si omette la necessaria terzo argomento, il che significa che il comportamento è indefinito - tutto è possibile.

In pratica, l'uso di una parte dello stack che doveva essere stack frame o indirizzo di ritorno o qualcosa di simile è abbastanza probabile - fino a un'approssimazione ragionevole, che può essere considerato un numero intero casuale.

Lo standard POSIX 2008 ha alcune nuove interessanti (e utili) bandiere per open(), tra cui:

  • O_FDCLOEXEC per specificare close-on-exec in aperto.
  • O_DIRECTORY per specificare che il file deve essere una directory.
  • O_NOFOLLOW per specificare di non inseguire i collegamenti simbolici.
0

Per la cronaca, sulla maggior parte dei sistemi libc, probabilmente sarete sulle mani della va_arg, which states in it's man page:

If there is no next argument, or if type is not compatible with the 
    type of the actual next argument (as promoted according to the 
    default argument promotions), **random errors will occur**. 
int 
__libc_open64 (const char *file, int oflag, ...) 
{ 
    int mode = 0; 

    if (oflag & O_CREAT) 
    { 
     va_list arg; 
     va_start (arg, oflag); 
     mode = va_arg (arg, int); 
     va_end (arg); 
    } 

    if (SINGLE_THREAD_P) 
     return INLINE_SYSCALL (open, 3, file, oflag | O_LARGEFILE, mode); 

    int oldtype = LIBC_CANCEL_ASYNC(); 

    int result = INLINE_SYSCALL (open, 3, file, oflag | O_LARGEFILE, mode); 

    LIBC_CANCEL_RESET (oldtype); 

    return result; 
} 
Problemi correlati