В прошлый раз я исследовал на практике, как работают разрешения rwx
в Linux. Сегодня я продолжу упражнения с правами доступа к файлам и каталогам в Linux и рассмотрю атрибуты setuid
, setgid
и sticky bit
. (Забегая вперед, скажу, что приключение оказалось интереснее, чем я ожидал.) Все приводимые далее примеры я буду выполнять в консоли Ubuntu 14.04.
На самом деле, с файлововй системой от имени пользователя работают процессы, порождаемые командами пользователя, такими как cat
, ls
, mv
и другими. Выполняющийся процесс, помимо прочих, имеет атрибуты эффективный пользователь и эффективная группа, которые обычно соответствуют запустившему процесс пользователю и его первичной группе.
Увидеть эти атрибуты процессов позволяет команда ps
:
ay@tsuki:~$ ps -o uid,user,gid,group,pid,comm
UID USER GID GROUP PID COMMAND
1002 ay 1002 ay 2627 bash
1002 ay 1002 ay 2689 ps
Однако, имеется способ указать операционной системе, чтобы эффективный пользователь или эффективная группа процесса соответствовали не запускающему пользователю и его первичной группе, а пользователю-владельцу и группе исполняемого файла. Для этого используются атрибуты файла
-
setuid
- сделать эффективным пользователем процесса владельца исполняемого файла, и -
setgid
- сделать эффективной группой процесса группу исполняемого файла.
Но процесс всегда помнит, кто его запустил. В отличие от эффективного пользователя и эффективной группы, атрибуты процесса реальный пользователь и реальная группа всегда соответствуют запустившему процесс пользователю и его первичной группе.
Классический пример использования setuid
- утилита passwd
, которая, при изменении каждым пользователем своего пароля, вносит изменения в файл /etc/passwd
, доступный для записи только root
:
ay@tsuki:~$ ls -l /etc/passwd
-rw-r--r-- 1 root root 2002 авг. 27 21:15 /etc/passwd
Повторю: каждый пользователь, изменяя свой пароль, вносит изменения в файл, недоступный ему для записи!
Для того, чтобы утилита passwd
могла изменять файл /etc/passwd
, процесс passwd
выполняется с правами эффективного пользователя - владельца исполняемого файла, а этим владельцем является root
:
ay@tsuki:~$ ls -l `which passwd`
-rwsr-xr-x 1 root root 47032 февр. 17 2014 /usr/bin/passwd
Буква s
в триаде user означает установленный атрибут setuid
. Помимо passwd
, имеются и другие файлы с установленным setuid
. Вот некоторые из них:
ay@tsuki:~$ ls -l /usr/bin/* | grep rws
-rwsr-xr-x 1 root root 46424 февр. 17 2014 /usr/bin/chfn
-rwsr-xr-x 1 root root 41336 февр. 17 2014 /usr/bin/chsh
-rwsr-xr-x 1 root root 68152 февр. 17 2014 /usr/bin/gpasswd
...
В /usr/bin
имеются также файлы с установленным setgid
:
ay@tsuki:~$ ls -l /usr/bin/* | egrep '^-.....s'
-rwxr-sr-x 1 root tty 14688 июня 5 2013 /usr/bin/bsd-write
-rwxr-sr-x 1 root shadow 54968 февр. 17 2014 /usr/bin/chage
-rwxr-sr-x 1 root crontab 35984 февр. 9 2013 /usr/bin/crontab
...
Назначение атрибутов setuid
и setgid
- дать возможность программе выполнять операции с файлами или каталогами, недоступные запускающему (реальному) пользователю. Отсюда - повышенное внимание к таким исполняемым файлам с точки зрения безопасности. Так, каждый из файлов, принадлежащих root
, у которых установлен setuid
, выполняется с эффективными правами root
!
Что если бы setuid
был установлен у файла /bin/rm
?
А если бы в системе отыскался файл, принадлежащий root
, с правами доступа -rwsrwxrwx
?
В качестве эксперимента с setuid
напишу скрипт come2party
для самозаписи пользователей на некое мероприятие. Файл с записями будет доступен для изменения только пользователю-владельцу скрипта - чтобы никто не мог вычеркнуть другого записавшегося.
Вначале подготовлю файл, в который будут записываться пользователи:
ay@tsuki:~$ touch come2party.lst
ay@tsuki:~$ chmod 644 come2party.lst
ay@tsuki:~$ ls -l come2party.lst
-rw-r--r-- 1 ay ay 0 сент. 9 19:42 come2party.lst
Теперь создам скрипт и установлю необходимые разрешения:
ay@tsuki:~$ cat > come2party
#!/bin/sh
echo $USER >> /home/ay/come2party.lst
^D
ay@tsuki:~$ chmod 4755 come2party
ay@tsuki:~$ ls -l come2party
-rwsr-xr-x 1 ay ay 95 сент. 9 19:43 come2party
Атрибуты setuid
, setgid
и sticky bit
кодируются 4-ой справа цифрой в восьмеричном представлении разрешений: 4 - setuid
, 2 - setgid
, 1 - sticky bit
. В статье Linux. Упражнения с rwx мы уже встречались с четырехразрядным восьмеричным представлением разрешений - когда воспользовались командой umask
.
Запишусь на вечеринку первым!
ay@tsuki:~$ come2party
ay@tsuki:~$ cat come2party.lst
ay
Теперь пусть запишется пользователь andrey
:
andrey@tsuki:~$ /home/ay/come2party
/home/ay/come2party: 2: /home/ay/come2party: cannot create /home/ay/come2party.lst: Permission denied
Неудача! Проверяю, что скрипт come2party
имеет установленный атрибут setuid
:
andrey@tsuki:~$ ls -l /home/ay/come2party
-rwsr-xr-x 1 ay ay 48 сент. 9 19:47 /home/ay/come2party
В чем же дело?
Оказывается, в Linux (и некоторых других ОС семейства Unix) атрибуты setuid
и setgid
для shell-скриптов не работают! Это ограничение связано с обеспечением безопасности.
На самом деле, скрипт come2party
, как и любой shell-скрипт, выполняется программой-интерпретатором /bin/sh
или иной, указанной в первой строке скрипта. Процесс, интерпретирующий скрипт, создается из двоичного исполняемого файла /bin/sh
(или иного), который не имеет установленных setuid
или setgid
и потому выполняется с правами запускающего пользователя:
andrey@tsuki:~$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 июля 26 20:15 /bin/sh -> dash
andrey@tsuki:~$ ls -l `which dash`
-rwxr-xr-x 1 root root 121272 февр. 19 2014 /bin/dash
andrey@tsuki:~$ ls -l `which bash`
-rwxr-xr-x 1 root root 1017016 апр. 24 09:43 /bin/bash
"Несамостоятельность" выполнения скрипта /home/ay/come2party
можно наглядно увидеть, если добавить в скрипт команду ps
, отображающую выполняемую командную строку. Добавив команду ps
, посмотрю на результат как пользователь andrey
:
andrey@tsuki:~$ cat /home/ay/come2party
#!/bin/sh
ps -o uid,user,gid,group,pid,command
echo $USER >> /home/ay/come2party.lst
andrey@tsuki:~$ /home/ay/come2party
UID USER GID GROUP PID COMMAND
1000 andrey 1000 andrey 3324 bash
1000 andrey 1000 andrey 3401 /bin/sh /home/ay/come2party
1000 andrey 1000 andrey 3402 ps -o uid,user,gid,group,pid,command
/home/ay/come2party: 3: /home/ay/come2party: cannot create /home/ay/come2party.lst: Permission denied
Из вывода команды ps
видно, что
-
скрипт
/home/ay/come2party
передан в качестве параметра интерпретатору/bin/sh
, - процесс выполняется с эффективными пользователем и группой, равными текущему пользователю и его первичной группе.
3401
процесс 3402
, исполняющий команду ps
, унаследовал эффективных пользователя и группу процесса-родителя.)
Чтобы реализовать задуманный сценарий с самозаписью пользователей на вечеринку, мне нужен бинарный исполняемый файл come2party
с установленным setuid
. Что же касается текстовых файлов, содержащих интерпретируемые скрипты (bash, python, perl и другие), то для них setuid
и setgid
Linux не поддерживает.
Вместо создания собственного бинарника я решил проделать следующий трюк под пользователем ay
:
- скопировать
/bin/bash
в домашний каталог, -
установить для
/home/ay/bash
атрибутsetuid
и -
прописать
/home/ay/bash
в первой строке скриптаcome2party
.
Тогда скрипт come2party
будет выполняться интерпретатором /home/ay/bash
с эффективным пользователем ay
, который сможет перенаправить вывод команды echo
в файл come2party.lst
!
ay@tsuki:~$ cp /bin/bash bash
ay@tsuki:~$ chmod u+s bash
ay@tsuki:~$ ls -l bash
-rwsr-xr-x 1 ay ay 1017016 сент. 9 20:23 bash
ay@tsuki:~$ cat > come2party
#!/home/ay/bash
echo $USER >> /home/ay/come2party.lst
^D
ay@tsuki:~$ ls -l come2party
-rwxr-xr-x 1 ay ay 57 сент. 9 20:25 come2party
Очищу come2party.lst
и запишусь первым:
ay@tsuki:~$ cat /dev/null > come2party.lst
ay@tsuki:~$ ls -l come2party.lst
-rw-r--r-- 1 ay ay 0 сент. 9 20:16 come2party.lst
ay@tsuki:~$ come2party
ay@tsuki:~$ cat come2party.lst
ay
Теперь пусть запишется пользователь andrey
:
andrey@tsuki:~$ /home/ay/come2party
/home/ay/come2party: 2: /home/ay/come2party: cannot create /home/ay/come2party.lst: Permission denied
Снова неудача!
Но этого не может быть: интерпретатор /home/ay/bash
, скрипт come2party
и файл come2party.lst
принадлежат ay
, и интепретатор выполняет скрипт с эффективными правами пользователя ay
! Проверю, так ли это, выполнив команду ps
при помощи домашнего bash
:
andrey@tsuki:~$ /home/ay/bash -c 'ps -o uid,user,gid,group,pid,command'
UID USER GID GROUP PID COMMAND
1000 andrey 1000 andrey 3599 bash
1000 andrey 1000 andrey 3751 ps -o uid,user,gid,group,pid,command
Как видим, bash
и порожденный им процесс ps
выполняются с эффективными пользователем и группой andrey
.
Получается, что атрибут setuid
не работает с bash
? Или вмешивается selinux
?
Google помог установить истину: виноват bash
. Оказывается, если реальный пользователь и эффективный пользователь запущенного процесса bash
оказываются разными, bash
принудительно устанавливает эффективного пользователя равным реальному. Аналогично он поступает и с эффективной группой процесса - ради безопасности и исключения злоупотреблений.
Однако, выход имеется. Ключ -p
позволяет отключить параноидальное поведение bash
и добиться желаемого:
andrey@tsuki:~$ /home/ay/bash -pc 'ps -o uid,user,gid,group,pid,command'
UID USER GID GROUP PID COMMAND
1002 ay 1000 andrey 3777 ps -o uid,user,gid,group,pid,command
Ура :)
Пусть теперь пользователь ay
изменит первую строчку скрипта /home/ay/come2party
, чтобы интерпретатор запускался с ключом -p
. Скрипт станет таким:
ay@tsuki:~$ cat come2party
#!/home/ay/bash -p
echo $USER >> /home/ay/come2party.lst
Теперь andrey
сможет, наконец, записаться на вечеринку:
andrey@tsuki:~$ /home/ay/come2party
andrey@tsuki:~$ cat /home/ay/come2party.lst
ay
andrey
Итак, мне удалось заставить setuid
работать с копией интерпретатора bash
, принадлежащей пользователю ay
. Но возможности bash
широки, и пользователь andrey
может теперь не только записаться на вечеринку, но и многое другое. Например, удалить файлы, принадлежащие ay
:
andrey@tsuki:~$ rm -f /home/ay/come2party.lst
rm: cannot remove ‘/home/ay/come2party.lst’: Permission denied
andrey@tsuki:~$ /home/ay/bash -pc 'rm -f /home/ay/come2party*'
andrey@tsuki:~$ ls -l /home/ay/come2party*
ls: cannot access /home/ay/come2party*: No such file or directory
Очевидно, что bash
с setuid
чертовски опасен для его владельца. Теперь я убежден, что setuid
не стоит раздавать каким угодно исполняемым файлам.
В данном случае опасность может быть ликвидирована с помощью ее самой:
andrey@tsuki:~$ /home/ay/bash -pc 'rm -f /home/ay/bash'
andrey@tsuki:~$ ls -l /home/ay/bash
ls: cannot access /home/ay/bash: No such file or directory
На этом я завершу эксперименты с setuid
для файлов, сделаю перерыв на кофе, и перейду к каталогам.
Из двух атрибутов setuid
и setgid
для каталогов в Linux используется только setgid
.
Установка атрибута setgid
для каталога приводит к тому, что файлы, создаваемые в этом каталоге, в качестве группы-владельца получают не первичную группу их создателя, а группу каталога. Файлы в каталоге как бы наследуют группу от каталога с атрибутом setgid
.
Такое поведение позволяет организовать совместную работу пользователей над общими файлами в каталоге, при условии, что все эти пользователи - члены группы-владельца каталога. Тогда все созданные в каталоге файлы доступны всем членам группы.
Поставлю эксперимент. Для начала, создам нового пользователя ya
, новую группу ayya
и добавлю в нее пользователей ay
и ya
.
andrey@tsuki:~$ sudo useradd -m ya
[sudo] password for andrey:
andrey@tsuki:~$ sudo passwd ya
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
andrey@tsuki:~$ sudo groupadd ayya
andrey@tsuki:~$ sudo usermod -aG ayya ay
andrey@tsuki:~$ sudo usermod -aG ayya ya
andrey@tsuki:~$ groups ay ya
ay : ay ayya
ya : ya ayya
Группа ayya
является вторичной группой (secondary group) для пользователей ay
и ya
, а их первичные группы - персональные группы ay
и ya
, соответственно. Вторичные группы используются только для получения доступа к существующим файлам и каталогам. Тогда как первичная группа устанавливается в качестве группы-владельца созданных пользователем файлов и каталогов.
Создам каталог, для которого установлю группу ayya
, полные разрешения для группы и атрибут setgid
.
ay@tsuki:~$ mkdir shared
ay@tsuki:~$ chgrp ayya shared
ay@tsuki:~$ chmod g+sw shared
ay@tsuki:~$ ls -ld shared
drwxrwsr-x 2 ay ayya 4096 авг. 30 18:08 shared
Создам файл в этом каталоге как пользователь ay
:
ay@tsuki:~$ echo It\'s $USER > ~ay/shared/created_by_$USER.txt
А теперь, как пользователь ya
, создам там же другой файл и изменю файл, созданный пользователем ay
:
ya@tsuki:~$ echo It\'s $USER > ~ay/shared/created_by_$USER.txt
ya@tsuki:~$ ls -l ~ay/shared
total 8
-rw-rw-r-- 1 ay ayya 8 авг. 30 18:11 created_by_ay.txt
-rw-rw-r-- 1 ya ayya 8 авг. 30 18:12 created_by_ya.txt
ya@tsuki:~$ echo It\'s $USER >> ~ay/shared/created_by_ay.txt
ya@tsuki:~$ cat ~ay/shared/created_by_ay.txt
It's ay
It's ya
Как видим, созданные в каталоге ~ay/shared
файлы наследуют группу-владельца от каталога и доступны членам этой группы для изменения. setgid
для каталога работает согласно теории!
Наконец, последний предмет для экспериментирования сегодня - атрибут sticky bit
.
Как рассказывает Википедия, когда-то в ОС семейства Unix "липкий бит" использовался для удержания кода исполняемых файлов в свопе - для их быстрого повторного запуска. Но эта практика осталась в прошлом, и в Linux данный атрибут используется только с каталогами.
В Linux установленный для каталога sticky bit
запрещает удаление и переименование файлов в этом каталоге всем, кроме root
, владельца каталога и владельцев соответствующих файлов. Этот запрет работает независимо от разрешений каталога и имеет приоритет над ними.
Так, каталог /tmp
имеет полные разрешения, в него пишут все, но не могут удалить чужие файлы и тем помешать работе других пользователей:
$ ls -ld /tmp
drwxrwxrwt 7 root root 4096 Apr 17 15:55 /tmp
Поставлю эксперимент, дав всем пользователям полный доступ в каталог /home/ay/dummy
:
ay@tsuki:~$ chmod 777 dummy
ay@tsuki:~$ ls -ld dummy
drwxrwxrwx 2 ay ay 4096 авг. 27 22:55 dummy
Теперь пользователи andrey
и ya
создадут файлы в этом каталоге, после чего ya
беспрепятственно удалит как свой, так и чужой файлы:
andrey@tsuki:~$ echo Hello > /home/ay/dummy/andrey\'s
andrey@tsuki:~$ ls -l /home/ay/dummy
total 4
-rw-rw-r-- 1 andrey andrey 6 сент. 9 22:13 andrey's
andrey@tsuki:~$ su - ya
Password:
ya@tsuki:~$ echo Hello > /home/ay/dummy/ya\'s
ya@tsuki:~$ ls -l /home/ay/dummy
total 8
-rw-rw-r-- 1 andrey andrey 6 сент. 9 22:13 andrey's
-rw-rw-r-- 1 ya ya 6 сент. 9 22:13 ya's
ya@tsuki:~$ rm -f /home/ay/dummy/*
ya@tsuki:~$ ls -l /home/ay/dummy
total 0
Теперь установлю на /home/ay/dummy
атрибут sticky bit
:
ay@tsuki:~$ chmod +t dummy
ay@tsuki:~$ ls -ld dummy
drwxrwxrwt 2 ay ay 4096 сент. 9 22:14 dummy
Пользователи andrey
и ya
снова создадут файлы в этом каталоге и ya
попытается удалить чужой файл:
andrey@tsuki:~$ echo Hello > /home/ay/dummy/andrey\'s
andrey@tsuki:~$ ls -l /home/ay/dummy
total 4
-rw-rw-r-- 1 andrey andrey 6 сент. 9 22:15 andrey's
andrey@tsuki:~$ su - ya
Password:
ya@tsuki:~$ echo Hello > /home/ay/dummy/ya\'s
ya@tsuki:~$ ls -l /home/ay/dummy
total 8
-rw-rw-r-- 1 andrey andrey 6 сент. 9 22:15 andrey's
-rw-rw-r-- 1 ya ya 6 сент. 9 22:15 ya's
ya@tsuki:~$ rm -f /home/ay/dummy/andrey\'s
rm: cannot remove ‘/home/ay/dummy/andrey's’: Operation not permitted
Не получается! Так работает sticky bit
.
Теперь удалю файлы как владелец каталога:
ay@tsuki:~$ rm -f dummy/*
ay@tsuki:~$ ls -l dummy
total 0
Кстати, сценарий самозаписи на вечеринку можно реализовать с помощью каталога с установленным "липким" битом. Для записи на вечеринку пользователи будут создавать файл с именем пользователя в таком каталоге. Другие пользователи не смогут удалить чужие файлы из этого каталога, а значит, не смогут "вычеркнуть" записавшихся ранее. Такое решение позволяет обойтись без использования setuid
(и не требует создания бинарного файла специально для этого случая).
В заключение, удалю пользователей и группу, использовавшиеся для экспериментов:
andrey@tsuki:~$ sudo groupdel ayya
[sudo] password for andrey:
andrey@tsuki:~$ sudo userdel ay
andrey@tsuki:~$ sudo userdel ya
andrey@tsuki:~$ sudo rm -Rf /home/ay /home/ya
Интересно, а возможно ли на samba 4 реализовать к шаре следующий двойственный вариант доступа: чтобы под одним пользователем можно было войти с логином и паролем с полным доступом ко всем папкам(подпапкам) и файлам в шаре. В то же время, в этой же шаре был публичный доступ только на чтение (выполнение) без возможности правки, за исключением только файлов в одной конкретной подпапке?
ОтветитьУдалитьНет ли у вас мануала по реализации что-то подобного?
Увы, с самбой не разбирался.
ОтветитьУдалитьНу с самбу худо-бедно попробую победить сам. Те доступы и права что требуется, все-равно должно решаться чисто путем настройки правильных доступов для пользователей. А именно...
ОтветитьУдалитьЕсть в системе user1 и user2 и общая папка. Надо, чтобы user1 имел полный доступ на все подпапки и файлы. А user2 только чтение-выполнение на все подпапки и файлы, кроме одной конкретной подпапки FOLDER, где должна быть полные права у обоих пользователей. Причем user2 не должен смочь переименовать и удалять эту подпапку.
Есть соображения как это возможно реализовать?