Qu'est-ce qu'un bon moyen de simuler O_NOFOLLOW sur les systèmes sans ce drapeau?
-
04-10-2019 - |
Question
Je voudrais être en toute sécurité capable de open
Simuler avec O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW
et O_CREAT | O_WRONLY | O_APPEND | O_NOFOLLOW
sur les systèmes qui ne prend pas en charge O_NOFOLLOW
. Je peux un peu réaliser ce que je vous demande avec:
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);
mais j'introduire une condition de course et peut-être un problème de sécurité.
Je pensé à créer peut-être un fichier factice avec seul l'utilisateur étant capable d'écrire, un peu comme touch
ing filename
, faire le chèque de lstat
, puis en utilisant chmod
après avoir fini d'écrire (pour corriger les bits de mode de fichier), mais je pourrait être vue sur quelque chose d'important (par exemple si le fichier à filename
existe, est pas un fichier régulier, ou est déjà un lien symbolique).
Que pensez-vous?
La solution
Votre proposition a encore une condition de course:
- Mallory crée le lien qu'il veut vous suivre;
- Vous
open()
le lien avecO_CREAT
; - Mallory remplace le lien avec un fichier régulier;
- Vous faites votre test
lstat()
, qui passe (pas de lien); - Mallory remplace le fichier régulier avec le lien à nouveau.
Vous pouvez résoudre ce problème pour le cas non O_TRUNC
en appelant fstat()
sur votre descripteur de fichier ouvert, ainsi que lstat()
sur le chemin, et veiller à ce que les membres de .st_dev
et .st_ino
sont les mêmes.
Cependant, cela ne fonctionne pas si vous utilisez O_TRUNC
- le temps que vous avez découvert la supercherie, il est trop tard -. Mallory vous a déjà amené à tronquer un de vos fichiers importants
Je crois que la façon traditionnelle d'éliminer le trou sans support O_NOFOLLOW
est:
- Créez un répertoire temporaire avec le mode
700
. Erreur (ou nouvelle tentative) simkdir()
échoue en raison d'annuaire existant; - Créez votre nouveau fichier dans le répertoire temporaire;
- Utilisez
rename()
pour déplacer atomiquement le fichier temporaire au nom de la cible; - Supprimer le répertoire temporaire.