Лабораторная работа "Дискреционное управление доступом" - efanov/mephi GitHub Wiki
Данная работа посвящена дискреционному управлению доступом. В ходе её выполнения вы воспользуетесь инструментами, реализующими этот механизм, а также начнёте программировать с использованием системных вызовов.
Для сдачи работы достаточно написать аналог программы chmod
на языке C.
Требования к программе и формат сдачи описаны ниже.
- Содержание
- Общие сведения
- Практические задания
- Основное задание
- Вопросы для самоконтроля
- Порядок защиты работы
В ходе выполнения работы Вам потребуется обращаться к man(2)
для получения информации о системных вызовах.
Если при попытке открыть man(2)
Вы получаете ошибки вроде следующей:
No manual entry for open in section 2
Установите man
-страницы с помощью
sudo dnf install man-pages
Описание битов доступа:
Бит доступа | Файл | Директория |
---|---|---|
r (чтение) |
Читать из файла | Выводить содержимое директории (только имена файлов) |
w (запись) |
Писать в файл | Создавать, удалять, перемещать и переименовывать файлы в директории (также требуется x ) |
x (исполнение/поиск) |
Запускать файл на исполнение (файл является программой или сценарием) | Читать метаданные файлов в директории (содержимое инодов). Использовать директорию в пути к файлу, переходить в директорию (cd), выводить содержимое директории в длинном формате (ls -l ) |
u +s (set-user-ID, SUID) |
Устанавливает эффективный идентификатор пользователя EUID процесса при исполнении файла равным идентификатору UID владельца файла | Не используется |
g +s (set-group-ID, SGID) |
Устанавливает эффективный идентификатор группы EGID процесса при исполнении файла равным идентификатору GID группы файла | Устанавливает идентификатор группы GID для файлов, создаваемых в директории, равным идентификатору группы директории GID (при создании файла, GID наследуется от директории, в которой создается файл) |
o +t (sticky) |
Не используется | Удалять или переименовывать файлы в директории может только владелец директории, или владелец файла, или процесс с привилегией CAP_FOWNER (также требуется w ) |
Чтобы запустить двоичный файл, достаточно только права на исполнение, а для запуска сценария необходимо наличие двух прав: на чтение и на исполнение.
Некоторые системные вызовы требуют указания или возвращают права доступа к файлу или тип файла.
Для описания типа файла используются следующие флаги, определённые в заголовочном файле sys/stat.h
:
#define S_IFLNK 0120000
#define S_IFREG 0100000
#define S_IFBLK 0060000
#define S_IFDIR 0040000
#define S_IFCHR 0020000
#define S_IFIFO 0010000
Для описания прав доступа к файлу используются следующие флаги, определённые в заголовочном файле sys/stat.h
:
#define S_ISUID 0004000
#define S_ISGID 0002000
#define S_ISVTX 0001000
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001
Флаги можно комбинировать между собой с помощью операции побитового ИЛИ |
.
Например, для создания файла может использоваться системный вызов open
с перечислением указанных выше флагов для задания прав доступа к нему:
open("some_file", O_CREAT, S_IRWXU | S_IRGRP);
Системные вызовы могут завершиться неудачей.
Например, файл, к которому запрашивается доступ, не существует или для его открытия недостаточно прав.
Для предотвращения непредсказуемого поведения программы в этих случаях необходимо исследовать результат выполнения системного вызова (вообще, любой функции).
Чтобы понять, как обрабатывать результат системного вызова, необходимо прочитать его документацию в man(2)
.
Например, рассмотрим системный вызов access
.
В man(2)
написано:
...
RETURN VALUE
On success (all requested permissions granted, or mode is F_OK
and the file exists), zero is returned. On error (at least one
bit in mode asked for a permission that is denied, or mode is
F_OK and the file does not exist, or some other error occurred),
-1 is returned, and errno is set to indicate the error.
...
Таким образом, выполнять системный вызов access
следует, например, так:
if (-1 == access("some_file", F_OK))
{
perror("access");
exit(EXIT_FAILURE);
}
Конечно, действия при ошибке зависят от программы. В данном примере пользователю просто сообщается об ошибке, и выполнение порграммы прерывается с соответствующим кодом ошибки.
Права доступа и принадлежность файла можно просмотреть с помощью команд ls -l
, stat
.
Например:
ls -l /etc/passwd
# Вывод:
# -rw-r--r--. 1 root root 1047 Oct 3 17:53 /etc/passwd
stat /etc/passwd
# Вывод:
# File: /etc/passwd
# Size: 1047 Blocks: 8 IO Block: 4096 regular file
# Device: fd00h/64768d Inode: 33965265 Links: 1
# Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
# Context: system_u:object_r:passwd_file_t:s0
# Access: 2023-10-03 17:53:54.820289385 +0300
# Modify: 2023-10-03 17:53:54.675292727 +0300
# Change: 2023-10-03 17:53:54.688292428 +0300
# Birth: 2023-10-03 17:53:54.675292727 +0300
Изучите права доступа программы passwd
.
Объясните их смысл.
Для изменения прав доступа к файлу используется системный вызов chmod
.
Этот вызов возможно выполнять как в Bash, так и напрямую в C.
Рассмотрим оба варианта.
В командах ниже предполагается, что в системе существуют два пользователя: ivan
(включен в /etc/sudoers
) и polina
(не включена в /etc/sudoers
).
Команды выполняются от лица пользователя ivan
.
Создадим файл с секретом и сделаем его доступным на чтение только владельцу:
touch file
echo "This is a secret!" > file
chmod 600 file
Попробуем вывести содержимое файла сначала от лица пользователя ivan
, а затем — от лица пользователя polina
:
cat file
# Вывод:
# This is a secret!
sudo -u polina cat file
# Вывод:
# cat: file: Permission denied
Теперь сделайте так, чтобы polina
смогла прочитать содержимое файла file
.
Создадим директорию с файлом в ней:
mkdir dir
touch dir/file
echo "File content." > dir/file
Сделайте так, чтобы файл dir/file
мог прочитать только тот, кто знает о его существовании.
Решите следующие задачи от имени обычного пользователя (не root
).
- Перейдите в домашний каталог.
- Создайте каталог
test
и перейдите в него. - Создайте файл
file
, определите его права доступа. - Запретите любые действия с файлом
file
. - Попробуйте записать строку
"test"
в файлfile
. В доступе должно быть отказано. - Попробуйте прочитать файл
file
. В доступе должно быть отказано. - Измените права доступа для
file
так, чтобы только текущий пользователь мог осуществлять в него запись. Командаls -l
должна показывать права--w-------
. - Запишите строку "test" в файл
file
. Попробуйте прочитать содержимое файла — в доступе должно быть отказано. - Разрешите группе текущего пользователя читать содержимое файла.
Группа текущего пользователя обычно совпадает с именем пользователя.
Команда
ls -l
должна показывать права--w-r-----
. - Попробуйте прочитать содержимое файла
file
. В доступе должно быть отказано. - Разрешите текущему пользователю читать содержимое файла
file
. Командаls -l
должна показывать права-rw-r-----
. - Попробуйте прочитать содержимое файла
file
— должна появиться ранее добавленная туда строка"test"
. - Создайте каталог
dir
. Создайте в этом каталоге файлnew_file
, запишите в него текст "file 2". - Просмотрите содержимое каталога
dir
. Должен появиться файлnew_file
. - Измените права доступа на каталог
dir
так, чтобы пользователи не имели права на исполнение (x
). Попробуйте просмотреть содержимое файлаnew_file
в каталогеdir
. В доступе должно быть отказано. Попробуйте удалить этот файл — в доступе также должно быть отказано. - Попробуйте изменить владельца файла
file
наroot
. Изменить группу владельца наroot
. В обоих операциях должно быть отказано — обычный пользователь не может изменить владельца файла. - При помощи команды
umask
задайте такую маску, чтобы при создании файла никто не имел к нему никакого доступа, кроме владельца. При создании нового файла (командаtouch file1
) права доступа данного файла будут следующими:-rw-------
. - При помощи команды
umask
задайте такую маску, чтобы при создании файла все имели к данному файлу полный доступ. При создании нового файла (командаtouch file2
) права доступа данного файла будут следующими:-rw-rw-rw-
. - Откройте второе окно с терминалом и выполните вход от имени системного администратора (
root
):su
- От имени системного администратора измените владельца файла
file
наroot
. Измените права доступа так, чтобы только владелец мог прочитать файл. По окончании изменений выйдите из сеансаroot
, выполнив командуexit
. - Попробуйте прочитать файл
file
от имени обычного пользователя (неroot
!). В доступе должно быть отказано. - От имени системного администратора измените права доступа на файл так, чтобы группа могла прочитать данный файл.
По окончании изменений выйдите из сеанса
root
, выполнив командуexit
. - Попробуйте прочитать файл
file
от имени обычного пользователя. Доступ должен быть разрешён.
Следующий блок команд выполняется от лица суперпользователя root
.
Ниже файлу f_append_only
устанавливаются атрибуты, позволяющие только дописывать содержимое в конец файла.
Подробности в man chattr
.
echo abc > f_append_only
echo 123456 > f_append_only
ls -l f_append_only
# Вывод:
# -rw-r--r--. 1 root root 4 Oct 10 19:00 f_append_only
cat f_append_only
# Вывод:
# 123456
chattr +a f_append_only
lsattr f_append_only
# Вывод:
# -----a-------------- f_append_only
Попробуйте изменить/перезаписать файл. Объясните результаты. В каких сценариях это может быть полезно?
Сделайте так, чтобы этот файл нельзя было изменять, переименовывать и удалять, а также чтобы нельзя было создавать на него ссылки и открывать его для записи.
Для вывода ACL предназначена команда getfacl
:
getfacl /etc/passwd
# Вывод:
# getfacl: Removing leading '/' from absolute path names
# # file: etc/passwd
# # owner: root
# # group: root
# user::rw-
# group::r--
# other::r--
Для установки ACL предназначена команда setfacl
:
touch file
chmod 600 file
setfacl -m u:polina:r file
ls -l file
# Вывод:
# -rw-r-----+ 1 ivan ivan 14 Oct 5 18:01 file
getfacl file
# Вывод:
# # file: file
# # owner: ivan
# # group: ivan
# user::rw-
# user:polina:r--
# group::---
# mask::r--
# other::---
Перейдите в директорию /tmp
.
Создайте папку и сделайте так, чтобы polina
по-умолчанию могла изменять содержимое всех создаваемых в ней файлов.
Установите необходимые программы в виртуальную машину:
sudo dnf install -y git make gcc
В этом подразделе описывается процесс проброса SSH-агента с целью использования приватных ключей на виртуальной машине без физического переноса их на виртуальную машину. Другими словами, здесь описано, как сделать так, чтобы приватный ключ для GitHub находился у Вас на компьютере, но Вы могли им пользоваться в виртуальной машине, как будто он находится и там тоже. Более подробно можно прочитать в официальной документации.
Для того, чтобы сдать программу, Вам необходимо:
-
Зарегистрироваться на GitHub и настроить себе Git. Для этого выполните всё вот отсюда до раздела Создание Git-репозитория не включительно.
-
На своём компьютере (не на виртуальной машине) отредактируйте файл
~/.ssh/config
и добавьте в нём в разделе с Вашей виртуальной машиной строкуForwardAgent yes
. В итоге должно получиться что-то такое, где<ip_address>
— IP-адрес виртуальной машины, а<username>
— имя вашего пользователя в виртуальной машине:Host rocky HostName <ip_address> User <username> ForwardAgent yes
-
На своём компьютере выполните следующую команду, если Вы в точности следовали инструкции настройки GitHub:
ssh-add ~/.ssh/github
Если следовали инструкции не в точности, замените
~/.ssh/github
на путь до приватного ключа, который используете для GitHub. Вывод команды должен быть примерно такой:Identity added: /Users/<username>/.ssh/github (github)
-
Подключитесь к виртуальной машине через VS Code или терминал и проверьте, что вывод команды
ssh-add -L
имеет примерно следующий вид:ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFzMR8xHlqKBmNSjhLhGzGazSHpERLl5Gudl9wgeahog github
-
Выполните на виртуальной машине
ssh -T [email protected]
Убедитесь, что вывод команды примерно следующий:
Hi USERNAME! You've successfully authenticated, but GitHub does not provide shell access.
Теперь Вы можете использовать свой ключ от GitHub на виртуальной машине без его физического присутствия на нём.
В данном подразделе описано, как выполнять и сдавать работу.
-
Примите задание на платформе GitHub Classroom, перейдя по ссылке: https://classroom.github.com/a/SxqEOs1u.
-
Выберите Своё имя в списке доступных.
-
Вам будет создан репозиторий. Склонируйте его к себе в виртуальную машину в папку
~/projects
. Например, для этого можно выполнить следующие команды, заменив путь к репозиторию в конце на свой (тот, который Вам выдан):mkdir -p ~/projects cd ~/projects git clone [email protected]:Operating-System-Security-Course/discretionary-access-control-USERNAME.git
-
Напишите код программы в файле
src/main.c
относительно корня репозитория (файл уже создан) Структура репозитория следующая:. ├── Makefile ├── README.md ├── src │ └── main.c <- изменять надо этот файл └── tests └── test.sh
Когда Вы напишете код, запустите тесты, выполнив в корне репозитория
make test
Исправьте ошибки, если они возникли. Если ошибок нет и команда выше выводит
ok
, "запушьте" (git push
) код в репозиторий.
Реализуйте программу chmod
на языке C с использованием системных вызовов.
Вызов программы должен происходить следующим образом:
chmod <number> <file>
Например,
chmod 0644 some_file
Проверьте пользовательский ввод, обработайте ошибки и выведите их в случае возникновения.
Подсказка
Для конвертации строки в число можно воспользоваться функциейstrtoul
(string to unsigned long).
- Объясните все биты прав доступа в выводе
ls -l
. - Какая команда используется для изменения прав доступа к файлу?
- Кто может изменять права доступа к файлам?
- Для чего нужен ACL?
- Как устанавливать атрибуты файла?
- Может ли пользователь
root
игнорировать атрибуты файла при работе с ним?
Для защиты работы достаточно написать программу chmod
.