Есть ли файл, который всегда существует, и «нормальный» пользователь не может это сделать?

14

Мне нужно это для модульного теста. Есть функция, которая делает lstat для пути к файлу, переданного в качестве его параметра. Я должен вызвать путь кода, где происходит lstatсбой (потому что охват кода должен достигать 90%)

Тест может выполняться только под одним пользователем, поэтому мне было интересно, есть ли в Ubuntu файл, который всегда существует, но у обычных пользователей нет доступа для чтения к нему или к его папке. (Таким образом, lstatпроизойдет сбой, если он не выполнен от имени пользователя root.)

Несуществующий файл не является решением, потому что для этого есть отдельный путь к коду, который я уже запускаю.

РЕДАКТИРОВАТЬ: Недостаток доступа только для чтения файла недостаточно. С этим lstatеще можно выполнить. Я смог запустить его (на моей локальной машине, где у меня есть права доступа root), создав папку в / root и файл в ней. И установив разрешение 700 на папку. Поэтому я ищу файл, который находится в папке, доступной только пользователю root.

Крадущийся котенок
источник
6
ИМХО/etc/shadow
Ромео Нинов
3
Вы не можете предполагать существование какого-либо файла, потому что ваша программа может работать в изолированном пространстве или пространстве имен. Если предположить, что / proc монтируется, и init ничего особенного, то /proc/1/fd/0следует сделать.
Мосви
1
@mosvy Спасибо, что работает на моей локальной машине. Хм, тогда я попробую это на QA и Staging pool тоже.
Крадущийся котенок
2
Почему вы привязываете свой тестовый код к определенной разновидности ОС, когда вы можете просто создать одноразовый файл и удалить свой собственный доступ для чтения к нему?
Килиан Фот
4
Я бы сказал, что на самом деле это не модульное тестирование, поскольку оно начинается в зависимости от реальной, а не надуманной файловой системы.
Тоби Спейт

Ответы:

21

В современных системах Linux вы должны быть в состоянии использовать /proc/1/fdinfo/0(информацию для файлового дескриптора 1 (stdout) процесса с идентификатором 1 ( initв пространстве имен корневого pid, которое должно работать как root)).

Вы можете найти список с (как обычный пользователь):

sudo find /etc /dev /sys /proc -type f -print0 |
  perl -l -0ne 'print unless lstat'

(удалите, -type fесли вы не хотите ограничиваться обычными файлами).

/var/cache/ldconfig/aux-cacheеще один потенциальный кандидат, если вам нужно только рассмотреть системы Ubuntu. Он должен работать на большинстве систем GNU, так как /var/cache/ldconfigсоздается для чтения + записи + с возможностью поиска в корневом каталоге только ldconfigкомандой, поставляемой с GNU libc.

Стефан Шазелас
источник
1
Благодарность! Если /proc/1/fdinfo/0работает на Ubuntu 16.04 и 18.04, этого более чем достаточно.
Крадущийся котенок
1
Использование /proc/1/fdinfo/0не обязательно работает в контейнере (например, контейнере Docker), и часто модульные тесты выполняются в таких контейнерах в CI.
Филипп Вендлер
@PhilippWendler, я уже упоминал пространство имен корневого pid . ОП спрашивает не о контейнерах, а о файлах, которые гарантированно будут присутствовать в макете файловой системы системы Ubuntu. Поскольку контейнеры могут содержать любой файл и макет каталога, этот вопрос не может быть подотчетен там.
Стефан
12

Глядя на справочную страницу lstat (2), вы можете получить некоторое представление о случаях, которые могут привести к сбою с ошибками, отличными от ENOENT (файл не существует).

Самый очевидный из них:

EACCES разрешения Поиск запрещен для одного из каталогов в пути префиксом пути .

Таким образом, вам нужен каталог, из которого вы не можете искать.

Да, вы можете найти тот, который уже есть в вашей системе (возможно, /var/lib/privateесли он существует?), Но вы могли бы также создать его самостоятельно, с эквивалентом:

$ mkdir myprivatedir
$ touch myprivatedir/myunreachablefile
$ chmod 0 myprivatedir
$ ls -l myprivatedir/myunreachablefile

Операция lstat (2) завершится с ошибкой EACCES. (Удаление всех разрешений из каталога гарантирует это. Может быть, вам даже не нужно так много, и chmod -xудаления разрешений на выполнение будет достаточно, поскольку для доступа к файлам в нем необходимы разрешения на выполнение.)

Есть еще один творческий способ сделать так, чтобы lstat (2) потерпел неудачу, посмотрев его справочную страницу:

ENOTDIR Компонент префикса пути пути не является каталогом.

Таким образом, попытка доступа к файлу, например, /etc/passwd/nonexistentдолжна вызвать эту ошибку, которая опять-таки отличается от ENOENT («Нет такого файла или каталога») и может удовлетворить ваши потребности.

Еще один:

ENAMETOOLONG путь слишком длинный.

Но вам может понадобиться действительно длинное имя для этого (я думаю, что 4096 байт - это типичное ограничение, но ваша система / файловая система может иметь более длинное имя).

Наконец, трудно сказать, будет ли что-нибудь из этого действительно полезным для вас. Вы говорите, что хотите что-то, что не вызывает сценарий «файл не существует». Хотя обычно это означает ошибку ENOENT, на практике многие проверки более высокого уровня будут просто интерпретировать любые ошибки из lstat (2) как «не существует». Например, test -eили эквивалент [ -e ...]из оболочки может просто интерпретировать все вышеперечисленное как «не существует», тем более что у него нет хорошего способа вернуть другое сообщение об ошибке, и не возвращая ошибку, можно предположить, что файл существует, что, безусловно, не так.

filbranden
источник
@ StephaneChazelas Отличный момент! Обновлено.
filbranden
6

Вы можете сделать findэто сами.

Использование /etc- каталог файлов конфигурации в качестве отправной точки:

sudo find /etc -type f -perm 0400 -user root

В моей системе это ничего не возвращает.

Вы можете быть менее строгой и разрешить группу root(только пользователь rootдолжен быть членом группы root), и искать разрешение 440:

sudo find /etc -perm 0440 -user root -group root

В моей системе это возвращает:

/etc/sudoers.d/README
/etc/sudoers

Редактировать:

Основываясь на ваших изменениях, вы ищете каталог, который не имеет достаточных прав для вызывающего пользователя, чтобы предотвратить листинг каталога:

sudo find / -perm o-rwx -type d -user root -group root 

здесь я ищу каталоги ( -type d), в которых отсутствуют биты perm для чтения-записи-выполнения для других ( o-rwx) и которые принадлежат root:root.

Технически, просто отсутствие xбита execute ( ) предотвратило бы каталог ( lstat(2)) в каталоге.

В выводе я нашел /run/systemd/inaccessible/в моей системе на основе инициализации Systemd.

Что касается файлов /proc, /sys, /dev:

  • Эти файловые системы являются виртуальными ФС, то есть они находятся в памяти, а не на диске

  • Если вы планируете полагаться /proc, используйте, /proc/1/т.е. полагайтесь на что-то в соответствии с PID 1, а не на любые более поздние PID для обеспечения надежности / согласованности, поскольку более поздние PID (процессы) не гарантируются.

heemayl
источник
Спасибо, я думаю, что мой вопрос не так. Я все еще могу lstat файлы без доступа для чтения к ним. Может быть, доступ к папке должен быть ограничен? (Я изменил название)
Крадущийся Kitten
Благодарю. С помощью find / -type d -perm 0400 -user rootя нашел каталог /proc/20/map_files/, если я ссылаюсь на имя файла в этой папке, например /proc/20/map_files/asdasd, он всегда терпит неудачу. Эта папка всегда существует в Ubuntu?
Крадущийся котенок
@CrouchingKitten, каталоги в /proc/1/могут быть более безопасными, так как init всегда существует. Но это procне обычная файловая система, если это имеет значение.
ilkkachu
Спасибо, я дал возражение, но принял другой ответ, потому что он сказал, что гарантированно /proc/1/fdinfo/0работает на современном Ubuntus.
Крадущийся котенок
-perm o-rwxэто как -perm 0биты все с начала. Вот, ты бы хотел ! -perm -1.
Стефан