Чому файл / dev / null - файл? Чому його функція не реалізована як проста програма?


114

Я намагаюся зрозуміти поняття спеціальних файлів в Linux. Однак, маючи спеціальний файл у, /devздається, нерозумно, коли його функцію можна було реалізовувати за допомогою декількох рядків у С, наскільки мені відомо.

Крім того, ви можете використовувати його майже однаково, тобто підключення, nullа не перенаправлення в /dev/null. Чи є конкретна причина того, що він є файлом? Чи не робить це файлом чимало інших проблем, як-от занадто багато програм, що мають доступ до одного файлу?


20
Між іншим, значна частина цих витрат також cat foo | barє значно гіршою (за масштабами), ніж bar <foo. catце тривіальна програма, але навіть тривіальна програма створює витрати (деякі з них характерні для семантики FIFO - оскільки програми не можуть бути seek()всередині FIFO, наприклад, програма, яка може бути ефективно реалізована за допомогою пошуку, може зробити набагато дорожчі операції коли йому надано конвеєр; з таким символьним пристроєм, як /dev/nullвін може підробляти ці операції, або з реальним файлом він може реалізовувати їх, але FIFO не допускає будь-якого обстеження в контексті).
Чарльз Даффі

13
grep blablubb file.txt 2>/dev/null && dosomethingне вдалося працювати з null програмою чи функцією.
rexkogitans

16
Можливо, вам стане зрозумілим (або принаймні розширює розум), щоб прочитати про операційну систему Plan 9, щоб побачити, куди рухається бачення "все є файлом" - стає легше побачити силу наявності ресурсів у вигляді файлу шляхи, коли ви бачите систему, яка повністю охоплює концепцію (а не переважно / частково, як це роблять сучасні Linux / Unix).
mtraceur

25
Крім того, що ніхто не вказує, що драйвер пристрою, що працює в просторі ядра, - це програма з "жменю рядків C" , жодна з відповідей поки що насправді не стосується припущення про "занадто багато програм, що мають доступ до одного файлу" у питанні.
JdeBP

12
Re «її функція може бути реалізована з допомогою кількох рядків у C»: Ви не повірите, але це буде реалізовано на кількох рядків у C! Наприклад, тіло readфункції для /dev/nullскладається з "return 0" (це означає, що він нічого не робить і, я думаю, призводить до отримання EOF): (З статичного github.com/torvalds/linux/blob/master/ драйвери / char / mem.c ) ssize_t read_null(struct file *file, char __user *buf, size_t count, loff_t *ppos) { return 0; }(О, я просто бачу, що @JdeBP вже сказав про це. У будь-якому випадку, ось ілюстрація :-).
Пітер А. Шнайдер

Відповіді:


153

На додаток до переваг продуктивності використання пристрою, що спеціалізується на символах, головна перевага - модульність . / dev / null може використовуватися майже в будь-якому контексті, де очікується файл, а не лише в оболонкових конвеєрах. Розглянемо програми, які приймають файли як параметри командного рядка.

# We don't care about log output.
$ frobify --log-file=/dev/null

# We are not interested in the compiled binary, just seeing if there are errors.
$ gcc foo.c -o /dev/null  || echo "foo.c does not compile!".

# Easy way to force an empty list of exceptions.
$ start_firewall --exception_list=/dev/null

Все це випадки, коли використання програми як джерела або раковини було б надзвичайно громіздким. Навіть у випадку з конвеєрним каналом оболонки stdout та stderr можуть бути перенаправлені до файлів самостійно, що важко зробити з виконуваними файлами як потоками:

# Suppress errors, but print output.
$ grep foo * 2>/dev/null

14
Також ви не використовуєте /dev/nullлише команди команд оболонки. Ви можете використовувати його в інших параметрах, що постачаються до програмного забезпечення ---, наприклад, у файлах конфігурації. --- Для програмного забезпечення це дуже зручно. Тут не потрібно змінювати /dev/nullі звичайний файл.
пабук

Я не впевнений, що розумію частину про окремі переадресації, щоб виконувати виконання файлів складно. У C, ви просто зробити pipe, forkі , execveяк і будь-який інший технологічний трубопровід, тільки зі змінами в dup2викликах , які встановлюють з'єднання, НЕ так? Це правда, що більшість оболонок не пропонують найкрасивіших способів зробити це, але, мабуть, якби у нас не було стільки шаблону пристрою як файл, а більшість речей /devі /procвважалися виконуваними, оболонки були б розроблені способами зробити це так просто, як ми перенаправляємо зараз.
aschepler

6
@aschepler Це те, що не перенаправити на потоплення виконуваних файлів складно. Це те, що написання програм, які можуть записувати / читати з обох файлів та нульової раковини, було б складніше, якщо нульова раковина не була файлом. Якщо ви не говорите про світ, де замість того, щоб все було файлом, усе є виконуваним? Це була б зовсім інша модель, ніж у вас в * nix OS.
Кубік

1
@aschepler Ви забули wait4! Ви маєте рацію, безумовно, можна передавати stdout та stderr в різні програми за допомогою POSIX apis, і можливо можливо винайти розумний синтаксис оболонки для перенаправлення stdout та stderr до різних команд. Однак я не знаю про будь-яку подібну оболонку зараз, і більш суть полягає в тому, що / dev / null чітко вписується в існуючий інструментарій (який значною мірою працює з файлами), а / bin / null не буде. Ми також могли б уявити API IO, який дозволяє GCC настільки просто (надійно!) Виводити програму як файл, але це не така ситуація, в якій ми знаходимося.
ioctl,

2
@ioctl щодо снарядів; і zsh, і bash принаймні дозволять вам робити такі речі, як grep localhost /dev/ /etc/hosts 2> >(sed 's/^/STDERR:/' > errfile ) > >(sed 's/^/STDOUT:/' > outfile)результат, обробляється окремо errfileіoutfile
Matija Nalis

62

Чесно кажучи, це не звичайний файл сам по собі; це персонаж спеціального пристрою :

$ file /dev/null
/dev/null: character special (3/2)

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


24
cat file | nullмав би багато накладних витрат, спочатку під час налаштування труби, нерестування процесу, виконання "null" у новому процесі тощо. Також nullсам би використовував зовсім небагато процесора в циклі читання байтів у буфер, який пізніше щойно відкинуто ... Реалізація /dev/nullв ядрі просто ефективніша. Крім того, що робити, якщо ви хочете подати /dev/nullяк аргумент, а не перенаправлення? (Ви можете використовувати <(...)в баші, але це навіть набагато важче!)
filbranden

4
Якщо вам довелося передати програму з назвою nullЗамість використання перенаправлення на /dev/null, чи буде простий, зрозумілий спосіб сказати оболонці запускати програму, надсилаючи лише її stderr до нуля?
Марк Плотнік

5
Це дійсно дорога установка для надземної демонстрації. Я б запропонував використовувати /dev/zeroзамість цього.
chrylis -на страйк-

20
Ці приклади неправильні. dd of=-записує у файл під назвою -, просто пропустіть of=записувати до stdout, оскільки там ddпишеться за замовчуванням. Трубопровід falseне працюватиме так, як falseвін не читає його stdin, тому ddбуде вбито за допомогою SIGPIPE. Для команди , яка відкидає його вхід можна використовувати ... cat > /dev/null. Також порівняння, яке, мабуть, не має ніякого значення, оскільки шийка пляшки, ймовірно, буде генерацією випадкових чисел тут.
Стефан Шазелас

8
Версії AST ddтощо навіть не заважають робити системний виклик запису, коли вони виявляють призначення / dev / null.
Марк Плотнік

54

Я підозрюю, чому багато чого стосується бачення / дизайну, який формував Unix (і, отже, Linux), та переваг, що випливають з цього.

Без сумніву, є несуттєва користь від продуктивності, щоб не розгортати зайвий процес, але я думаю, що в цьому є і більше: Early Unix мав метафору "все є файлом", яка має не очевидну, але елегантну перевагу, якщо подивитися це з системної точки зору, а не з сценарію оболонок сценаріїв.

Скажіть, у вас є програма nullкомандного рядка та /dev/nullвузол пристрою. З точки зору оболонок сценаріїв, foo | nullпрограма насправді є справді корисною та зручною та foo >/dev/nullпотребує трохи більше часу, щоб набрати та може здатися дивним.

Але ось дві вправи:

  1. Давайте реалізуємо програму , nullвикористовуючи існуючі інструменти Unix і /dev/null- легко: cat >/dev/null. Зроблено.

  2. Чи можете ви реалізувати /dev/nullз точки зору null?

Ви абсолютно праві, що код C для відмови від введення є тривіальним, тому може бути ще не очевидно, чому корисно мати віртуальний файл для виконання завдання.

Поміркуйте: майже кожна мова програмування вже потребує роботи з файлами, дескрипторами файлів та шляхами до файлів, оскільки вони з початку були частиною парадигми Unix "все є файл".

Якщо все, що у вас є, це програми, які пишуть у stdout, ну, програмі не важливо, перенаправляєте їх у віртуальний файл, який проковтує всі записи, або трубу в програму, яка ковтає всі записи.

Тепер, якщо у вас є програми, які беруть шляхи до файлів читання чи запису даних (що це робить більшість програм), - і ви хочете додати до цих програм функцію "пустий ввід" або "відкинути цей вихід" - добре, /dev/nullщо це безкоштовно.

Зауважте, що його елегантність полягає в тому, що це зменшує складність коду всіх програм, що беруть участь - для кожного загального, але особливого шаблону, який ваша система може надати як "файл" з фактичним "ім'ям файлу", ваш код може уникнути додавання спеціальної команди -лінійні параметри та спеціальні шляхові коди для обробки.

Хороша інженерія програмного забезпечення часто залежить від того, щоб знайти хороші або "природні" метафори для абстрагування якогось елемента проблеми таким чином, що стає простіше думати, але залишається гнучким , так що ви можете вирішити в основному той самий спектр проблем вищого рівня без необхідності постійно витрачайте час і розумову енергію на повторне втілення в життя рішень тих самих проблем нижчого рівня.

"Все є файлом", здається, є однією з таких метафор для доступу до ресурсів: Ви викликаєте openзаданий шлях у герархічному просторі імен, отримуєте посилання (дескриптор файлу) на об'єкт, і ви можете readі writeт. Д. На дескриптори файлів. Ваш stdin / stdout / stderr - це також дескриптори файлів, які щойно були попередньо відкриті для вас. Ваші труби - це лише файли та дескриптори файлів, а перенаправлення файлів дозволяє склеїти всі ці частини разом.

Unix досяг успіху настільки ж, як і частково, через те, наскільки добре ці абстракції працювали разом, і /dev/nullце найкраще розуміти як частину цілого.


PS Варто подивитися на версію Unix "все є файлом" і такі речі, як /dev/nullперші кроки до гнучкішого та потужнішого узагальнення метафори, що було реалізовано у багатьох системах, що слідували за цим.

Наприклад, в Unix спеціальні файлоподібні об'єкти, такі як /dev/nullповинні були бути реалізовані в самому ядрі, але виявляється, що досить корисно розкрити функціональність у формі файлу / папки, що з тих пір було створено кілька систем, які забезпечують шлях для програм зробити це.

Однією з перших була операційна система Plan 9, яку створили одні і ті ж люди, які створили Unix. Пізніше GNU Hurd зробив щось подібне зі своїми "перекладачами". Тим часом, Linux в кінцевому підсумку отримав FUSE (який уже розповсюдився на інші основні системи).


8
@PeterCordes пункт відповіді починається з позиції не розуміння дизайну. Якби всі вже зрозуміли дизайн, це питання не існувало б.
OrangeDog

1
@mtraceur: Встановити файл зображення без дозволу кореня? показує деякі докази того, що FUSE може не вимагати root, але я не впевнений.
Пітер Кордес

1
@PeterCordes RE: "здається дивним": Це не вибачення за дизайн, а лише підтвердження того, як це може здатися, якщо ви не замислюєтесь над впровадженням системи під ним, і ще не мали моменту еврики про систему переваги дизайну в цілому. Я спробував це зрозуміти, відкривши це речення "з точки зору сценарію оболонки" і натякаючи на контраст між цією та системною перспективою на кілька пропозицій до цього. При подальшій думці краще "може здатися дивним", тому я підключу його до цього. Я вітаю подальші формулювання пропозицій, щоб зробити це більш зрозумілим, не роблячи його занадто багатослівним.
mtraceur

2
Перше, що мені сказали, як молодий інженер стосовно Unix, - це "Все є файлом", і я клянусь, що ви можете почути столиці. І якнайшвидше отримати цю ідею, Unix / Linux здається набагато простішим для розуміння. Linux успадкував більшу частину цієї філософії дизайну. Я радий, що хтось це згадав.
StephenG

2
@PeterCordes, DOS "вирішив" проблему введення тексту, створивши магічне ім'я файлу NULу кожному каталозі, тобто все, що вам потрібно ввести > NUL.
Крістіан Цюпіту

15

Я думаю /dev/null, що це символьний пристрій (який поводиться як звичайний файл) замість програми з міркувань продуктивності .

Якщо це буде програма, вона вимагає завантаження, запуску, планування, запуску, а потім зупинення та вивантаження програми. Проста програма C, яку ви описуєте, звичайно, не потребує великої кількості ресурсів, але я думаю, що це має суттєву різницю при розгляді великої кількості (скажімо мільйонів) дій переадресації / трубопроводів, оскільки операції з управління процесами коштують у великому масштабі, оскільки вони включають контекстні комутатори.

Ще одне припущення: підключення до програми вимагає виділення пам'яті приймаючою програмою (навіть якщо вона відкидається безпосередньо після цього). Тож якщо ви підключите цей інструмент, ви маєте подвійне споживання пам’яті, один раз на програму відправки і знову на програму прийому.


10
Це не лише вартість налаштування, це те, що кожне записування в трубу вимагає копіювання пам'яті та переключення контексту на програму читання. (Або принаймні контекстний перемикач, коли буфер каналу заповнений. І зчитувач повинен зробити ще одну копію, коли він містить readдані). Це не є незначним для одноядерного PDP-11, де був розроблений Unix! Пропускна здатність / копіювання пам’яті сьогодні набагато дешевше, ніж тоді. writeСистемний виклик до FD відкриється /dev/nullможе повернутися відразу ж, навіть НЕ читаючи жодних даних з буфера.
Пітер Кордес

@PeterCordes, моя примітка є дотичною, але можливо, що, як не парадоксально, пам'ять, що пише сьогодні, коштує дорожче, ніж будь-коли. 8-ядерний процесор потенційно виконує 16 цілих операцій за годинник, тоді як запис пам'яті в кінці закінчується, наприклад, 16 тактовими частотами (4 ГГц процесор, 250 МГц ОЗУ). Це коефіцієнт 256. ОЗУ для сучасного процесора - це як RL02 до процесора PDP-11, майже як периферійний накопичувач! :) Не так просто, природно, але все, що потрапить у кеш, буде виписано, і марні записи позбавлять інших обчислень завжди важливого простору кешу.
ккм

@kkm: Так, витрачати приблизно 2х 128 Кб слід кешу L3 на буфер труби в ядрі та буфер читання в nullпрограмі буде смоктати, але більшість багатоядерних процесорів не працюють із усіма ядрами, зайнятими весь час, тому Час процесора для запуску nullпрограми здебільшого вільний. У системі з усіма приєднаними сердечниками марні трубопроводи - це велика справа. Але ні, "гарячий" буфер може бути переписаний багато разів, не потрапляючи в RAM, тому ми здебільшого конкуруємо за пропускну здатність L3, а не за кеш. Не чудово, особливо в системі SMT (гіпертрейдінг), де змагаються інші логічні ядра на тій же фізичній основі ...
Пітер Кордес,

.... Але ваш розрахунок пам'яті дуже хибний. Сучасні процесори мають багато паралелізму пам’яті, тому, хоча затримка в DRAM - це щось на зразок 200-400 базових тактових циклів і L3> 40, пропускна здатність становить ~ 8 байт / такт. (Дивно, але однопотокова пропускна здатність до L3 або DRAM гірша на багатоядерному Xeon з чотирьохядерною пам’яттю порівняно з чотирьохядерним робочим столом, оскільки вона обмежена максимальною сукупністю запитів, яку може підтримувати одне ядро ​​в польоті. Bandwidth = max_concurrency / latency: Чому Skylake настільки кращий, ніж Broadwell-E для однопотокової пропускної здатності пам’яті? )
Пітер Кордес,

... Дивіться також 7-cpu.com/cpu/Haswell.html для номерів Haswell, порівнюючи чотирьохядерний та 18-ядерний. У будь-якому випадку, так, сучасні процесори можуть отримати смішну кількість роботи за годинник, якщо вони не застрягли в очікуванні пам'яті. Здається, що ваші номери становлять лише 2 операції ALU за годинник, як, можливо, Pentium 1993 року або сучасний низькопробний ARM з двома випусками. Ryzen або Haswell потенційно виконує 4 скалярні цілі числа ALU ops + 2 ops оперативної пам’яті на ядро за такт або набагато більше за SIMD. наприклад, Skylake-AVX512 має (на ядро) 2-х тактову пропускну здатність vpaddd zmm: 16 32-бітних елементів за інструкцію.
Пітер Кордес

7

Окрім "все є файлом", а отже, простота використання скрізь, на якій базується більшість інших відповідей, існує також проблема продуктивності, як згадується @ user5626466.

Щоб показати на практиці, ми створимо просту програму під назвою nullread.c:

#include <unistd.h>
char buf[1024*1024];
int main() {
        while (read(0, buf, sizeof(buf)) > 0);
}

і скласти його gcc -O2 -Wall -W nullread.c -o nullread

(Примітка: ми не можемо використовувати lseek (2) на трубах, тому єдиний спосіб злити трубу - це зчитування з неї, поки вона не порожня).

% time dd if=/dev/zero bs=1M count=5000 |  ./nullread
5242880000 bytes (5,2 GB, 4,9 GiB) copied, 9,33127 s, 562 MB/s
dd if=/dev/zero bs=1M count=5000  0,06s user 5,66s system 61% cpu 9,340 total
./nullread  0,02s user 3,90s system 41% cpu 9,337 total

тоді як при стандартному /dev/nullперенаправленні файлів ми отримуємо набагато кращі швидкості (завдяки згаданим фактам: менша комутація контексту, ядро ​​просто ігнорує дані, а не копіює їх тощо):

% time dd if=/dev/zero bs=1M count=5000 > /dev/null
5242880000 bytes (5,2 GB, 4,9 GiB) copied, 1,08947 s, 4,8 GB/s
dd if=/dev/zero bs=1M count=5000 > /dev/null  0,01s user 1,08s system 99% cpu 1,094 total

(це повинен бути коментар, але він занадто великий для цього і був би абсолютно нечитабельним)


На якому апараті ви протестували? 4.8 Гб / с досить низький порівняно з 23 Гб / с, який я отримую на Skylake i7-6700k (DDR4-2666, але буфер повинен залишатися гарячим в кеш-пам'яті L3. Отже, хороша частина вартості - це системні дзвінки, що дорогі за допомогою Spectre + Увімкнено запобігання збитку. Це спричиняє біль удвічі для трубопроводів, оскільки трубопровідні буфери менші, ніж 1 М, тому це більше записів / читання системних викликів. Майже в 10 разів різниця в перфірмі є гіршою, ніж я очікував. Однак у моїй системі Skylake це 23 Гб / с проти 3,3 ГБ / с , працює на x86-64 Linux 4.15.8-1-ARCH, тож це коефіцієнт 6,8. Нічого, системні дзвінки зараз дорогі )
Пітер Кордес,

1
@PeterCordes 3 Гб / с з 64- кратними буферними трубами пропонує 2 x 103124 систематичних дзвінків на секунду ... і таку кількість контекстних комутаторів, хе. На серверному процесорі, що має 200000 системних дзвінків в секунду, ви можете очікувати ~ 8% накладних витрат від PTI, оскільки робочого набору дуже мало. (Графік, на який я посилаюсь, не включає оптимізацію PCID, але, можливо, це не так важливо для невеликих робочих наборів). Тож я не впевнений, що PTI має великий вплив на це? brendangregg.com/blog/2018-02-09/…
sourcejedi

1
Про цікаво, так це Silvermont з 2Мб кеша L2 , так що ваш ddбуфер + приймальний буфер не підходить; ви, мабуть, маєте справу з пропускною здатністю пам'яті замість пропускної здатності кешу останнього рівня. Ви можете покращити пропускну здатність за допомогою буферів 512k або навіть 64K буферів. (Згідно straceз моїм робочим столом, writeі readповертаються 1048576, тому я думаю, що це означає, що ми платимо користувачеві <-> вартість ядра недійсності TLB + флеш-прогнозування філії один раз на MiB, а не на 64k, @sourcejedi. Це Spectre пом'якшення, яке має найбільшу вартість, я думаю)
Пітер Кордес

1
@sourcejedi: Якщо ввімкнено зменшення ефекту Spectre, вартість syscallповернення, що повертається відразу, ENOSYSстановить ~ 1800 циклів на Skylake з увімкненим пом’якшенням Spectre. Більшість це те, wrmsrщо втрачає чинність на BPU, згідно з тестуванням @ BeeOnRope . Якщо функція пом'якшення відключена, час подорожі користувача у користувачеві> ядро-> користувач становить ~ 160 циклів. Але якщо є зворушливі багато пам'яті, Meltdown пом'якшення є значним, теж. Величезні сторінки повинні допомогти (потрібно зменшити кількість записів TLB).
Пітер Кордес

1
@PeterCordes У одноядерній системі Unix ми, безумовно, побачимо 1 контекстний перемикач на 64 Кб, або будь-який ваш буфер, і це зашкодить ... насправді я також бачу [таку ж кількість контекстних комутаторів з 2 ядрами процесора] ( unix.stackexchange.com/questions/439260/… ); він також повинен рахувати цикл сну / неспання для кожного 64k як контекстний перемикач (до номінального "простою"). Утримання процесів трубопроводу на одному процесорі фактично працювало більш ніж удвічі швидше.
sourcejedi

6

Ваше запитання задається так, ніби щось можна було б отримати в простоті, використовуючи нульову програму замість файлу. Можливо, ми можемо позбутися поняття «чарівні файли» і замість цього мати просто «звичайні труби».

Але врахуйте, труба - це також файл . Зазвичай вони не названі, і таким чином ними можна керувати лише через їх дескриптори файлів.

Розглянемо цей дещо надуманий приклад:

$ echo -e 'foo\nbar\nbaz' | grep foo
foo

Використовуючи підстановку процесу Баша, ми можемо зробити те ж саме шляхом більш обхідним способом:

$ grep foo <(echo -e 'foo\nbar\nbaz')
foo

Замінити grepна echoта ми можемо бачити під ковдрою:

$ echo foo <(echo -e 'foo\nbar\nbaz')
foo /dev/fd/63

<(...)Конструкція просто замінюється ім'ям файлу, і Grep думає , що це відкриття будь-який старий файл, він просто трапляється , щоб бути названим /dev/fd/63. Ось /dev/fdмагічний каталог, який робить іменовані труби для кожного дескриптора файлів, якими володіє файл, що має до нього доступ.

Ми могли б зробити менш магічним, mkfifoщоб зробити іменовану трубу, яка відображається в lsі все, як звичайний файл:

$ mkfifo foofifo
$ ls -l foofifo 
prw-rw-r-- 1 indigo indigo 0 Apr 19 22:01 foofifo
$ grep foo foofifo

В іншому місці:

$ echo -e 'foo\nbar\nbaz' > foofifo

і ось, греп виведе foo.

Я думаю , як тільки ви розумієте , трубу і звичайні файли і спеціальні файли , такі як / DEV / нуль все тільки файли, це очевидно , впровадження нульової програми є більш складним. Ядро повинно в будь-якому випадку керувати записом у файл, але у випадку / dev / null воно може просто скинути записи на підлогу, тоді як з трубою воно має фактично передати байти в іншу програму, яка потім повинна насправді їх читайте.


@Lyle Так? Тоді чому відлуння друкує /dev/fd/63?
Філ Мороз

Гм. Влучне зауваження. Ну, це реалізовано снарядами, тому, можливо, ваша оболонка відрізняється від старої оболонки Борна, з якою я виріс.
Лайл

Одна відмінність полягає в тому, що ехо не читається зі stdin, а grep, але я не можу подумати, як оболонка знала б це, перш ніж виконувати їх.
Лайл

1
І напруження робить це зрозумілішим: для мене. у вас це правильно, з басом. Конструкція '<(...)' робить щось зовсім інше, ніж <ім'я файлу. Гм. Я чомусь навчився.
Лайл

0

Я б заперечував, що існує проблема безпеки поза історичними парадигмами та ефективністю. Обмеження кількості програм з привілейованими обліковими даними виконання, неважливо, наскільки просто, є основоположним принципом безпеки системи. /dev/nullБезперечно потрібна заміна , щоб мати такі привілеї через використання системними службами. Сучасні системи безпеки виконують чудову роботу, запобігаючи подвигам, але вони не є надійними. Пристрій, керований ядром, доступ до якого є файлом, набагато складніше експлуатувати.


Це звучить як дурниця. Написання драйвера ядра без помилок не простіше, ніж написання програми без помилок, яка читає + відкидає її stdin. Він не повинен бути УИП або що - небудь, так як для /dev/nullабо пропонованого введення-відкидаючи програми, вектор атаки буде такою ж: отримати скрипт або програму , яка працює як корінь , щоб зробити що - то дивне (як намагаються lseekв /dev/nullабо відкритої це кілька разів за один і той же процес, або IDK що- /bin/nullнебудь . Або викликати дивне середовище чи будь-що інше).
Пітер Кордес

0

Як вже вказували інші, /dev/null це програма, що складається з декількох рядків коду. Просто ці рядки коду є частиною ядра.

Щоб зробити це зрозумілішим, ось реалізація Linux: символьний пристрій викликає функції під час читання або запису на них. Писання на /dev/nullдзвінки write_null , під час читання дзвінків read_null , зареєстровані тут .

Буквально жменька рядків коду: ці функції нічого не роблять. Вам знадобиться більше рядків коду, ніж пальці на руках, лише якщо ви рахуєте інші функції, ніж читання та запис.


Можливо, я мусив би точніше її сформулювати. Я мав на увазі, чому реалізувати це як пристрій чарівництва замість програми. Будь-який рядок буде в декількох напрямках, але реалізація програми була б простішою. Як вказували інші відповіді, в цьому є досить багато переваг; ефективність та мобільність серед них.
Ankur S

Звичайно. Я щойно додав цю відповідь, тому що бачити фактичну реалізацію було цікаво (я її нещодавно я виявив), але справжня причина - це те, що насправді зазначили інші.
Матьє Мой Мой

Я також! Нещодавно я почав вивчати пристрої в Linux і відповіді були досить інформативними
Ankur S

-2

Я сподіваюся, що ви також знаєте / dev / chargen / dev / zero та інших подібних до них, включаючи / dev / null.

У LINUX / UNIX є декілька з них - доступні для того, щоб люди могли добре використати ФОРМАЛЬНІ КОДОВІ КОДИ.

Chargen призначений для генерування конкретного і повторюваного шаблону символів - він досить швидкий і підштовхує межі послідовних пристроїв, і це допоможе налагодити послідовні протоколи, які були написані та провалили тест чи інше.

Нуль призначений для заповнення наявного файлу або виведення цілого ряду нулів

/ dev / null - це ще один інструмент з такою ж ідеєю на увазі.

Усі ці інструменти у вашому наборі інструментів означають, що у вас є половина шансів зробити існуючу програму зробити щось унікальне, не зважаючи на їх (ваші конкретні потреби) як пристрої або заміну файлів

Дозвольте створити конкурс, щоб побачити, хто може отримати найцікавіший результат, враховуючи лише декілька символьних пристроїв у вашій версії LINUX.

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