Стандартный способ избежать TOCTTOU при операциях с файлами – open
файл один раз, а затем выполнить все необходимые действия с помощью файлового дескриптора, а не имени файла.
Однако как для переименования, так и для удаления связи с файлом требуется его путь (поскольку им нужно знать, какую ссылку переименовывать или удалять), поэтому здесь вы не можете использовать этот подход. Альтернативой может быть копирование содержимого файла в другое место, а затем его усечение до нуля байтов, хотя ваш сценарий с файлами журналов, вероятно, требует, чтобы операция была атомарной, что может быть трудновыполнимым. Другой подход заключается в требовании жесткого контроля доступа к каталогу: если злоумышленник не может писать в каталог, он не может играть в игры TOCTTOU с вашим процессом. Вы можете использовать unlinkat
и renameat
, чтобы ограничить свои пути файловым дескриптором определенного каталога, чтобы вам не нужно было беспокоиться об изменении самого каталога.
Что-то вроде этого непроверенного кода может выполнить эту работу, предполагая платформу, подобную POSIX:
dirfd = open(LOGDIR, O_DIRECTORY);
// check for failure
res = fstatat(dirfd, LOGFILE, statbuf, AT_SYMLINK_NOFOLLOW);
if ((0 == res) && (S_ISREG(statbuf) && (data.st_size > MAX_LOGSIZE)) {
unlinkat(dirfd, PREV_LOGFILE, 0);
renameat(dirfd, LOGFILE, dirfd, PREV_LOGFILE);
}
close(dirfd);
person
user3553031
schedule
27.06.2019
std::ofstream
— в любом случае вам нужно будет защитить все это с помощью объектаstd::mutex
. В любом случае вам это нужно, если в файл журнала будет записываться более одного потока... - person Aconcagua   schedule 27.06.2019