Что в Unix означает фраза «Все есть поток байтов»?

Быстрое решение вашей проблемы :смонтируйте tmpfsс параметром mode=(, который устанавливает разрешения корневого каталога файловой системы ), и используйте режим без либо липкий бит (01000), либо разрешение на запись для других (002)--, которые оба на по умолчанию:

root@host:~/test# mount -o mode=0755 -t tmpfs none dev/

Вы ничего не теряете; наличие каталога /devвнутри вашего контейнера, доступного для записи всем, не было хорошей идеей с самого начала (было бы интересно узнать, делает ли это Docker;-))


Это происходит из-за tmpfsмонтирования внутри пользовательского пространства имен :ядро ​​устанавливает владельца корневого каталога файловой системы tmpfsиз непереведенных учетных данных процесса, выполняющего монтирование (, откуда uid=1000,gid=1000в выводе mount(1)), а его разрешения по умолчанию01777(rwxдля всех + липкий бит ).

Сочетание не -корневого владельца, разрешений на запись для других(S_IWOTH)и фиксированного бита(S_ISVTX)в каталоге вызывает любопытное поведение в более новых ядрах Linux :, пытающихся open(2)существующий символ устройство внутри такого каталога выйдет из строя с EACCES, если используется флаг O_CREAT, даже если это сделал владелец каталога:

$ mkdir doo; chmod 1777 doo 
$ su -c 'mknod -m 666 doo/null c 1 3'  # or touch doo/null; mount -B /dev/null doo/null 
$ echo > doo/null
bash: doo/null: Permission denied

$ perl -MFcntl -e 'sysopen(NULL, "doo/null", O_WRONLY|O_CREAT, 0666) or die $!'
Permission denied at -e line 1.
$ perl -MFcntl -e 'sysopen(NULL, "doo/null", O_WRONLY, 0666) or die $!'
$ # ok!

$ chmod -t doo
$ echo > doo/null
$ # ok!

Это воспроизводится в Debian Buster / 4.19.0 -5 и в более поздних ядрах, но не в Debian Stretch / 4.9.0 -4.

Такое поведение было введено как побочный эффект этой фиксации :

.

commit 30aba6656f61ed44cba445a3c0d38b296fa9e8f5
Author: Salvatore Mesoraca 
Date:   Thu Aug 23 17:00:35 2018 -0700

    namei: allow restricted O_CREAT of FIFOs and regular files
...
diff --git a/fs/namei.c b/fs/namei.c
...
+static int may_create_in_sticky(struct dentry * const dir,
+                               struct inode * const inode)
+{
+       if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) ||
+           (!sysctl_protected_regular && S_ISREG(inode->i_mode)) ||
+           likely(!(dir->d_inode->i_mode & S_ISVTX)) ||
+           uid_eq(inode->i_uid, dir->d_inode->i_uid) ||
+           uid_eq(current_fsuid(), inode->i_uid))
+               return 0;
+
+       if (likely(dir->d_inode->i_mode & 0002) ||
+           (dir->d_inode->i_mode & 0020 &&
+            ((sysctl_protected_fifos >= 2 && S_ISFIFO(inode->i_mode)) ||
+             (sysctl_protected_regular >= 2 && S_ISREG(inode->i_mode))))) {
+               return -EACCES;
+       }
+       return 0;
+}

doo/nullне очистит первый if, потому что это не fifo и не обычный файл, в содержащем каталоге действительно установлен фиксированный бит, а его uid отличается от идентификатора каталога и от идентификатора каталога. процесс пытается его открыть.

Он будет немедленно соответствовать второму if, потому что в содержащем каталоге установлен бит002(записи -для -других ).

Я не нашел в обсуждениях lkml, где это было введено(1 , 2 , 3 ), рассматривался ли вообще этот эффект. В любом случае, помещение символьных устройств в мир -записываемых липких каталогов вряд ли будет преднамеренным.

-1
01.11.2021, 12:10
1 ответ

«Все есть напильник» — это, так сказать, лозунг. Мем, если хотите. Это не совсем так.

Очевидно, что аппаратные устройства не являются реальными файлами, как hello.txtв файловой системе ext4. Многие из них даже не имеют ничего общего с устройствами хранения.

Но даже несмотря на то, что не все является файлом , к некоторым вещам можно получить доступ, как если бы они были файлами, по крайней мере отчасти. То есть они имеют имя в дереве файловой системы, и для них можно использовать системные вызовы read()и write(). Последнее особенно важно, если учесть, что «все является потоком байтов», поскольку эти вызовы обращаются к потокам байтов.

Поскольку одни и те же системные вызовы работают с обычными файлами, дисковыми устройствами, терминалами, сетевыми сокетами и каналами, с ними можно использовать один и тот же набор инструментов. Например. echo fooработает одинаково независимо от того, куда подключен выход. Это может упростить реализацию утилиты,и облегчает их применение для новых целей.

Кроме того, когда в файловой системе присутствует ряд объектов, они могут быть перечислены с помощью lsи доступны с помощью catи перенаправления оболочки(echo foo >...).

Еще не все является файлом или потоком байтов, а для того, что есть, не все можно сделать с помощью read()и write(). Сокеты UDP не являются потоками байтов, они передают многобайтовые дейтаграммы -фиксированного размера. Некоторые действия по-прежнему необходимо выполнять с помощью системного вызова ioctl(), а операции ioctl зависят от устройства -.

См. также, например,.

0
01.11.2021, 15:11

Теги

Похожие вопросы