Лабораторная работа "Управление процессами" - efanov/mephi GitHub Wiki

Содержание

Цель

Изучить свойства процессов и командный интерфейс управления процессами. Изучить механизм привилегий (capabilities).

Команды, изучаемые в лабораторной работе: ps, top, pgrep, pstree, w, uptime, jobs, fg, bg, kill, killall, pkill, trap, getcap, setcap.

Процессы

Изучение команды ps

  1. Выведите информацию обо всех процессах в системе, используя стандартный синтаксис:

      $ ps -e
      $ ps -ef
      $ ps -eF
      $ ps -ely
    
  2. Выведите информацию обо всех процессах в системе, используя синтаксис BSD:

      $ ps ax
      $ ps axu
    
  3. Выведите информацию обо всех процессах в системе в виде дерева:

      $ ps -ejH
      $ ps axjf
    
  4. Выведите информацию о легковесных процессах:

      $ ps -eLf
      $ ps axms
    
  5. Выведите атрибуты безопасности процессов:

      $ ps -eo euser,ruser,suser,fuser,f,comm,label
      $ ps axZ
      $ ps -eM
    
  6. Выведите информацию о процессах, выполняющихся от имени пользователя root (real & effective ID), в пользовательском формате:

      $ ps -U root -u root u
    
  7. Выведите информацию о процессах в пользовательском формате:

      $ ps -eo pid,tid,class,rtprio,ni,pri,psr,pcpu,stat,wchan:14,comm
      $ ps axo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm
      $ ps -Ao pid,tt,user,fname,tmout,f,wchan
    
  8. Выведите только идентификаторы процессов с именем systemd:

      $ ps -C systemd -o pid=
    
  9. Выведите только имя процесса с идентификатором номер:

      $ ps -q номер -o comm=
    

Выполнение процесса в основном и фоновом режимах

  1. Откройте два окна терминала (левый и правый).

  2. В левом окне запустите бесконечный процесс, который с интервалом в одну секунду будет писать строку AAA в файл test.out в домашнем каталоге.

      $ ( while true; do printf "AAA %d " $$ >> ~/test.out; sleep 1; done )
    
  3. В правом окне наблюдайте за работой процесса.

      $ tail -f ~/test.out
    
  4. В левом окне остановите процесс. BASH вернет номер задания в квадратных скобках. Убедитеь, что процесс перестал писать в файл.

      $ Ctrl+z
    
  5. В левом окне выведите список заданий. Знаком + помечено текущее задание. Определите состояние процесса. Запустите задание в фоновом режиме. Убедитеь, что процесс снова продолжил писать в файл. Определите состояние процесса ещё раз.

      $ jobs
      $ ps j
      $ bg
      $ jobs
      $ ps j
    
  6. В левом окне запустите второй бесконечный процесс в фоновом режиме, который с интервалом в одну секунду будет писать строку UUU в файл test.out в домашнем каталоге. Команда должна быть заключена в круглые скобки и заканчиваться знаком &.

      $ ( while true; do printf "UUU %d " $$ >> ~/test.out; sleep 1; done ) &
    
  7. В левом окне выведите список заданий. Убедитеь, что теперь два процесса пишут в файл.

      $ jobs
    
  8. В левом окне завершите процессы.

      $ fg %номер
      $ Ctrl+c
      $ fg %номер
      $ Ctrl+c
    
  9. В правом окне завершите команду tail.

Посылка сигналов процессам

  1. Откройте два окна терминала (левый и правый).

  2. В левом окне запустите два бесконечных процесса, которые с интервалом в одну секунду будут писать строки в файл test.out в домашнем каталоге. Выведите список заданий (наблюдайте Running). Определите состояние процессов.

      $ ( while true; do printf "AAA %d " $$ >> ~/test.out; sleep 1; done ) &
      $ ( while true; do printf "UUU %d " $$ >> ~/test.out; sleep 1; done ) &
      $ jobs
      $ ps j
    
  3. В правом окне наблюдайте за работой процессов.

      $ tail -f ~/test.out
    
  4. В левом окне остановите первый процесс (задание "AAA"). Выведите список заданий (наблюдайте Stopped).

      $ kill -SIGSTOP %1
      $ jobs
    
  5. В левом окне завершите второй процесс (задание "UUU"). Выведите список заданий (наблюдайте Terminated).

      $ kill -SIGTERM %2
      $ jobs
    
  6. В левом окне завершите процесс.

      $ fg
      $ Ctrl+c
    
  7. В правом окне завершите команду tail.

Изучение команд trap и sleep

Команда trap позволяет установить обработчик на сигнал. Опция -l выводит список сигналов. Опция -p выводит установленные обработчики сигналов.

  1. Выведите список сигналов.

      $ trap -l
       1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
       6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
      11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
      16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
      21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
      26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
      31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
      38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
      43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
      48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
      53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
      58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
      63) SIGRTMAX-1	64) SIGRTMAX
    
  2. Запустите дочерний shell и установите обработчик сигнала EXIT (0, который посылается нажатием Ctrl+d).

      $ sh
      sh-4.3$ trap 'echo Завершение работы...; sleep 2' EXIT
      sh-4.3$ trap -p EXIT
      trap -- 'echo Завершение работы...; sleep 2' EXIT
    
  3. Завершите shell.

      $ Ctrl+d
    
  4. Наблюдайте перехват сигнала и вызов обработчика.

  5. Создайте сценарий.

      $ cat test-trap.sh
      #!/bin/bash
      declare -i i=0
      trap 'echo "Аварийное завершение..."; exit 1' SIGINT
      while [ $i -lt 100 ]
      do
      	(( i++ ))
      	echo $i
      	sleep 1
      done
    
  6. Запустите сценарий.

      $ chmod +x test-trap.sh
      $ ./test-trap.sh
    
  7. Завершите сценарий. Объясните результаты.

      $ Ctrl+c
    

Изучение возможностей файловых систем procfs и sysfs

  1. Изучите содержимое файла /proc/version и сравните с выводом команды uname -a.

  2. Изучите и сравниет содержимое файлов /proc/meminfo и /sys/devices/system/node/node0/meminfo, и вывод команды free.

  3. Изучите содержимое файла /proc/cpuinfo. Определите количество ядер.

  4. Изучите содержимое файла /proc/uptime и сравните с выводом команды uptime.

  5. Изучите специальную символьную ссылку /proc/self, которая указывает на подкаталог текущего процесса. В переменной $ хранится PID текущего процесса. Объясните результаты.

      $ echo $$
      3203
      $ ls -l /proc/self
      lrwxrwxrwx. 1 root root 0 Oct 13 21:42 /proc/self -> 12485
      $ ls -ld /proc/$$
      dr-xr-xr-x. 9 defanov defanov 0 Oct 13 18:58 /proc/3203
    
  6. Изучите содержимое файла /proc/PID_процесса/stat. Формат вывода можно посмотреть в исходном коде ядра Linux в файле /fs/proc/array.c в функции do_task_stat().

      $ read pid tcomm state other < /proc/$$/stat
      $ echo "Процесс $pid $tcomm находится в состоянии $state"
      Процесс 3203 (bash) находится в состоянии R
    

Работа процесса с файлами

  1. Изучите различные формы обращения к файловым дескрипторам и потокам stdin, stdout, stderr.

      $ ls -l /dev/std*
      lrwxrwxrwx. 1 root root 15 Oct 13 21:42 /dev/stderr -> /proc/self/fd/2
      lrwxrwxrwx. 1 root root 15 Oct 13 21:42 /dev/stdin -> /proc/self/fd/0
      lrwxrwxrwx. 1 root root 15 Oct 13 21:42 /dev/stdout -> /proc/self/fd/1
      $ ls -l /dev/fd/
      total 0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 0 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 1 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 2 -> /dev/pts/0
      lr-x------. 1 defanov defanov 64 Oct 14 00:31 3 -> /proc/13123/fd
    
  2. Изучите список открытых файлов процесса. Определите потоки stdin, stdout, stderr.

      $ ls -l /proc/self/fd
      total 0
      lrwx------. 1 defanov defanov 64 Oct 14 00:07 0 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:07 1 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:07 2 -> /dev/pts/0
      lr-x------. 1 defanov defanov 64 Oct 14 00:07 3 -> /proc/12898/fd
    
  3. Перенаправьте потоки stdout и stderr в файлы. Объясните результаты.

      [defanov@dimix /]$ ls -l /proc/self/fd > /tmp/ls.out 2> /tmp/ls.err
      [defanov@dimix /]$ cat /tmp/ls.out 
      total 0
      lrwx------. 1 defanov defanov 64 Oct 14 00:09 0 -> /dev/pts/0
      l-wx------. 1 defanov defanov 64 Oct 14 00:09 1 -> /tmp/ls.out
      l-wx------. 1 defanov defanov 64 Oct 14 00:09 2 -> /tmp/ls.err
      lr-x------. 1 defanov defanov 64 Oct 14 00:09 3 -> /proc/12915/fd
    
  4. Перенаправьте поток stdin. Объясните права доступа.

Исследование взаимодействия параллельных процессов через каналы

  1. Откройте два окна терминала (левый и правый).

  2. В левом окне запустите конвейер, перенаправьте потоки stdout и stderr в файлы в домашнем каталоге.

      $ ( cat | head ) > ~/test.out 2> ~/test.err
    
  3. В правом окне выведите списки открытых файлов процессов bash, cat и head.

      $ ps j
       PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
      13700 13704 13704 13704 pts/0    13881 Ss    1000   0:00 bash
      13700 13746 13746 13746 pts/1    13884 Ss    1000   0:00 bash
      13704 13881 13881 13704 pts/0    13881 S+    1000   0:00 bash
      13881 13882 13881 13704 pts/0    13881 S+    1000   0:00 cat
      13881 13883 13881 13704 pts/0    13881 S+    1000   0:00 head
      13746 13884 13884 13746 pts/1    13884 R+    1000   0:00 ps j
      $ ls -l /proc/13881/fd
      total 0
      lrwx------. 1 defanov defanov 64 Oct 14 01:31 0 -> /dev/pts/0
      l-wx------. 1 defanov defanov 64 Oct 14 01:31 1 -> /home/defanov/test.out
      l-wx------. 1 defanov defanov 64 Oct 14 01:30 2 -> /home/defanov/test.err
      lrwx------. 1 defanov defanov 64 Oct 14 01:31 255 -> /dev/pts/0
      $ ls -l /proc/13882/fd
      total 0
      lrwx------. 1 defanov defanov 64 Oct 14 01:30 0 -> /dev/pts/0
      l-wx------. 1 defanov defanov 64 Oct 14 01:30 1 -> pipe:[173460]
      l-wx------. 1 defanov defanov 64 Oct 14 01:30 2 -> /home/defanov/test.err
      $ ls -l /proc/13883/fd
      total 0
      lr-x------. 1 defanov defanov 64 Oct 14 01:30 0 -> pipe:[173460]
      l-wx------. 1 defanov defanov 64 Oct 14 01:30 1 -> /home/defanov/test.out
      l-wx------. 1 defanov defanov 64 Oct 14 01:30 2 -> /home/defanov/test.err
    
  4. Изучите как поток stdout процесса cat связан с потоком stdin процесса head.

  5. В левом окне завершите процессы.

  6. В левом окне создайте именованный канал и запустите команду cat с перенаправлением вывода в созданный канал.

      $ mkfifo ~/fifo1
      $ cat > ~/fifo1
    
  7. В правом окне запустите команду cat с перенаправлением ввода из канала.

      $ cat < ~/fifo1
    
  8. Откройте новое окно терминала, в котором выведите списки открытых файлов двух процессов cat.

  9. В новом (третьем) окне запустите команду cat с перенаправлением ввода из канала.

      $ cat < ~/fifo1
    
  10. В левом окне вводите строки текста и наблюдайте вывод в двух других окнах. Объясните результаты.

  11. Организуйте чтение из канала в бесконечном цикле while с помощью команды read.

  12. Завершите процессы.

Изучение команды exec

Команда exec используется для двух целей: запуск программ и открытие файлов.

  1. Запустите дочерний shell и заместите коды порожденного процесса кодами команды ps -l. Обратите внимание на то, что PID процесса sh совпадает с PID процесса ps (13028). Объясните результаты.

      $ sh
      sh-4.3$ ps -l
      F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
      0 S  1000  3203  3197  0  80   0 - 29691 wait   pts/0    00:00:00 bash
      0 S  1000 13028  3203  0  80   0 - 28960 wait   pts/0    00:00:00 sh
      0 R  1000 13030 13028  0  80   0 - 34450 -      pts/0    00:00:00 ps
      sh-4.3$ exec ps -l
      F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
      0 S  1000  3203  3197  0  80   0 - 29691 wait   pts/0    00:00:00 bash
      0 R  1000 13028  3203  0  80   0 - 34450 -      pts/0    00:00:00 ps
      $ ps -l
      F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
      0 S  1000  3203  3197  0  80   0 - 29691 wait   pts/0    00:00:00 bash
      0 R  1000 13034  3203  0  80   0 - 34450 -      pts/0    00:00:00 ps
    
  2. Исследуйте работу процесса с файлами на примере bash. Откройте файл ~/test.out на запись и свяжите его с дескриптором 3.

      $ exec 3> ~/test.out
      $ ls -l /proc/$$/fd
      total 0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 0 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 1 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:21 2 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 13 21:30 255 -> /dev/pts/0
      l-wx------. 1 defanov defanov 64 Oct 14 00:31 3 -> /home/defanov/test.out
      $ echo Test
      Test
      $ echo Test3 >&3
      $ cat ~/test.out 
      Test3
      $ echo Test333 >&3
      $ cat ~/test.out 
      Test3
      Test333
    
  3. Выведите информацию об открытых файлах процесса bash. Объясните позицию указателя чтения/записи (pos: 14).

      $ echo $$
      3203
      $ ls -l /proc/3203/fdinfo/
      total 0
      -r--------. 1 defanov defanov 0 Oct 13 21:30 0
      -r--------. 1 defanov defanov 0 Oct 13 21:30 1
      -r--------. 1 defanov defanov 0 Oct 13 21:30 2
      -r--------. 1 defanov defanov 0 Oct 13 21:30 255
      -r--------. 1 defanov defanov 0 Oct 14 00:40 3
      $ cat /proc/3203/fdinfo/3 
      pos:	14
      flags:	0100001
      mnt_id:	82
    
  4. Откройте файл ~/test.out на чтение и свяжите его с дескриптором 4.

      $ exec 4< ~/test.out 
      $ ls -l /proc/$$/fd
      total 0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 0 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 1 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:21 2 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 13 21:30 255 -> /dev/pts/0
      l-wx------. 1 defanov defanov 64 Oct 14 00:31 3 -> /home/defanov/test.out
      lr-x------. 1 defanov defanov 64 Oct 14 00:54 4 -> /home/defanov/test.out
      $ cat ~/test.out 
      Test3
      Test333
      $ cat <&4
      Test3
      Test333
      $ cat ~/test.out 
      Test3
      Test333
      $ cat <&4
      $
      $ echo Test4 >&3
      $ cat ~/test.out 
      Test3
      Test333
      Test4
      $ cat <&4
      Test4
      $ cat <&4
      $
    
  5. Удалите файл ~/test.out.

      $ rm ~/test.out 
      $ ls -l /proc/$$/fd
      total 0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 0 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:31 1 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 14 00:21 2 -> /dev/pts/0
      lrwx------. 1 defanov defanov 64 Oct 13 21:30 255 -> /dev/pts/0
      l-wx------. 1 defanov defanov 64 Oct 14 00:31 3 -> /home/defanov/test.out (deleted)
      lr-x------. 1 defanov defanov 64 Oct 14 00:54 4 -> /home/defanov/test.out (deleted)
    
  6. Попробуйте вывести содержимое файла ~/test.out командой cat, используя два способа обращения к файлу: через дескриптор и через имя. Объясните результат.

Разработка сценария

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

Для тестирования можно использовать программу passwd.

Контрольные вопросы по теме процессов

  1. Что происходит при прерывании скрипта text-trap.sh? Объясните, почему.
  2. Напишите, по какой причине выводы команды ls -l /proc/self и ls -l /proc/$$ отличаются?
  3. Напишите, какие дескрипторы в выводе команды ls -l /proc/self/fd отвечают за stdin, stdout, stderr.
  4. Что происходит с дескрипторами при перенаправлении потоков stdout и stderr в файлы при выполнении команды ls -l /proc/self/fd > /tmp/ls.out 2> /tmp/ls.err?
  5. Запишите эту же команду, добавив к ней перенаправление потока stdin. Что изменилось?
  6. Какой эффект наблюдается при выполнении команды exec ps -l?
  7. Что означает pos при выводе содержимого файла /proc/$$/fdinfo/3?
  8. Существует ли возможность читать содержимое файла test.out даже после его удаления? Почему так происходит?

Привилегии (capabilities)

Привилегии процесса

Механизм привилегий (capabilities) позволяет разделить неограниченные права суперпользователя (у которого EUID == 0) по администрированию системы на отдельные группы прав, которые могут быть независимо друг от друга предоставлены обычным пользователям (у которых EUID != 0). Этим достигается реализация принципа наименьших привилегий, а также уменьшается поверхность атаки: если программа, обладающая одной или более привилегиями скомпрометирована, ее возможности по нанесению ущерба системе будут меньше по сравнению с такой же программой, выполняющейся с EUID == 0.

Каждый процесс обладает пятью 64-битными векторами привилегий. Эти векторы хранятся в структуре cred, на которую ссылается указатель из дескриптора процесса task_struct.

Рассмотрим фрагмент структуры cred:

struct cred {
    // ...
    kernel_cap_t cap_inheritable;
    kernel_cap_t cap_permitted;
    kernel_cap_t cap_effective;
    kernel_cap_t cap_bset;
    kernel_cap_t cap_ambient;
    // ...
}
  • Наследуемый вектор (inheritable) — привилегии, которые сохраняются при выполнении вызова execve. Наследуемые привилегии остаются наследуемыми при выполнении любой программы. Наследуемые привилегии добавляются к разрешенному набору при выполнении программы, у которой есть соответствующие биты в наследуемом наборе файла.
  • Разрешенный вектор (permitted) — максимальный набор привилегий, которые может использовать процесс (является надмножеством эффективного набора). Это также максимальный набор привилегий, которые могут быть добавлены в наследуемый набор процессом, не имеющим привилегию CAP_SETPCAP в своем эффективном наборе. Если процесс удаляет привилегию из своего разрешенного набора, он никогда не сможет повторно получить эту возможность. Исключения составляют случаи запуска в процессе программы с установленным битом SUID или программы с установленной привилегией на исполняемый файл.
  • Эффективный вектор (effective) – набор привилегий, используемый ядром при выполнении проверок доступа для процесса (permission checks).
  • Ограничивающий вектор (bounding) – механизм, который может использоваться для ограничения привилегий, получаемых во время вызова execve.
  • Внешний вектор (ambient) – привилегии, которые сохраняются при выполнении вызова execve привилегированной программой. Привилегия может быть внешней, если она одновременно разрешенная и наследуемая. Внешние привилегии автоматически сбрасываются, если соответствующая разрешенная или наследуемая привилегия сбрасывается.

Посмотреть привилегии процесса можно в файле /proc/<pid>/status. Рассмотрим на примере обычного пользователя user1 привилегии процесса cat:

id
# Вывод:
# uid=1001(user1) gid=1001(user1) groups=1001(user1) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

cat /proc/self/status | grep ^Cap
# Вывод:
# CapInh: 0000000000000000
# CapPrm: 0000000000000000
# CapEff: 0000000000000000
# CapBnd: 000001ffffffffff
# CapAmb: 0000000000000000

capsh --print
# Вывод:
# Current: =
# Bounding set =cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read,38,39,40
# Ambient set =
# Securebits: 00/0x0/1'b0
# secure-noroot: no (unlocked)
# secure-no-suid-fixup: no (unlocked)
# secure-keep-caps: no (unlocked)
# secure-no-ambient-raise: no (unlocked)
# uid=1001(user1)
# gid=1001(user1)
# groups=1001(user1)

capsh --decode=0000000000000001
# Вывод:
# 0x0000000000000001=cap_chown

Для исследования и конструирования наборов привилегий предназначена команда capsh. Системные вызовы capget и capset позволяют процессу манипулировать собственными векторами привилегий.

Привилегии файла

Привилегии также можно связать с исполняемым файлом с помощью команды setcap. Привилегии файла хранятся в его расширенных атрибутах в пространстве security.capability. Запись в этот расширенный атрибут требует наличия привилегии CAP_SETFCAP.

Суперпозиция привилегий исполняемого файла и привилегий вызывающего процесса определяет привилегии процесса после выполнения системного вызова execve.

Существует три набора привилегий файла:

  • разрешенный набор (permitted) — эти привилегии автоматически разрешаются процессу, независимо от наследуемых привилегий процесса;
  • наследуемый набор (inheritable) — логически перемножается с наследуемым набором процесса (операция логического «И»), чтобы определить, какие наследуемые привилегии должны быть включены в разрешенном наборе процесса после вызова execve;
  • эффективный бит (effective). Если этот бит установлен, то во время выполнения вызова execve все новые разрешенные привилегии процесса также поднимаются в векторе эффективных привилегий. Если этот бит не установлен, то после execve никаких новых разрешенных привилегий нет в новом эффективном наборе.

Во время выполнения вызова execve ядро вычисляет новые привилегии процесса по следующему алгоритму:

P'(ambient)     = (файл привилегированный) ? 0 : P(ambient)
P'(permitted)   = (P(inheritable) & F(inheritable)) | (F(permitted) & P(bounding)) | P'(ambient)
P'(effective)   = F(effective) ? P'(permitted) : P'(ambient)
P'(inheritable) = P(inheritable) [не изменяется]
P'(bounding)    = P(bounding) [не изменяется]

где P() – привилегии процесса до вызова execve; P'() – привилегии процесса после вызова execve; F() – привилегии исполняемого файла.

Относительно механизма привилегий программы можно разделить на две группы:

  • программы, использующие привилегии, которые скомпилированы с библиотекой libcap (можно посмотреть с помощью команды ldd);
  • программы, не использующие механизм привилегий (capability-dumb).

Рассмотрим привилегии исполняемого файла на примере команды cat. Пусть обычный пользователь попытается вывести на экран содержимое файла /etc/shadow, в котором хранятся хэши паролей пользователей, и который доступен только пользователю root:

whereis -b cat
# Вывод:
# cat: /usr/bin/cat

ldd /usr/bin/cat
# Вывод:
# linux-vdso.so.1 (0x00007ffc48c74000)
# libc.so.6 => /lib64/libc.so.6 (0x00007f5304859000)
# /lib64/ld-linux-x86-64.so.2 (0x00007f5304a4a000)

cat /etc/shadow
# Вывод:
# cat: /etc/shadow: Permission denied

Видно, что в выводе команды ldd отсутствует библиотека libcap. Это означает, что программа cat не умеет управлять своими привилегиями, т.е. разработчик программы cat не использовал API библиотеки libcap для обращения к механизму привилегий.

Создадим копию программы cat и с помощью команды setcap установим для нее привилегию cap_dac_read_search. Так как cat является capability-dumb-программой, то необходимо установить оба набора привилегий (=pe) у исполняемого файла: разрешенный (p) и эффективный (e). Если бы программа cat умела управлять своими привилегиями, то было бы достаточно установить только разрешенный (p) набор привилегий. Команда getcap показывает, что привилегия установлена.

cp /usr/bin/cat .

sudo setcap "cap_dac_read_search=ep" cat

getcap ./cat
# Вывод:
# ./cat = cap_dac_read_search+ep

./cat /etc/shadow | head -n 1
# Вывод:
# root:!::0:99999:7:::

Теперь обычный пользователь может прочитать содержимое любого файла в системе, независимо от установленных для этого файла дискреционных прав доступа, т.е. может обходить механизм DAC по чтению.

Допуск

  1. Как запустить программу в фоновом режиме?
  2. Что такое сигналы и зачем они нужны?
  3. Какие системные вызовы используются для создания нового процесса?
  4. Что такое привилегии и для чего они нужны?
  5. Что такое зомби-процессы?

Порядок защиты работы

Для защиты работы необходимо ответить на вопросы по теме работы.

⚠️ **GitHub.com Fallback** ⚠️