int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);
... open () ... O_CREAT flag ...
What if this mode is not specified?
In addition to other people's answers, if you want proof against this in the future by getting a Ting compilation error when you forgot to specify the mode flag in cases where it is necessary (for example, O_CREAT or O_TMPFILE, according to man 2 open , man 2 open ) you will have to use the GNU C project and the C ++ compiler (for example, the gcc command) with the arg argument. -D_FORTIFY_SOURCE=1 (or 2 ) and an optimization flag, for example. -O1 or regular -O2 (because _FORTIFY_SOURCE requires compiling with optimization (-O) ).
For example:
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> int main() { 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); }
(save this as file: ac )
$ gcc -D_FORTIFY_SOURCE=2 -O1 ac In file included from /usr/include/fcntl.h:328, from ac:3: In function 'open, inlined from 'main at ac:10:13: /usr/include/bits/fcntl2.h:50:4: error: call to '__open_missing_mode declared with attribute error: open with O_CREAT or O_TMPFILE in second argument needs 3 arguments __open_missing_mode (); ^~~~~~~~~~~~~~~~~~~~~~
So you get: open with O_CREAT or O_TMPFILE in second argument needs 3 arguments
Pedantics should :
Note: -O0 or not -O arg. will not work (i.e. it wonβt tell you that you forgot to add mode because it is like _FORTIFY_SOURCE not _FORTIFY_SOURCE or just ignored):
$ gcc -D_FORTIFY_SOURCE=2 -O0 ac In file included from /usr/include/bits/libc-header-start.h:33, from /usr/include/stdio.h:27, from ac:1: /usr/include/features.h:382:4: warning: #warning _FORTIFY_SOURCE requires compiling with optimization (-O) [-Wcpp] # warning _FORTIFY_SOURCE requires compiling with optimization (-O) ^~~~~~~
Using _FORTIFY_SOURCE will protect you in the same way for other cases , and for open() there is one more case: open can be called either with 2 or 3 arguments, not more , as seen from the file /usr/include/bits/fcntl2.h as:
__errordecl (__open_too_many_args, "open can be called either with 2 or 3 arguments, not more"); __errordecl (__open_missing_mode, "open with O_CREAT or O_TMPFILE in second argument needs 3 arguments"); __fortify_function int open (const char *__path, int __oflag, ...) { if (__va_arg_pack_len () > 1) __open_too_many_args (); if (__builtin_constant_p (__oflag)) { if (__OPEN_NEEDS_MODE (__oflag) && __va_arg_pack_len () < 1) { __open_missing_mode (); return __open_2 (__path, __oflag); } return __open_alias (__path, __oflag, __va_arg_pack ()); } if (__va_arg_pack_len () < 1) return __open_2 (__path, __oflag); return __open_alias (__path, __oflag, __va_arg_pack ()); }
The reason why you need a GNU C compiler (e.g. gcc ) is at least because of the following code from the /usr/include/sys/cdefs.h file:
#if __GNUC_PREREQ (4,3) # define __warndecl(name, msg) \ extern void name (void) __attribute__((__warning__ (msg))) # define __warnattr(msg) __attribute__((__warning__ (msg))) # define __errordecl(name, msg) \ extern void name (void) __attribute__((__error__ (msg))) #else # define __warndecl(name, msg) extern void name (void) # define __warnattr(msg) # define __errordecl(name, msg) extern void name (void) #endif
this suggests that gcc version 4.3 is the minimum required for this to work. (For your information: my current version of gcc (GCC) is 8.3.0)
Therefore, if you try clang version 8.0.0 (tags / RELEASE_800 / final) Target: x86_64-pc-linux-gnu, you will not get a compilation error:
$ clang -D_FORTIFY_SOURCE=2 -O1 ac
(there is no output even with -, the compilation was successful: a.out was created), since this version of clang defines __GNUC__ equal to 4 and __GNUC_MINOR__ equal to 2 in this way, 4.2 is simply not __GNUC_MINOR__ 4.3 necessary for its operation; and coercion, for example. 8.3 will not work:
$ clang -D_FORTIFY_SOURCE=1 -D__GNUC__=8 -D__GNUC_MINOR__=8 -O1 ac In file included from <built-in>:355: <command line>:2:9: warning: '__GNUC__' macro redefined [-Wmacro-redefined] #define __GNUC__ 8 ^ <built-in>:9:9: note: previous definition is here #define __GNUC__ 4 ^ In file included from <built-in>:355: <command line>:3:9: warning: '__GNUC_MINOR__' macro redefined [-Wmacro-redefined] #define __GNUC_MINOR__ 8 ^ <built-in>:7:9: note: previous definition is here #define __GNUC_MINOR__ 2 ^ 2 warnings generated.
The source code above was obtained from the glibc 2.29.9000.r269.g1f50f2ad85-1 package on Arch Linux. i.e.
/usr/include/sys/cdefs.h is owned by glibc 2.29.9000.r269.g1f50f2ad85-1 /usr/include/bits/fcntl2.h is owned by glibc 2.29.9000.r269.g1f50f2ad85-1
PS: without _FORTIFY_SOURCE you can get random modes every time the program starts, as I did :
$ ./go -rx--s--T 1 user user 0 May 17 17:22 /tmp/broken_perms.log $ ./go ---sr-s--- 1 user user 0 May 17 17:23 /tmp/broken_perms.log $ ./go -rws--x--- 1 user user 0 May 17 17:23 /tmp/broken_perms.log $ ./go --wsr-x--T 1 user user 0 May 17 17:23 /tmp/broken_perms.log