Быстрое решение вашей проблемы :смонтируйте 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 ), рассматривался ли вообще этот эффект. В любом случае, помещение символьных устройств в мир -записываемых липких каталогов вряд ли будет преднамеренным.
«Все есть напильник» — это, так сказать, лозунг. Мем, если хотите. Это не совсем так.
Очевидно, что аппаратные устройства не являются реальными файлами, как hello.txt
в файловой системе ext4. Многие из них даже не имеют ничего общего с устройствами хранения.
Но даже несмотря на то, что не все является файлом , к некоторым вещам можно получить доступ, как если бы они были файлами, по крайней мере отчасти. То есть они имеют имя в дереве файловой системы, и для них можно использовать системные вызовы read()
и write()
. Последнее особенно важно, если учесть, что «все является потоком байтов», поскольку эти вызовы обращаются к потокам байтов.
Поскольку одни и те же системные вызовы работают с обычными файлами, дисковыми устройствами, терминалами, сетевыми сокетами и каналами, с ними можно использовать один и тот же набор инструментов. Например. echo foo
работает одинаково независимо от того, куда подключен выход. Это может упростить реализацию утилиты,и облегчает их применение для новых целей.
Кроме того, когда в файловой системе присутствует ряд объектов, они могут быть перечислены с помощью ls
и доступны с помощью cat
и перенаправления оболочки(echo foo >...
).
Еще не все является файлом или потоком байтов, а для того, что есть, не все можно сделать с помощью read()
и write()
. Сокеты UDP не являются потоками байтов, они передают многобайтовые дейтаграммы -фиксированного размера. Некоторые действия по-прежнему необходимо выполнять с помощью системного вызова ioctl()
, а операции ioctl зависят от устройства -.
См. также, например,.