int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
... open () ... O_CREAT flag ...
Что если этот mode не указан?
В дополнение к ответам других людей, если вы хотите противостоять этому будущему, наберите get ting a ошибка компилятора при вы забыли указать флаг mode в тех случаях, когда это необходимо (т. е. O_CREAT или O_TMPFILE , согласно man 2 open
), у вас будет использовать GNU project C и C ++ (например, команду gcc
) с аргументом arg. -D_FORTIFY_SOURCE=1
(или 2
) и флаг оптимизации, например. -O1
или обычный -O2
(потому что _FORTIFY_SOURCE requires compiling with optimization (-O)
).
Например:
#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);
}
(сохранить как файл: a.c
)
$ gcc -D_FORTIFY_SOURCE=2 -O1 a.c
In file included from /usr/include/fcntl.h:328,
from a.c:3:
In function ‘open’,
inlined from ‘main’ at a.c: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 ();
^~~~~~~~~~~~~~~~~~~~~~
Итак, вы получите: open with O_CREAT or O_TMPFILE in second argument needs 3 arguments
Педантику следует :
Обратите внимание: -O0
или нет -O
arg. не будет работать (т.е. он не скажет вам, что вы забыли добавить mode
, потому что это как если бы _FORTIFY_SOURCE
не было указано или просто проигнорировано):
$ gcc -D_FORTIFY_SOURCE=2 -O0 a.c
In file included from /usr/include/bits/libc-header-start.h:33,
from /usr/include/stdio.h:27,
from a.c: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)
^~~~~~~
Использование _FORTIFY_SOURCE
защитит вас таким же образом и для других случаев тоже, а для open()
есть еще один случай: open can be called either with 2 or 3 arguments, not more
, видимый в файле /usr/include/bits/fcntl2.h
как:
__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 ());
}
Причина, по которой необходим GNU C Compiler (например, gcc
), по крайней мере, из-за следующего кода из файла /usr/include/sys/cdefs.h
:
#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
, который говорит, что gcc версии 4.3 - это минимум, необходимый для этой работы.
(К вашему сведению: моя текущая версия gcc (GCC) 8.3.0)
Так что если вы попробуете clang
версии 8.0.0 (tags / RELEASE_800 / final) Цель: x86_64-pc-linux-gnu , вы не получите ошибку компиляции:
$ clang -D_FORTIFY_SOURCE=2 -O1 a.c
(здесь нет выходных данных даже с -, компиляция прошла успешно: a.out создан)
потому что эта версия clang определяет __GNUC__
как 4
и __GNUC_MINOR__
как 2
, поэтому 4.2 просто стесняется 4.3, необходимой для его работы; и принуждение, например. 8.3 не будет работать:
$ clang -D_FORTIFY_SOURCE=1 -D__GNUC__=8 -D__GNUC_MINOR__=8 -O1 a.c
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.
Приведенные выше исходные коды получены из пакета glibc
2.29.9000.r269.g1f50f2ad85-1 в Arch Linux. то есть.
/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: без _FORTIFY_SOURCE
, вы можете получить случайные режимы при каждом запуске программы, как Я сделал :
$ ./go
-r-x--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