Як vim краде файли, що належать кореням?


39

Свідком наступного:

sh-3.2$ mkdir testcase
sh-3.2$ cd testcase
sh-3.2$ sudo touch temp
sh-3.2$ ls -al
total 0
drwxr-xr-x   3 glen  staff  102 19 Dec 12:38 .
drwxr-xr-x  12 glen  staff  408 19 Dec 12:38 ..
-rw-r--r--   1 root  staff    0 19 Dec 12:38 temp

sh-3.2$ echo nope > temp
sh: temp: Permission denied

sh-3.2$ vim temp
# inside vim
itheivery
# press [ESC]
:wq!
# vim exits

sh-3.2$ ls -al
total 8
drwxr-xr-x   3 glen  staff  102 19 Dec 12:38 .
drwxr-xr-x  12 glen  staff  408 19 Dec 12:38 ..
-rw-r--r--   1 glen  staff    7 19 Dec 12:38 temp

Якось vim взяв цей root-файл і змінив його у файл, що належить користувачеві!

Це, здається, працює лише в тому випадку, якщо користувачеві належить каталог - але все ще здається, що це не може бути можливим. Хтось може пояснити, як це робиться?

Відповіді:


51

Ви, glenвласник каталогу (див. .Файл у вашому списку). Каталог - це лише список файлів, і ви маєте дозвіл на зміну цього списку (наприклад, додайте файли, видаліть файли, змініть право власності, щоб зробити його знову вашим тощо). Можливо, ви не зможете безпосередньо змінити вміст файлу, але ви можете прочитати та від’єднати (видалити) файл у цілому та додати нові файли згодом. 1 Тільки спостерігаючи до і після, це може виглядати так, що файл був змінений.

Vim використовує файли swap і переміщує файли під водою, так що це пояснює, чому, здається, записується в той самий файл, що і у вашій оболонці, але це не те саме. 2

Отже, що робить Вім, зводиться до цього:

cat temp > .temp.swp          # copy file by contents into a new glen-owned file
echo nope >> .temp.swp        # or other command to alter the new file
rm temp && mv .temp.swp temp  # move temporary swap file back

1 Це важлива різниця в обробці дозволів на файли між Windows та Unices. У Windows зазвичай не вдається видалити файли, на які ви не маєте дозволу на запис.

2 оновлення: як зазначено в коментарях, Vim насправді не робить це так, щоб змінити право власності, оскільки номер inode у tempфайлі не змінюється (порівняння ls -liдо і після). Використовуючи straceми можемо бачити, що саме vimробить. Цікава частина тут:

open("temp", O_WRONLY|O_CREAT|O_TRUNC, 0664) = -1 EACCES (Permission denied)
unlink("temp")                               = 0
open("temp", O_WRONLY|O_CREAT|O_TRUNC, 0664) = 4
write(4, "more text bla\n", 14)              = 14
close(4)                                     = 0
chmod("temp", 0664)                          = 0

Це показує, що він лише від’єднує посилання , але не закриває дескриптор файлу temp. Він швидше переписує весь вміст ( more text bla\nв моєму випадку). Я думаю, це пояснює, чому номер inode не змінюється.


3
FWIW ви можете переконатися, що це відбувається, запустивши ls -ilдо і після ... якщо tempномер inode змінився, ви знаєте, що це інший файл з тим же ім'ям.
Марно

3
Можна додати, що rm фактично не видаляє файл, а просто видаляє посилання на файл, а файл не видаляється до того, як кількість посилань зменшиться до 0. rm просто видаляє запис у файл у каталозі. Якщо у корінця є інше посилання (жорстке посилання) на файл в іншому каталозі, користувач не може видалити файл.
gerrit

1
@ Безрезультатно, я намагався, і номер не змінювався, хоча змінювались власник та мітка часу!
amyassin

1
@amyassin Ви маєте рацію! Я оновив свою відповідь страйковим уривком, що пояснює її.
gertvdijk

1
На відміну від вашої замітки про дозволи Windows та Unix, якщо ви хочете, як Windows поведінка в Unix, ви можете створити каталог, що належить root (або іншого користувача, який повинен мати універсальні дозволи на видалення / перейменування / тощо) і встановити липкий біт у каталозі. Тоді користувачі зможуть видаляти лише власні файли.
Меттью Крамлі

16

перед:

-rw-r--r-- 1 root staff 0 19 Dec 12:38 temp

після:

-rw-r--r-- 1 glen staff 7 19 Dec 12:38 temp

Vim не прориває бар'єр дозволу. Просто уважно подивіться на інформацію про файл, перелічену тоді, ви зможете дізнатися, що vim фактично видалив оригінальний файл (тому що у вас є дозвіл на видалення файлу, хоча ви не можете змінити його вміст), а потім створив новий власний файл ( побачити, що власник більше не "root").

І під час редагування вихідного файлу vim він попереджає про те, що ви змінюєте файл лише для читання. Отже, коли ви вводите команду :wq!(змушуйте операцію), що тільки vim може зробити, це видалити існуючий файл і створити новий файл, який має однакове ім'я.

Сподіваюся, що це допомагає.


1

Скористайтеся -iопцією, lsщоб побачити номер inode, який є унікальним ідентифікатором (у файловій системі) файлу чи іншого об’єкта.

Ви побачите, що файл було замінено на інший об’єкт: число inode, ймовірно, зміниться.

Бачити один і той же номер вводу не є доказом нічого: номер inode може бути перероблений. Якщо ми видалимо останнє посилання на файл, а потім створимо новий файл, ми можемо отримати одне з тим же номером inode. Але цього не може статися, якщо старий файл буде видалено після створення нового. Напр mv file file.tmp; touch file; rm file.tmp. Я підозрюю, що vim насправді робить щось подібне до цього echo new_content > tmpfile; mv tmpfile file. mvОперація переведе до renameсистемного виклику, тому присвоєння номерів індексних дескрипторів залежить від того, як файлової системи реалізує перейменування який від'єднує пункт призначення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.