- Chcę dodać dane do pliku w/tmp.
- Jeśli plik nie istnieje, chcę go utworzyć
- Nie obchodzi mnie, że ktoś inny jest właścicielem pliku. Dane nie są tajne.
- Nie chcę, aby ktoś był w stanie ścigać się z wyścigiem, aby zapisać go w innym miejscu lub w innym pliku.
Jaki jest najlepszy sposób na zrobienie tego?Jak powinienem chronić się przed atakami z twardym łączem?
Oto moja myśl:
fd = open("/tmp/some-benchmark-data.txt", O_APPEND | O_CREAT | O_NOFOLLOW | O_WRONLY, 0644);
fstat(fd, &st);
if (st.st_nlink != 1) {
HARD LINK ATTACK!
}
Problem z tym: Ktoś może połączyć plik do jakiegoś pliku krótkotrwały kopalni, tak że /tmp/some-benchmark-data.txt jest taka sama jak/tmp/tmpfileXXXXXX, którego używa inny skrypt (i poprawnie otworzony przy użyciu O_EXCL i tak dalej). Moje dane porównawcze są następnie dołączane do tego pliku/tmp/tmpfileXXXXXX, , podczas gdy nadal jest używane.
Jeśli mój inny skrypt miałby otworzyć swój plik tymczasowy, usuń go, a następnie użyj go; wtedy zawartość tego pliku zostanie uszkodzona przez moje dane porównawcze. Ten inny skrypt musiałby następnie usunąć swój plik między open() i fstat() powyższego kodu.
Więc innymi słowy:
This script Dr.Evil My other script or program
open(fn2, O_EXCL | O_CREAT | O_RDWR)
link(fn1,fn2)
open(fn1, ...)
unlink(fn2)
fstat(..)=>link is 1
write(...)
close(...)
write(...)
seek(0, ...)
read(...) => (maybe) WRONG DATA!
A zatem powyższe rozwiązanie nie działa. Prawdopodobnie istnieją inne ataki.
Jaka jest właściwa droga? Poza tym nie używasz katalogu do zapisu na świecie.
Edit: W celu ochrony przed takim skutkiem, że zło użytkownik tworzy plik z jego/jej własności i uprawnień, lub po prostu źle uprawnieniami (przez trudne łącząc swój plik, a następnie usunięcie oryginału lub hardlinking krótkotrwały plik) Mogę sprawdzić bity prawa własności i pozwolenia po sprawdzeniu nlink.
Nie będzie problemu z bezpieczeństwem, ale zapobiegnie również niespodziankom. Najgorszym przypadkiem jest to, że dostaję część moich własnych danych (z innego pliku) na początku pliku skopiowanego z innego mojego pliku.
Edycja 2: Myślę, że to prawie niemożliwe, aby chronić przed ktoś ciężko łącząc nazwę pliku, który jest otwarty, a następnie usunięty używane. Przykładem tego są pakery EXE, które czasem wykonują nawet usunięty plik poprzez/proc/pid/fd-num. Wyścigi z tym powodują niepowodzenie wykonania spakowanego programu. lsof mógłby prawdopodobnie znaleźć, gdyby ktoś inny miał otwarty i-węzeł, ale wydaje się, że jest to więcej kłopotu niż jest warte.
To tylko atak przed utworzeniem pliku. Jeśli jestem standardowym użytkownikiem, mogę utworzyć łącze do dowolnego pliku (nawet jeśli nie mogę napisać do tego pliku) w dowolnym katalogu, w którym mogę pisać. Oznacza to, że mogę utworzyć plik o nazwie '/ tmp/foo', który jest twardy link '/ etc/passwd'. Teraz, gdy jego program zapisuje do '/ tmp/foo', to naprawdę pisze do'/etc/passwd'. Chce tego uniknąć, upewniając się, że to jego pierwsze ogniwo z stworzonym przez niego kastą. – Gabe
@gabe: right. Dlatego sprawdzam st_nlink. Możesz utworzyć nowy link do plików innych osób, ale nie możesz ich usunąć (zmniejsz liczbę połączeń). – Thomas
Dobra uwaga, Thomas. Jeśli mój komentarz wygląda zabawnie, to dlatego, że odpowiadam na inny komentarz, który został usunięty. – Gabe