Какой хороший способ симулировать O_NOFOLLOW на системах без этого флага?
-
04-10-2019 - |
Вопрос
Я хотел бы благополучно сможет имитировать open
с участием O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW
а также O_CREAT | O_WRONLY | O_APPEND | O_NOFOLLOW
на системах, которые не поддерживают O_NOFOLLOW
. Отказ Я могу несколько добиться того, что я прошу с:
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);
Но тогда я вводим состояние гонки и, возможно, проблему безопасности.
Я думал о возможном создании фиксированного файла только с возможностью записи пользователя, вроде как touch
вспомогательный filename
, делать lstat
Проверьте, а затем используете chmod
После того, как я закончу письмо (чтобы исправить биты в режиме файла), но я мог бы с видом на что-то можно снять (например, если файл в filename
Существует, не является обычным файлом или уже является символической ссылкой).
Как вы думаете?
Решение
Ваше предложение по-прежнему имеет состояние гонки:
- Мэллори создает ссылку, которую он хочет, чтобы вы следили;
- Ты
open()
Ссылка сO_CREAT
; - Mallory заменяет ссылку с обычным файлом;
- Вы делаете свой
lstat()
тест, который проходит (не ссылка); - Mallory снова заменяет обычный файл со ссылкой.
Вы можете исправить это дляO_TRUNC
дело, позвонив fstat()
на вашем открытом файловом дескрипторе, а также lstat()
на пути и обеспечение того, чтобы .st_dev
а также .st_ino
Члены одинаковы.
Тем не менее, это не работает, если вы используете O_TRUNC
- К тому времени, как вы обнаружили обман, слишком поздно - Mallory уже побудил вас обрезать одну из ваших важных файлов.
Я считаю, что традиционный способ устранить дыру без O_NOFOLLOW
Поддержка:
- Создайте временный каталог с режимом
700
. Отказ Ошибка (или повторить), еслиmkdir()
не удается из-за существующего каталога; - Создайте свой новый файл во временном каталоге;
- Использовать
rename()
аторично переместить временный файл в целевое имя; - Удалить временный каталог.