Sd pam linux что это
Перейти к содержимому

Sd pam linux что это

  • автор:

Посторонним вход воспрещен

Тебе никогда не приходила в голову мысль о том, что идея использовать логин и пароль для входа в систему несколько устарела? Почему, имея в одном кармане флешку, в другом — телефон, а на компе установленный SSH с настроенной авторизацией при помощи ключей, мы продолжаем вводить эти запутанные пароли?

Пароли и учетные записи были придуманы в эпоху больших мейнфреймов, движения хиппи, войны в Афганистане и больших аналоговых магнитофонов, самым технологичным компонентом из которых были транзисторы. В те времена использование паролей для входа в мейнфрейм выглядело действительно круто. Можно было придумать комбинацию вроде sexhero или iamsuperman и действительно гордиться собой.
Сегодня же пароли выглядят не только архаичной, но и ужасно неудобной вещью, старые понтовые комбинации уже не работают, и вместо них приходится придумывать зубодробительные наборы символов, которые не только нереально запомнить, но и проблематично ввести с первого раза. Мы живем в XXI веке, имеем доступ к огромному количеству гаджетов и технических средств, которые предлагают гораздо более простой и качественный механизм аутентификации, но продолжаем вбивать пароли, матерясь на всю квартиру при каждой неудачной попытке войти в систему. Пора это исправить.
В этой статье я расскажу о том, как раз и навсегда избавиться от паролей и превратить свой комп в по-настоящему технологичное устройство, для входа в которое будет достаточно вставить флешку, взглянуть в веб-камеру или просто положить на стол сотовый телефон.

Высокотехнологичный ключ

Ключ — самый простой и эффективный метод защиты чего бы то ни было. Мы пользуемся ключами ежедневно: для включения двигателя автомобиля, для входа в квартиру, для отпирания ящиков и шкафов. Ключи удобны и просты в изготовлении, благодаря современным программируемым замкам их не страшно потерять. Множество раз человечество пыталось придумать замену ключам, но все попытки провалились (все мы помним, к чему привела идея использовать кодовые замки на подъездных дверях). Почему же мы не используем столь хорошую и проверенную временем технологию для защиты компьютеров?
Современный аналог ключа — USB-флешка. Вне зависимости от того, для каких целей ты обычно используешь флешку, из нее всегда можно сделать полноценный высокотехнологичный ключ, с помощью которого войти в систему будет так же легко, как отпереть дверь в квартиру.
Есть несколько способов сделать это, но наиболее простой и универсальный метод — это использовать PAM-модуль pam_usb, который будет проверять каждую вставленную в комп флешку на предмет ее соответствия указанным требованиям и, в зависимости от результата, разблокировать или блокировать учетную запись пользователя.
Никакой модификации таблицы разделов или информации, хранимой на флешке, при этом не потребуется. Для идентификации «правильной» флешки используется ее серийный номер, модель, производитель, а также набор случайных данных, которые записываются в резервную область флешки и изменяются при каждой удачной аутентификации (если кто-то скопирует твою флешку, но ты успеешь войти в систему раньше злоумышленника, данные будут изменены, и его копия уже не сработает). В случае утери всегда останется возможность войти в систему, используя пароль, и перекодировать pam_usb на новую флешку. Также в качестве ключа можно использовать различные карты памяти (SD, MMC) и другие съемные накопители.
Начать использовать pam_usb довольно просто. Полная настройка системы состоит из пяти шагов.

1. Ставим библиотеку libpam_usb.so и утилиты управления модулем:

$ sudo apt-get install libpam-usb pamusb-tools

2. Берем флешку, которую собираемся использовать в качестве ключа, вставляем ее в USB-порт и выполняем следующую команду:

$ sudo pamusb-conf —add-device имя

Так pam_usb соберет всю необходимую информацию о флешке, добавит в свою базу данных и запишет 2 Кб случайных данных. Для поиска флешки в системе будет использован Udisks (аргумент «имя» здесь используется, чтобы дать флешке произвольное название, а не для указания ее файла-устройства), так что важно, чтобы другие внешние накопители на время работы этой команды были отключены.

3. Теперь даем pam_usb понять, чтобы эта флешка была ассоциирована с нужной нам учетной записью (путь это будет vasya):

$ sudo pamusb-conf —add-user vasya

4. Запускаем проверку правильности собранных данных на случай, если флешка не была корректно идентифицирована. Или мы забыли отсоединить какой-то другой накопитель, и он был использован вместо нужного нам:

$ sudo pamusb-check vasya

5. Добавляем pam_usb в список модулей, необходимых для проведения успешной аутентификации пользователя. В Ubuntu и других дистрибутивах, основанных на Debian, это делается с помощью модификации файла /etc/pam.d/common-auth. В нем необходимо найти строку примерно следующего вида (она может отличаться): auth required pam_unix.so . И прямо перед ней добавить следующую строку: auth sufficient pam_usb.so .
Так мы сообщим PAM, что перед логином любого пользователя нужно отдавать управление модулю pam_usb, который проверит наличие нужной флешки, и лишь в случае неудачи этой операции запрашивать пароль. Поэтому, если ты хочешь впускать пользователя только по флешке, полностью блокируя аккаунт в случае неудачи, слово «sufficient» следует заменить словом «required».
В принципе, всего этого должно быть достаточно для того, чтобы система просто работала (попытайся выйти и войти, чтобы это проверить), однако функциональность pam_usb можно несколько расширить, если использовать демон pamusb-agent.
Задача pamusb-agent — автоматизировать работу по блокированию и разблокированию учетной записи пользователя при извлечении и втыкании флешки в комп. Чтобы агент заработал, необходимо добавить в конфигурационный файл /etc/pamusb.conf следующие строки:

Это рецепт для Gnome. Чтобы использовать pamusb-agent с другими средами, команды «gnome-screensaver-command —lock» и «gnome-screensaver-command —deactivate» необходимо изменить.
Теперь можно запустить pamusb-agent и проверить его работоспособность:

Если все работает нормально, можно добавить его в автозапуск:

$ cd ~/.config/autostart
$ ln -s /usr/bin/pamusb-agent pamusb-agent

Обкатаем пальчики?

Модуль pam_usb удобно использовать в качестве метода защиты ноутбуков, оснащенных кард-ридером. Можно носить небольшую SD-карту в кошельке или внутреннем кармане и втыкать ее в ноутбук, не беспокоясь о том, что она будет мешать (как это происходит в случае с USB-флешкой). Однако этот подход будет выглядеть несколько архаично, если ноутбук уже оснащен сканером для снятия отпечатков пальцев.
Ноутбуки со сканером отпечатков пальцев выпускают многие производители. Как правило, они не намного дороже других сходных по характеристикам моделей, однако их сенсор отпечатков работает только в Windows. Для устранения этого недостатка freedesktop.org запустил проект fprint, в рамках которого разработана открытая реализация библиотеки для распознавания отпечатков и соответствующий PAM-модуль, позволяющий задействовать возможности библиотеки во время логина пользователя и других манипуляций над аккаунтом.
Сегодня libfprint есть в любом дистрибутиве, поэтому установить его можно с помощью любого пакетного менеджера:

$ sudo apt-get install libfprint0 libpam-fprint fprint-demo

Далее сканер можно проверить с помощью специальной демонстрационной программы с графическим интерфейсом:

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

# pam_fprint_enroll –enroll-finger 7

Цифра 7 здесь означает указательный палец правой руки. Система fprint нумерует пальцы слева направо, так что цифрой 1 будет обозначен мизинец левой руки, а 10 — мизинец правой.
Когда слепок будет готов, добавим модуль pam_fprint в стек PAM-модулей всех приложений, для этого открываем файл /etc/pam.d/common-auth, находим все ту же строку «auth required pam_unix.so» и добавляем прямо перед ней строку, отвечающую за загрузку pam_fprint: auth sufficient pam_fprint.so .
При следующем логине все должно заработать.

Добавляем модули pam_usb и pam_fprint в стек PAM

Память на лица

Пальцы — не единственное, что отличает людей друг от друга. У всех нас разные лица, поэтому для идентификации пользователя система может использовать снимок лица, сделанный веб-камерой. Это не особо секьюрно, так как атакующий может показать камере обычную фотографию, отпечатанную на бумаге, но произведет очень сильное впечатление на друзей и знакомых.
В Linux-дистрибутивах нет встроенных средств распознавания лиц, однако их можно добавить с помощью установки комплекта ПО под названием pam-face-authentication, который включает в себя библиотеку, реализующую алгоритм распознавания лиц, PAM-модуль для осуществления аутентификации и приложение для генерирования эталонного снимка.
Все это можно собрать из исходников или же установить из сторонних репозиториев в Ubuntu. Так как проект еще сырой, и пакеты подготовлены не для всех дистрибутивов, мы рассмотрим оба варианта установки. Итак, для установки из исходников нам понадобятся пакеты с компилятором, линковщиком и заголовочными файлами для всех зависимостей. В Ubuntu (да и в других дистрибах) их можно установить, выполнив одну команду:

$ sudo apt-get install build-essential cmake qt4-qmake libx11-dev libcv-dev libcvaux-dev libhighgui4 libhighgui-dev libqt4-dev libpam0g-dev

Далее скачиваем исходники со страницы проекта и распаковываем:

$ cd
$ wget goo.gl/dpD1s
$ tar -xzf pam-face-authentication-0.3.tar.gz

Для сборки используется cmake, поэтому здесь все просто:

$ cd pam-face-authentication-0.3
$ cmake && make
$ sudo make install

Для установки уже прекомпилированного пакета в Ubuntu можно использовать репозиторий antonio.chiurazzi:

$ sudo add-apt-repository ppa:antonio.chiurazzi/ppa
$ sudo apt-get update
$ sudo apt-get install pam-face-authentication

После окончания установки запускаем обучающую программу:

Вертим лицом перед камерой, постоянно нажимая кнопку «Capture». Важно сделать хотя бы десяток фотографий, чтобы система научилась распознавать твое лицо под любым углом. Также будет неплохо сделать фотографии при разной освещенности. Не забываем протестировать работу системы.
Теперь добавим модуль pam_face_authentication.so в стек загружаемых PAM-модулей. Для этого открываем файл /etc/pam.d/gdm или /etc/pam.d/kdm (если ты пользуешься KDE) и добавляем в его начало следующую строку: auth sufficient pam_face_authentication.so enableX /
Файл /etc/pam.d/common-auth изменять не надо, так как он используется не только графическими менеджерами входа в систему, но и стандартными консольными /bin/login и /bin/su, а pam_face требует доступа к иксам.
Также необходимо создать профиль для нового PAM-модуля. Открываем (создаем) файл /usr/share/pam-configs/face_authentication следующего содержания:

Name: Manually installed face_authentication profile
Default: yes
Priority: 900
Auth-Type: Primary
Auth:
[success=end default=ignore] pam_face_authentication.so enableX

И активируем его:

$ sudo pam-auth-update —package face_authentication

Ключ из телефона

Сотовый телефон — символ 21-го века. Мы давно привыкли к тому, что его можно использовать не только для звонков, но и для выхода в интернет, игр, прослушивания музыки, просмотра видео и даже оплаты счетов. Но можно ли использовать его как ключ для входа в компьютерную систему?
Конечно, да. Как и USB-флешка, телефон имеет множество признаков, которые делают его уникальным. Это все те же идентификаторы производителя и модели, серийный номер, MAC-адреса, IMEI, в конце концов. Любой из них можно использовать для однозначной идентификации устройства и его владельца, но мы остановимся только на одном из них — MAC-адресе Bluetooth-интерфейса.
Любой, даже очень древний и простой телефон имеет поддержку протокола Bluetooth и, как следствие, уникальный MAC-адрес, который передает в сеть в ответ на любой запрос поиска устройств другим Bluetooth-адаптером. Многие современные ноутбуки имеют на борту такой адаптер, а его внешний USB’шный вариант стоит копейки, так что для нас синий зуб будет идеальным вариантом для настройки беспарольной и беспроводной аутентификации. Зашел в комнату — доступ открыт, вышел — система заблокирована.
Берем телефон, включаем Bluetooth, делаем так, чтобы он был «видим» другим устройствам. Садимся за комп и запускаем утилиту hcitool (входит в пакет bluez-utils) в режиме поиска устройств:

Получаем имя своего устройства и его MAC-адрес, копируем последний в буфер обмена. Устанавливаем пакет libpam_blue (или pam_blue, где как):

$ sudo apt-get install libpam_blue

Создаем файл конфигурации /etc/security/bluesscan.conf и пишем в него следующее:

# Общие настройки
general # Продолжительность сканирования в секундах (от 3 до 15)
timeout = 15;
>

# Настройки пользователей и их устройств
mylogin = name = Имя устройства;
bluemac = MAC-адрес устройства;
>

Сохраняем файл, открываем уже знакомый нам конфиг /etc/pam.d/common-auth и добавляем строку auth sufficient pam_blue.so перед строкой, содержащей «pam_unix.so».
Теперь для входа в систему будет достаточно положить телефон рядом с ноутом и ввести имя. Далее управление будет передано модулю pam_blue, который просканирует сеть, найдет MAC-адрес телефона и впустит пользователя. В противном случае придется ввести пароль.

Выводы

Настроить беспарольную аутентификацию с помощью альтернативных методов в Linux довольно просто. Для этого не нужно быть матерым гиком, уметь писать код или иметь глубокие познания в области безопасности, все делается за несколько минут и работает поразительно эффективно. Ты можешь сказать, что большинство из этих методов потенциально небезопасны и легко обходятся, но перед тем как это сделать, задумайся о том, насколько безопасны обычные пароли.
Безопасность машины, к которой могут получить доступ сторонние люди — чистой воды миф. Обойти стандартную защиту паролем проще простого. Есть огромное количество способов сделать это, и все они известны даже детям. Пароль — это лишь небольшой указательный знак, несущий информацию о том, что у компа есть владелец, и он не хочет видеть непрошенных гостей. Применив методы, описанные в статье, мы не сделаем систему более уязвимой, но сможем сделать свою жизнь проще и удобнее.

Аналог файла /etc/pam.d/common-auth в Gentoo и Mandriva носит имя /etc/pam.d/system-auth, во FreeBSD вместо него используется /etc/pam.d/system. В ArchLinux придется править PAM-конфиги отдельно для каждого приложения.
Еще один способ обезопасить машину от вторжения — удаленно создать файл /etc/nologin с помощью любого мобильного SSH-клиента. Для разблокировки придется войти как root и удалить этот файл.

image

Журнал Хакер, Сентябрь (09) 152
Евгений Зобнин (execbit.ru)
.

  • 1 999 р. за 12 номеров бумажного варианта
  • 1249р. за годовую подписку на iOS/iPad (релиз Android’а скоро!)
  • «Хакер» на Android

Процессы и память в Linux. Отрывок из книги «Внутреннее устройство Linux»

Про­цес­сы опе­раци­онной сис­темы в боль­шинс­тве слу­чаев отож­дест­вля­ются с выпол­няющи­мися прог­рамма­ми, что не сов­сем вер­но, точ­нее — сов­сем невер­но. В сов­ремен­ных опе­раци­онных сис­темах, вклю­чая Linux, меж­ду прог­раммой и про­цес­сом есть оче­вид­ная вза­имос­вязь, но далеко не такая непос­редс­твен­ная, как кажет­ся на пер­вый взгляд.

О книге

Сов­сем недав­но в изда­тель­стве БХВ выш­ло вто­рое изда­ние кни­ги Дмит­рия Кетова «Внут­реннее устрой­ство Linux». Я про­чел пре­дос­тавлен­ный изда­тель­ством экзем­пляр и сде­лал свои выводы о качес­тве кни­ги, ее плю­сах и целевой ауди­тории. В при­дачу мы пуб­лику­ем отры­вок кни­ги, который поз­волит тебе сос­тавить собс­твен­ное мне­ние.

Нес­мотря на гром­кое наз­вание, эта кни­га — не об устрой­стве Linux. Из нее ты не узна­ешь, как работа­ет сис­тема управле­ния вир­туаль­ной памятью ядра Linux или фай­ловая сис­тема Btrfs. Эта кни­га — ско­рее учеб­ник «GNU/Linux для про­дол­жающих», то есть тех, кто понял, что такое коман­дный интер­пре­татор и пра­ва дос­тупа, но хотел бы коп­нуть глуб­же и понять, почему этот интер­пре­татор имен­но такой, с какой целью появил­ся инс­тру­мент sudo и почему, нес­мотря на весь хейт, менед­жер Systemd стал стан­дартом.

Глав­ное дос­тоинс­тво кни­ги — гра­мот­ное балан­сирова­ние меж­ду теорией и прак­тикой. Автор соп­ровож­дает текст боль­шим количес­твом исто­ричес­ких спра­вок и деталей, которые быва­ют нез­накомы даже мне, умуд­ренно­му двад­цатилет­ним опы­том линук­соиду. При этом прак­тичес­ки каж­дое выс­казыва­ние авто­ра соп­ровож­дает­ся при­мером, пояс­няющим теорию. Хочешь уви­деть, как работа­ют управля­ющие пос­ледова­тель­нос­ти тер­минала? Вот тебе лис­тинг команд с отметка­ми, где, что и как надо нажать.

Вто­рой плюс — пол­нота информа­ции. Нес­мотря на мас­су под­робнос­тей о реали­зации ком­понен­тов типич­ного дис­три­бути­ва и срав­нитель­но неболь­шой объ­ем, кни­га охва­тыва­ет прак­тичес­ки все, что может быть инте­рес­но поль­зовате­лю, начиная от эму­лято­ра тер­минала и коман­дно­го интер­пре­тато­ра и закан­чивая гра­фичес­кой сис­темой Wayland, которая толь­ко готовит­ся занять мес­то стан­дар­тной в дис­три­бути­вах Linux, пла­ниров­щиком BFQ и кон­тей­нер­ной сис­темой Docker, о которых ты не узна­ешь из более «ака­деми­чес­кой» и «про­верен­ной вре­менем» литера­туры.

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

info

На сай­те изда­тель­ства мож­но купить эту кни­гу со скид­кой 20% по про­моко­ду linuxakep. Про­мокод сле­дует ввес­ти на эта­пе офор­мле­ния заказа, нажав на ссыл­ку «У вас есть купон? Наж­мите здесь для вве­дения кода».

Программы и библиотеки

Прог­рамма пред­став­ляет собой ал­горитм, записан­ный на опре­делен­ном язы­ке, понят­ном исполни­телю прог­раммы. Раз­лича­ют машин­ный язык, понят­ный цен­траль­ному про­цес­сору, и язы­ки более высоких уров­ней (алго­рит­мичес­кие), понят­ные сос­тавите­лю прог­раммы — прог­раммис­ту.

Прог­раммы, сос­тавлен­ные на язы­ке высоко­го уров­ня, в любом слу­чае перед исполне­нием дол­жны быть тран­сли­рова­ны (переве­дены) на язык исполни­теля, что реали­зует­ся при помощи спе­циаль­ных средств — тран­сля­торов. Раз­лича­ют два вида тран­сля­торов прог­рамм — ком­пилято­ры и ин­тер­пре­тато­ры. Ком­пилятор тран­сли­рует в машин­ный код сра­зу целиком всю прог­рамму и не учас­тву­ет в ее исполне­нии. Интер­пре­татор, наобо­рот, пошаго­во тран­сли­рует отдель­ные инс­трук­ции прог­раммы и немед­ленно выпол­няет их. Нап­ример, ко­ман­дный интер­пре­татор при инте­рак­тивном режиме пошаго­во выпол­няет коман­ды, вво­димые поль­зовате­лем, а в пакет­ном режиме так же пошаго­во выпол­няет коман­ды, записан­ные в фай­ле сце­нария.

Ал­горитм, в свою оче­редь, есть некото­рый набор инс­трук­ций, выпол­нение которых при­водит к решению кон­крет­ной задачи. В боль­шинс­тве слу­чаев инс­трук­ции алго­рит­ма име­ют при­чин­но‑следс­твен­ные зависи­мос­ти и выпол­няют­ся исполни­телем пос­ледова­тель­но. Одна­ко если выделить «незави­симые» под­наборы инс­трук­ций (незави­симые вет­ви), то их мож­но выпол­нять нес­коль­кими исполни­теля­ми одновре­мен­но — па­рал­лель­но. Поэто­му раз­лича­ют пос­ледова­тель­ные и парал­лель­ные алго­рит­мы и соот­ветс­тву­ющие им пос­ледова­тель­ные и парал­лель­ные прог­раммы. Некото­рые прог­раммы реали­зуют алго­рит­мы обще­го наз­начения, нап­ример алго­рит­мы сжа­тия или шиф­рования информа­ции, алго­рит­мы сетевых про­токо­лов и т. д. Такие прог­раммы, вос­тре­бован­ные не столь­ко конеч­ными поль­зовате­лями, сколь­ко дру­гими прог­рамма­ми, называ­ют биб­лиоте­ками.

Сог­ласно hier , откомпи­лиро­ван­ные до машин­ного язы­ка прог­раммы раз­меща­ются в катало­гах / bin, / sbin , / usr/ bin , / usr/ sbin , / usr/ local/ bin , / usr/ local/ sbin , а биб­лиоте­ки — в катало­гах / lib , / usr/ lib , / usr/ local/ lib . Прог­раммы име­ют спе­циаль­ный бинар­ный «запус­каемый» фор­мат W:[ELF] executable и зависят от биб­лиотек, что про­иллюс­три­рова­но в сле­дующем лис­тинге при помощи коман­ды ldd (loader dependencies). Каж­дая зависи­мость отоб­ража­ется име­нем биб­лиоте­ки ❶ (SONAME, shared object name), най­ден­ным в сис­теме фай­лом биб­лиоте­ки ❷ и адре­сом в памяти про­цес­са ❸ (32- или 48-бит­ным, в зависи­мос­ти от плат­формы), куда биб­лиоте­ка будет заг­ружена.

Прог­раммы и биб­лиоте­ки

fitz@ubuntu:~$ which ls
/usr/bin/ls
fitz@ubuntu:~$ file /usr/bin/ls
/usr/bin/ls: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=2f15ad836be3339dec0e2e6a3c637e08e48aacbd, for GNU/Linux 3.2.0, stripped
fitz@ubuntu:~$ ldd /usr/bin/ls
linux-vdso.so.1 (0x00007ffcb529d000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007fb02f58d000)
❶ libc.so.6 => ❷ /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb02f39c000) ❸
libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007fb02f317000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fb02f311000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb02f5f1000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb02f2ee000)

fitz@ubuntu:~$ file /lib/x86_64-linux-gnu/libc.so.6
❹ /lib/x86_64-linux-gnu/libc.so.6: symbolic link to libc-2.30.so

Нуж­но заметить, что фай­ла биб­лиоте­ки linux-vdso. so. 1 (реали­зующей интерфейс сис­темных вызовов к ядру) не сущес­тву­ет, так как она явля­ется вир­туаль­ной (VDSO, virtual dynamic shared object), т. е. пре­дос­тавля­ется и отоб­ража­ется в память про­цес­са самим ядром, «как буд­то» явля­ется нас­тоящей биб­лиоте­кой. Кро­ме того, биб­лиоте­ка ld-linux-x86-64. so. 2 ука­зана абсо­лют­ным путевым име­нем, поэто­му поиск ее фай­ла не про­изво­дит­ся.

Для боль­шинс­тва биб­лиотек зависи­мость уста­нав­лива­ется при помощи SONAME вида libNAME. so. X , где lib — стан­дар­тный пре­фикс (library, биб­лиоте­ка), . so — суф­фикс (shared object, раз­деля­емый объ­ект), NAME — имя «собс­твен­ное», а . X — номер вер­сии ее интерфей­са. По име­ни SONAME в опре­делен­ных (кон­фигура­цией ком­понов­щика) катало­гах про­изво­дит­ся поиск одно­имен­ного фай­ла биб­лиоте­ки, который на самом деле ока­зыва­ется сим­воличес­кой ссыл­кой ❹ на «нас­тоящий» файл биб­лиоте­ки. Нап­ример, для 6-й вер­сии интерфей­са динами­чес­кой биб­лиоте­ки язы­ка с ( libc. so. 6 ) нас­тоящий файл биб­лиоте­ки называ­ется libc2. 30. so , что ука­зыва­ет на вер­сию самой биб­лиоте­ки как 2.30.

Вер­сии биб­лиотек

fitz@ubuntu:~$ file /lib/x86_64-linux-gnu/libpcre2-8.so.0
/lib/x86_64-linux-gnu/libpcre2-8.so.0: symbolic link to libpcre2-8.so.0.7.1

Ана­логич­но, в при­веден­ном выше лис­тинге показа­но, что для 0-й вер­сии интерфей­са динами­чес­кой биб­лиоте­ки регуляр­ных perl-выраже­ний pcre2 ( libpcre2-8. so. 0 ) нас­тоящий файл биб­лиоте­ки называ­ется libpcre2-8. so. 0. 7. 1 , а это ука­зыва­ет на вер­сию самой биб­лиоте­ки как 0.7.1.

Та­кой под­ход поз­воля­ет заменять (исправ­лять ошиб­ки, улуч­шать неэф­фектив­ные алго­рит­мы и пр.) биб­лиоте­ки (при усло­вии неиз­меннос­ти их интерфей­сов) от­дель­но от прог­рамм, завися­щих от них. При обновле­нии биб­лиоте­ки libc2. 30. so , нап­ример, до libc2. 32. so дос­таточ­но уста­новить сим­воличес­кую SONAME-ссыл­ку libc. so. 6 на libc-2. 32. so , в резуль­тате чего ее нач­нут исполь­зовать все прог­раммы с зависи­мос­тями от libc. so. 6 . Более того, в сис­теме может быть одновре­мен­но уста­нов­лено любое количес­тво вер­сий одной и той же биб­лиоте­ки, реали­зующих оди­нако­вые или раз­ные вер­сии интерфей­сов, выбор которых будет ука­зан соот­ветс­тву­ющи­ми SONAME-ссыл­ками.

Биб­лиоте­ки — это незапус­каемые прог­раммы

fitz@ubuntu:~$ file /lib/x86_64-linux-gnu/libc-2.30.so
/lib/x86_64-linux-gnu/libc-2.30.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=2155f455ad56bd871c8225bcca85ee25c1c197c4, for GNU/Linux 3.2.0, stripped
fitz@ubuntu:~$ file /lib/x86_64-linux-gnu/libpcre2-8.so.0.7.1
/lib/x86_64-linux-gnu/libpcre2-8.so.0.7.1: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=815e1acbcc22015f05d62c17fe982c1b573125b1, stripped

fitz@ubuntu:~$ ldd /lib/x86_64-linux-gnu/libpcre2-8.so.0.7.1
linux-vdso.so.1 (0x00007ffe22093000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f8ec2bdd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8ec29ec000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8ec2c99000)

Биб­лиоте­ки име­ют тот же бинар­ный фор­мат W:[ELF], что и «запус­каемые» прог­раммы, но не «запус­каемый» executable, а «сов­мес­тно исполь­зуемый» shared object. Биб­лиоте­ки, явля­ясь пусть и незапус­каемы­ми, но прог­рамма­ми, естес­твен­ным обра­зом тоже зависят от дру­гих биб­лиотек, что показа­но в сле­дующем лис­тинге. Прак­тичес­ки «запус­каемость» ELF-фай­лов зависит не от их типа, а от прав дос­тупа и осмыслен­ности точ­ки вхо­да — адре­са пер­вой инс­трук­ции, которой переда­ется управле­ние при попыт­ке запус­ка. Нап­ример, биб­лиоте­ку libc-2. 30. so мож­но запус­тить, в резуль­тате чего будет выведе­на ста­тус­ная информа­ция.

За­пус­каемые биб­лиоте­ки

fitz@ubuntu:~$ ls –l /lib/x86_64-linux-gnu/libc-2.30.so
-rwxr-xr-x 1 root root 2025032 сен 16 17:56 /lib/x86_64-linux-gnu/libc-2.30.so
fitz@ubuntu:~$ /lib/i386-linux-gnu/libc-2.15.so
GNU C Library (Ubuntu GLIBC 2.30-0ubuntu2) stable release version 2.30.
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 9.2.1 20190909.
libc ABIs: UNIQUE IFUNC ABSOLUTE
For bug reporting instructions, please see:
< https:// bugs. launchpad. net/ ubuntu/ +source/ glibc/ +bugs>.

Ядро Linux

Не сто­ит забывать, что самой глав­ной прог­раммой опе­раци­онной сис­темы явля­ется ее ядро, которое в Linux сос­тоит из ста­тичес­кого стар­тового модуля в фор­мате ELF executable и динами­чес­ки прис­тыковы­ваемых прог­рам­мных модулей фор­мата ELF relocatable. Для выпол­нения про­цеду­ры началь­ной заг­рузки стар­товый модуль упа­кован в «саморас­паковы­вающий­ся» gzip-архив фор­мата bzImage (big zipped image), который сос­тоит из прог­раммы рас­паков­ки и собс­твен­но запако­ван­ного стар­тового модуля.

В при­веден­ном ниже лис­тинге про­иллюс­три­рован про­цесс извле­чения стар­тового модуля из архи­ва / boot/ vmlinuz-3. 13. 0-49-generic фор­мата bzImage ⓿, который пред­варитель­но копиру­ется ❶ в / tmp/ vmlinuz . Для извле­чения исполь­зует­ся сце­нарий extract-vmlinux ❷ из пакета заголо­воч­ных фай­лов ядра. Рас­пакован­ный ❸ стар­товый модуль / tmp/ vmlinux ожи­даемо ока­зыва­ется ста­тичес­ки ском­понован­ной (т. е. не исполь­зующей биб­лиоте­ки ELF shared object) исполня­емой ELF-прог­раммой.

Яд­ро опе­раци­онной сис­темы

fitz@ubuntu:~$ uname -r
5.3.0-23-generic
fitz@ubuntu:~$ file /boot/vmlinuz-5.3.0-23-generic
/boot/vmlinuz-5.3.0-23-generic: regular file, no read permission
fitz@ubuntu:~$ ls -l /boot/vmlinuz-5.3.0-23-generic
-rw——- 1 root root 11399928 ноя 12 11:51 /boot/vmlinuz-5.3.0-23-generic
fitz@ubuntu:~$ sudo file /boot/vmlinuz-5.3.0-23-generic
⓿ /boot/vmlinuz-5.3.0-23-generic: Linux kernel x86 boot executable bzImage, version 5.3.0-23-generic (buildd@lgw01-amd64-002) #25-Ubuntu SMP Tue Nov 12 09:22:33 UTC 2019, RO-rootFS, swap_dev 0xA, Normal VGA
❶ fitz@ubuntu:~$ sudo cat /boot/vmlinuz-5.3.0-23-generic > /tmp/vmlinuz
❷ fitz@ubuntu:~$ /usr/src/linux-headers-5.3.0-23/scripts/extract-vmlinux /tmp/vmlinuz > /tmp/vmlinux
fitz@ubuntu:~$ file /tmp/vmlinux
/tmp/vmlinux: ELF 64-bit LSB executable ❸, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=b23ff3f6790319ec538278e3269af619ba2ca642, stripped

Ди­нами­чес­кие модули заг­ружа­ются в прос­транс­тво ядра и прис­тыковы­вают­ся к стар­товому модулю поз­днее, уже при работе опе­раци­онной сис­темы при помощи сис­темных ути­лит insmod или modprobe . Для отсты­ков­ки и выг­рузки ненуж­ных модулей пред­назна­чена сис­темная ути­лита rmmod , для прос­мотра спис­ка ❶ заг­ружен­ных модулей — lsmod , а для иден­тифика­ции свой­ств и парамет­ров ❷ модулей — ути­лита modinfo . Заг­рузка и выг­рузка модулей реали­зует­ся спе­циаль­ными сис­темны­ми вызова­ми init_module и delete_module , дос­туп к спис­ку заг­ружен­ных модулей — при помощи фай­ла / proc/ modules псев­дофай­ловой сис­темы proc , а иден­тифика­ция свой­ств и парамет­ров модулей — чте­нием спе­циаль­ных сек­ций ELF-фай­лов модулей.

Модули ядра

❶ fitz@ubuntu:~$ lsmod
Module Size Used by
.
i915 1949696 4
.
btusb 57344 0
.
uvcvideo 98304 0
.
e1000e 258048 0
.
❷ fitz@ubuntu:~$ modinfo i915
filename: /lib/modules/5.3.0-23-generic/kernel/drivers/gpu/drm/i915/i915.ko
license: GPL and additional rights
description: Intel Graphics
.
fitz@ubuntu:~$ file /lib/modules/5.3.0-23-generic/kernel/drivers/gpu/drm/i915/i915.ko
/lib/modules/5.3.0-23-generic/kernel/drivers/gpu/drm/i915/i915.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=49e59590c1a718074b76b6541702f6f794ea7eae, not stripped

Ди­нами­чес­кие модули ядра зачас­тую явля­ются драй­верами устрой­ств, что про­иллюс­три­рова­но в лис­тинге при помощи ути­лит lspci и lsusb , которые ска­ниру­ют пос­редс­твом псев­дофай­ловой сис­темы sysfs спис­ки обна­ружен­ных ядром на шинах PCI и USB устрой­ств и обслу­жива­ющих их драй­веров.

Драй­веры устрой­ств

fitz@ubuntu:~$ lspci -k
.
00:02.0 VGA compatible controller: Intel Corporation 2nd Generation Core Process
or Family Integrated Graphics Controller (rev 09)
Subsystem: Dell 2nd Generation Core Processor Family Integrated Graphics
Controller
Kernel driver in use: i915
Kernel modules: i915
.
00:19.0 Ethernet controller: Intel Corporation 82579LM Gigabit Network Connection (Lewisville) (rev 04)
Subsystem: Dell 82579LM Gigabit Network Connection (Lewisville)
Kernel driver in use: e1000e
Kernel modules: e1000e
fitz@ubuntu:~$ lsusb –t
.
/: Bus 01. Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/ 3p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/ 6p, 480M
|__ Port 4: Dev 3, If 2, Class=Vendor Specific Class, Driver=, 12M
|__ Port 4: Dev 3, If 0, Class=Wireless, Driver=btusb, 12M
|__ Port 4: Dev 3, If 3, Class=Application Specific Interface, Driver=, 12M
|__ Port 4: Dev 3, If 1, Class=Wireless, Driver=btusb, 12M
|__ Port 5: Dev 4, If 0, Class=Video, Driver=uvcvideo, 480M
|__ Port 5: Dev 4, If 1, Class=Video, Driver=uvcvideo, 480M

Процессы и нити

Сущ­ность про­цес­са нераз­рывно свя­зана с муль­тип­рограм­мирова­нием и мно­гоза­дач­ностью опе­раци­онной сис­темы. Нап­ример, в одно­задач­ных опе­раци­онных сис­темах прог­раммы сущес­тву­ют, а про­цес­сы — нет. В одно­задач­ных опе­раци­онных сис­темах еди­нов­ремен­но одна пос­ледова­тель­ная прог­рамма выпол­няет­ся одним исполни­телем (цен­траль­ным про­цес­сором), имея воз­можность без­раздель­но исполь­зовать все дос­тупные ресур­сы (память, устрой­ства вво­да‑вывода и пр.).

В любой прог­рамме мож­но выделить переме­жающиеся бло­ки инс­трук­ций, исполь­зующих или цен­траль­ный про­цес­сор (ЦП), или устрой­ства вво­да‑вывода (УВВ). При этом цен­траль­ный про­цес­сор вынуж­ден прос­таивать при выпол­нении прог­раммой опе­раций вво­да‑вывода, нап­ример, при ожи­дании окон­чания записи (или чте­ния) бло­ка дан­ных на внеш­ний носитель, или при ожи­дании окон­чания переда­чи (или при­ема) сетево­го кад­ра, или при ожи­дании событий с устрой­ств челове­ко‑машин­ного вза­имо­дей­ствия. С дру­гой сто­роны, устрой­ства вво­да‑вывода тоже вынуж­дены прос­таивать при выпол­нении прог­раммой вычис­литель­ных опе­раций, нап­ример, ожи­дая резуль­тата, под­лежаще­го выводу, или ожи­дая воз­никно­вения у прог­раммы пот­ребнос­ти в новых исходных дан­ных.

Ис­поль­зуя такую модель поведе­ния прог­рамм, мож­но про­вес­ти ана­лиз пот­ребле­ния ими ресур­сов при выпол­нении. Нап­ример, ком­прес­соры gzip, bzip и xz счи­тыва­ют оче­ред­ной блок дан­ных исходно­го фай­ла, отно­ситель­но дол­го упа­ковы­вают его и записы­вают в резуль­тиру­ющий файл, а затем пов­торя­ют про­цеду­ру до исчерпа­ния бло­ков исходно­го фай­ла. Количес­тво вре­мени, пот­рачен­ного на вычис­литель­ные опе­рации упа­ков­ки, будет мно­го боль­ше количес­тва вре­мени, пот­рачен­ного на чте­ние исходных дан­ных и запись резуль­татов, поэто­му наг­рузка на ЦП будет высокой, а на УВВ — нет. Такой же ана­лиз мож­но при­вес­ти и для дуб­ликато­ра dd, копиров­щика rsync или архи­вато­ра tar, которые, наобо­рот, поч­ти не выпол­няют никаких вычис­лений, а сос­редото­чены на вво­де‑выводе боль­ших объ­емов дан­ных, поэто­му при их исполь­зовании наг­рузка на ЦП будет доволь­но низ­кой, а на УВВ — высокой.

Для коман­дно­го интер­пре­тато­ра bash, тек­сто­вых редак­торов nano и vim и дру­гих инте­рак­тивных прог­рамм, вза­имо­дей­ству­ющих с поль­зовате­лем, харак­терны дли­тель­ные ожи­дания вво­да неболь­ших команд, прос­тая и недол­гая их обра­бот­ка и вывод корот­кого резуль­тата. В резуль­тате коэф­фици­ент полез­ного исполь­зования и ЦП, и УВВ будет приб­лижен к нулю.

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

С появ­лени­ем муль­тип­рограм­мной сме­си (так называ­ют набор прог­рамм, меж­ду которы­ми перек­люча­ется про­цес­сор) каж­дая из ее прог­рамм боль­ше не может без­раздель­но исполь­зовать все дос­тупные ресур­сы (нап­ример, всю память — она одновре­мен­но нуж­на всем прог­раммам сме­си), в свя­зи с чем опе­раци­онная сис­тема берет на себя задачи дис­петче­риза­ции (рас­пре­деле­ния) ресур­сов меж­ду ними. В Linux, как и во мно­гих дру­гих опе­раци­онных сис­темах, прог­раммы изо­лиру­ются друг от дру­га в спе­циаль­ных «вир­туаль­ных» сре­дах, обес­печива­ющих их про­цесс выпол­нения. Каж­дая такая сре­да называ­ется про­цес­сом и получа­ет долю дос­тупных ресур­сов — выделен­ный учас­ток памяти, выделен­ные про­межут­ки про­цес­сорно­го вре­мени. Про­цесс эму­лиру­ет для прог­раммы «одно­задач­ный» режим выпол­нения, слов­но прог­рамма выпол­няет­ся в оди­ноч­ку, и «без­раздель­ное» исполь­зование ресур­сов про­цес­са, как буд­то это все дос­тупные ресур­сы.

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

В сле­дующем лис­тинге при помощи коман­ды ps показа­ны про­цес­сы поль­зовате­ля, упо­рядо­чен­ные в дерево, пос­тро­енное на осно­ве дочер­не‑родитель­ских отно­шений меж­ду про­цес­сами. Уни­каль­ный иден­тифика­тор, отли­чающий про­цесс от дру­гих, выведен в стол­бце PID (process identifier), а имя и аргу­мен­ты прог­раммы, запущен­ной в соот­ветс­тву­ющем про­цес­се — в стол­бце COMMAND.

В стол­бце STAT показа­но текущее сос­тояние про­цес­са, нап­ример S (сон, sleep) или R (выпол­нение, running, или готов­ность к выпол­нению, runnable). Про­цес­сы, ожи­дающие завер­шения их опе­раций вво­да‑вывода, находят­ся в сос­тоянии сна, в про­тив­ном слу­чае либо выпол­няют­ся, либо готовы к выпол­нению, т. е. ожи­дают, ког­да текущий выпол­няющий­ся про­цесс зас­нет и про­цес­сор будет перек­лючен на них. В стол­бце TIME показа­но чис­тое пот­реблен­ное про­цес­сом про­цес­сорное вре­мя от момен­та запус­ка прог­раммы, уве­личи­вающееся толь­ко при нахож­дении им в сос­тоянии выпол­нения.

Де­рево про­цес­сов поль­зовате­ля

fitz@ubuntu:~$ ps fx
PID TTY STAT TIME COMMAND
.
17764 tty3 Ssl+ 0:00 /usr/lib/gdm3/gdm-x-session —run-script .
17766 tty3 Sl+ 3:09 _ /usr/lib/xorg/Xorg vt3 -displayfd 3 .
17774 tty3 Sl+ 0:00 _ /usr/lib/gnome-session/gnome-session-binary .
.
2987 ? Ss 0:04 /lib/systemd/systemd —user
2992 ? S 0:00 _ (sd-pam)
17373 ? Ssl 0:08 _ /usr/bin/pulseaudio —daemonize=no
17444 ? Ss 0:02 _ /usr/bin/dbus-daemon —session —address=systemd: .
.
17921 ? Ssl 10:04 _ /usr/bin/gnome-shell
.
⓿ 30192 ? Ssl 0:00 _ /usr/libexec/gnome-terminal-server
❶ 30202 pts/1 Ss 0:00 _ bash
❷ 30226 pts/1 S+ 0:00 _ man ps
30236 pts/1 S+ 0:00 _ pager
❶ 30245 pts/3 Ss 0:00 _ bash
❷ 30251 pts/3 R+ 0:00 _ ps fx
❸ 30315 ? Sl 0:04 _ /usr/lib/firefox/firefox -new-window
30352 ? Sl 0:02 _ /usr/lib/firefox/firefox -contentproc -childID 1 .
30396 ? Sl 0:00 _ /usr/lib/firefox/firefox -contentproc -childID 2 .
30442 ? Sl 0:00 _ /usr/lib/firefox/firefox -contentproc -childID 3 .

Уп­равля­ющий тер­минал про­цес­са, показан­ный в стол­бце TTY, исполь­зует­ся для дос­тавки ему инте­рак­тивных сиг­налов (см. разд. 4.8) при вво­де управля­ющих сим­волов intr ^C, quit ^\ и пр. у час­ти про­цес­сов ⓿, ❸ управля­ющий тер­минал отсутс­тву­ет, потому что они выпол­няют при­ложе­ния, вза­имо­дей­ству­ющие с поль­зовате­лем не пос­редс­твом тер­миналов, а через гра­фичес­кую сис­тему.

Про­цесс по сво­ему опре­деле­нию изо­лиру­ет свою прог­рамму от дру­гих выпол­няющих­ся прог­рамм, что зат­рудня­ет исполь­зование про­цес­сов для выпол­нения таких парал­лель­ных прог­рамм, вет­ви которых не явля­ются пол­ностью незави­симы­ми друг от дру­га и дол­жны обме­нивать­ся дан­ными. Исполь­зование пред­назна­чен­ных для это­го средств меж­про­цес­сно­го вза­имо­дей­ствия при интенсив­ном обме­не при­водит к обре­мене­нию неоп­равдан­ными нак­ладны­ми рас­ходами, поэто­му для эффектив­ного выпол­нения таких парал­лель­ных прог­рамм исполь­зуют­ся лег­ковес­ные про­цес­сы (LWP, light-weight processes), они же нити (threads).

info

Су­щес­тву­ет еще один (неудач­ный, на мой взгляд) перевод понятия thread на рус­ский язык — поток. Во‑пер­вых, он кон­флик­тует с перево­дом понятия stream — поток, а во‑вто­рых, в отли­чие от stream, thread никуда не течет. А вот про­цесс (process) содер­жит в себе нити (thread) абсо­лют­но таким же обра­зом, как и обыч­ная верев­ка сос­тоит из нитей.

Ме­ханизм нитей поз­воля­ет перек­лючать цен­траль­ный про­цес­сор меж­ду парал­лель­ными вет­вями одной прог­раммы, раз­меща­емы­ми в од­ном (!) про­цес­се. Нити никак не изо­лиро­ваны друг от дру­га, и им дос­тупны абсо­лют­но все ресур­сы сво­его про­цес­са, поэто­му задача обме­на дан­ными меж­ду нитями поп­росту отсутс­тву­ет, т. к. все дан­ные явля­ются для них общи­ми.

В при­мере из cktle. otuj сле­дующе­го лис­тинга показа­ны нити про­цес­са в BSD-фор­мате вывода. Выбор про­цес­са про­изво­дит­ся по его иден­тифика­тору PID, пред­варитель­но получен­ному коман­дой pgrep по име­ни прог­раммы, выпол­няющей­ся в иско­мом про­цес­се.

В выводе наличие нитей про­цес­са отме­чает флаг l ( lwp) в стол­бце сос­тояния STAT, а каж­дая строч­ка без иден­тифика­тора PID сим­волизи­рует одну нить. Так как в мно­гони­тевой прог­рамме перек­лючение про­цес­сора про­изво­дит­ся меж­ду нитями, то и сос­тояния сна S, выпол­нения или ожи­дания R при­писы­вают­ся отдель­ным нитям.

Ни­ти про­цес­сов, BSD-фор­мат вывода

fitz@ubuntu:~$ pgrep firefox
30315
fitz@ubuntu:~$ ps mp 30315
PID TTY STAT TIME COMMAND
PID TTY STAT TIME COMMAND
30315 ? — 0:05 /usr/lib/firefox/firefox -new-window
— —  Sl 0:03 —
.
— — Sl 0:00 —
— — Sl 0:00 —
— — Sl 0:00 –

В нижес­леду­ющем лис­тинге показа­ны нити про­цес­са в SYSV-фор­мате вывода. Выбор про­цес­са про­изво­дит­ся по име­ни его прог­раммы. Общий для всех нитей иден­тифика­тор их про­цес­са отоб­ража­ется в стол­бце PID, уни­каль­ный иден­тифика­тор каж­дой нити — в стол­бце LWP (иног­да называ­емый TID, thread identifier), а имя про­цес­са (или собс­твен­ное имя нити, если задано) — в стол­бце CMD.

Ни­ти про­цес­сов, SYSV-фор­мат вывода

fitz@ubuntu:~$ ps -LC firefox
PID LWP TTY TIME CMD
30315 30315 ? 00:00:04 firefox
30315 30320 ? 00:00:00 gmain
30315 30321 ? 00:00:00 gdbus
.
30315 30328 ? 00:00:00 Socket Thread
30315 30332 ? 00:00:00 Cache2 I/O
30315 30333 ? 00:00:00 Cookie
.
30315 30371 ? 00:00:00 HTML5 Parser
30315 30373 ? 00:00:00 DNS Resolver #3
.

Порождение процессов и нитей, запуск программ

Нес­мотря на оче­вид­ные раз­личия, исто­рию воз­никно­вения и раз­вития, нити и про­цес­сы объ­еди­няет общее наз­начение — они явля­ются при­мити­вами выпол­нения некото­рого набора пос­ледова­тель­ных инс­трук­ций. Откро­вен­но говоря, нити, в общем, появи­лись в опе­раци­онных сис­темах рань­ше, чем изо­лиро­ван­ные UNIX-про­цес­сы, в которые со вре­менем вер­нулись UNIX-нити.

Про­цес­сы выпол­няют или раз­ные пос­ледова­тель­ные прог­раммы целиком, или вет­ви одной парал­лель­ной прог­раммы, но в изо­лиро­ван­ном окру­жении со сво­им «час­тным» (private) набором ресур­сов. Нити, наобо­рот, выпол­няют вет­ви одной парал­лель­ной прог­раммы в одном окру­жении с «общим» (shared) набором ресур­сов. В мно­гоза­дач­ном ядре Linux вооб­ще исполь­зует­ся уни­вер­саль­ное понятие «задача», которая может иметь как общие ресур­сы (память, откры­тые фай­лы и т. д.) с дру­гими задача­ми, так и час­тные ресур­сы для сво­его собс­твен­ного исполь­зования.

По­рож­дение нового про­цес­са реали­зует­ся при помощи сис­темно­го вызова fork , в резуль­тате которо­го ядро опе­раци­онной сис­темы соз­дает новый дочер­ний (child) про­цесс PID 2 — пол­ную копию (COPY) про­цес­са‑родите­ля (parent) PID 1. Вся (за неболь­шими исклю­чени­ями) память про­цес­са — сос­тояние, свой­ства, атри­буты (кро­ме иден­тифика­тора PID) и даже содер­жимое (прог­рамма с ее биб­лиоте­ками) — нас­леду­ется дочер­ним про­цес­сом. Даже выпол­нение порож­денно­го и порож­дающе­го про­цес­са про­дол­жится с одной и той же инс­трук­ции их оди­нако­вой прог­раммы. Такое кло­ниро­вание обыч­но исполь­зуют парал­лель­ные прог­раммы с вет­вями, выпол­няющи­мися в дочер­них про­цес­сах.

Унич­тожение про­цес­са (нап­ример, при штат­ном окон­чании прог­раммы) про­изво­дит­ся с помощью сис­темно­го вызова exit . При этом родитель­ско­му про­цес­су дос­тавля­ется сиг­нал SIGCHILD , опо­веща­ющий о завер­шении дочер­него про­цес­са. Ста­тус завер­шения status , передан­ный дочер­ним про­цес­сом через аргу­мен­ты exit , будет сох­ранять­ся ядром до момен­та его вос­тре­бова­ния родитель­ским про­цес­сом при помощи сис­темно­го вызова wait , а весь этот про­межу­ток вре­мени дочер­ний про­цесс будет находить­ся в сос­тоянии Z (zombie).

Ро­дитель­ский про­цесс может завер­шить­ся рань­ше сво­их дочер­них про­цес­сов, тог­да логич­но пред­положить, что все «оси­ротев­шие» про­цес­сы ока­жут­ся зом­би по завер­шении, потому как прос­то некому будет вос­тре­бовать их ста­тус завер­шения. На самом деле это­го не про­исхо­дит, потому что «оси­ротев­шим» про­цес­сам наз­нача­ется при­емный родитель, в качес­тве которо­го выс­тупа­ет пра­роди­тель всех про­цес­сов init с иден­тифика­тором PID = 1 .

Порождение процессов (а) и запуск программ (б)

За­пуск новой прог­раммы (см. рис.) реали­зует­ся при помощи сис­темно­го вызова exec , в резуль­тате которо­го содер­жимое про­цес­са PID 1 пол­ностью замеща­ется запус­каемой прог­раммой и биб­лиоте­ками, от которых она зависит, а свой­ства и атри­буты (вклю­чая иден­тифика­тор PID) оста­ются неиз­менны­ми. Такое замеще­ние обыч­но исполь­зует­ся прог­рамма­ми, уста­нав­лива­ющи­ми нуж­ные зна­чения свой­ств и атри­бутов про­цес­са и под­готав­лива­ющи­ми ресур­сы про­цес­са к выпол­нению запус­каемой прог­раммы. Нап­ример, обра­бот­чик тер­миналь­ного дос­тупа getty откры­вает задан­ный тер­минал, уста­нав­лива­ет режимы работы пор­та тер­минала, перенап­равля­ет на тер­минал стан­дар­тные потоки вво­да‑вывода, а затем замеща­ет себя прог­раммой аутен­тифика­ции login .

Для запус­ка новой прог­раммы в новом про­цес­се исполь­зуют­ся оба сис­темных
вы­зова fork и exec сог­ласно прин­ципу fork-and-exec «раз­дво­ить­ся и запус­тить», показан­ного на рисун­ке ниже. Нап­ример, коман­дный интер­пре­татор bash по коман­дам ps fx или man ps порож­дает дочер­ние про­цес­сы ❷ и замеща­ет их прог­рамма­ми ps и man . Тем же обра­зом дей­ству­ет ⓿ гра­фичес­кий эму­лятор тер­минала gnome-terminal-server — запус­кая новый сеанс поль­зовате­ля ❶ на каж­дой из сво­их вкла­док, он замеща­ет свои дочер­ние про­цес­сы прог­раммой интер­пре­тато­ра bash .

Запуск программы в отдельном процессе

Сле­дующий лис­тинг иллюс­три­рует коман­ду интер­пре­тато­ра, запущен­ную в «фоновом» режиме при помощи конс­трук­ции асин­хрон­ного спис­ка. Ана­логич­но всем пре­дыду­щим коман­дам, интер­пре­татор исполь­зует fork-and-exec для запус­ка прог­раммы в дочер­нем про­цес­се с иден­тифика­тором 23228 , но не дожида­ется его завер­шения при помощи сис­темно­го вызова wait , как обыч­но, а немед­ленно ❶ про­дол­жает инте­рак­тивное вза­имо­дей­ствие с поль­зовате­лем, сооб­щив ему PID порож­денно­го про­цес­са и «номер задания» [ 1] коман­ды «зад­него фона». Опо­веще­ние о завер­шении сво­его дочер­него про­цес­са интер­пре­татор получит поз­же, при помощи сиг­нала SIGCHLD , и отре­аги­рует соот­ветс­тву­ющим сооб­щени­ем ❷ об окон­чании коман­ды «зад­него фона».

Фо­новое выпол­нение прог­рамм

fitz@ubuntu:~$ dd if=/dev/dvd of=plan9.iso &

❶ [1] 23228
fitz@ubuntu:~$ ps f
PID TTY STAT TIME COMMAND
23025 pts/1 S 0:00 -bash
23228 pts/1  R 1:23 _ dd if=/dev/dvd of=plan9.iso
23230 pts/1 R+ 0:00 _ ps f
fitz@ubuntu:~$
.
fitz@ubuntu:~$ 586896+0 записей получе­но
586896+0 записей отправ­лено
300490752 байт (300 MB, 286 MiB) ско­пиро­ван, 14,6916 c, 20,5 MB/c

❷ [1]+ Завер­шён dd if=/dev/dvd of=plan9.iso

В сле­дующем лис­тинге показа­на кон­вей­ерная конс­трук­ция интер­пре­тато­ра, при помощи которой осу­щест­вля­ется поиск самого боль­шого фай­ла с суф­фиксом . html вниз по дереву катало­гов, начиная с / usr/ share/ doc . Эта конс­трук­ция реали­зует­ся при помощи fork-and-exec четырь­мя парал­лель­но порож­денны­ми дочер­ними про­цес­сами интер­пре­тато­ра, в каж­дом из которых запуще­на прог­рамма соот­ветс­тву­ющей час­ти кон­вей­ера, при этом дочер­ние про­цес­сы свя­заны неиме­нован­ным каналом pipe — прос­тей­шим средс­твом меж­про­цес­сно­го вза­имо­дей­ствия. Встро­енная коман­да интер­пре­тато­ра wait реали­зует одно­имен­ный сис­темный вызов и исполь­зует­ся для ожи­дания окон­чания всех дочер­них про­цес­сов кон­вей­ера, целиком запущен­ного в «фоновом» режиме.

Па­рал­лель­ный запуск вза­имо­дей­ству­ющих прог­рамм

fitz@ubuntu:~$ find /usr/share/doc -type f -name ‘.html’ | xargs -n1 wc –l | sort -k 1 –nr | head -1 &
[1] 12827
fitz@ubuntu:~$ ps fj
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
11715 11716 11716 9184 pts/0 14699 S 1006 0:01 -bash
11716 12824 12824 9184 pts/0 14699 R 1006 0:00 _ find . -type f -name *.html
11716 12825 12824 9184 pts/0 14699 R 1006 0:00 _ xargs -n1 wc -l
11716 12826 12824 9184 pts/0 14699 S 1006 0:00 _ sort -k 1 -nr
11716 12827 12824 9184 pts/0 14699 S 1006 0:00 _ head -1
11716 14699 14699 9184 pts/0 14699 R+ 1006 0:00 _ ps fj
fitz@ubuntu:~$ wait
15283 /usr/share/doc/xterm/xterm.log.html
[ 1] + Завер­шён find /usr/share/doc -type f -name ‘
.html’ | xargs -n1 wc -l | sort -k 1 -nr | head -1

Параллельные многопроцессные программы

Как ука­зыва­лось ранее, парал­лель­ные прог­раммы зачас­тую исполь­зуют про­цес­сы для выпол­нения отдель­ных вет­вей. В эту катего­рию час­то попада­ют прог­раммы сетевых служб, нап­ример сер­вер баз дан­ных W:[PostgreSQL], служ­ба уда­лен­ного дос­тупа W:[SSH] и подоб­ные. Сле­дующий лис­тинг иллюс­три­рует прог­рамму postgres, выпол­няющуюся в шес­ти парал­лель­ных про­цес­сах, один из которых — дис­петчер ❶, четыре слу­жеб­ных ❷ и еще один ❸ выз­ван под­клю­чени­ем поль­зовате­ля fitz к одно­имен­ной базе дан­ных fitz . При пос­леду­ющих под­клю­чени­ях поль­зовате­лей к сер­веру будут порож­дены допол­нитель­ные дочер­ние про­цес­сы для обслу­жива­ния их зап­росов — по одно­му на каж­дое под­клю­чение.

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

fitz@ubuntu:~$ ps f -C postgres
PID TTY STAT TIME COMMAND
❶ 6711 ? S 0:00 /usr/lib/postgresql/11/bin/postgres -D /var/lib/postgresql.
❷ 6713 ? Ss 0:00 _ postgres: 11/main: checkpointer
│ 6714 ? Ss 0: 00 \ _ postgres: 11/ main: background writer
│ 6715 ? Ss 0: 00 \ _ postgres: 11/ main: walwriter
│ 6716 ? Ss 0: 00 \ _ postgres: 11/ main: autovacuum launcher
│ 6717 ? Ss 0: 00 \ _ postgres: 11/ main: stats collector
6718 ? Ss 0: 00 \ _ postgres: 11/ main: logical replication launcher
❸ 9443 ? Ss 0:00 _ postgres: 11/main: fitz fitz [local] idle
fitz@ubuntu:~$ ssh ubuntu
fitz@ubuntu’s password:
.
Last login: Sat Nov 21 13:29:33 2015 from localhost
fitz@ubuntu:~$ ps f -C sshd
PID TTY STAT TIME COMMAND
① 655 ? Ss 0:00 /usr/sbin/sshd -D
② 21975 ? Ss 0:00 _ sshd: fitz [priv]
③ 22086 ? S 0:00 _ sshd: fitz@pts/1
fitz@ubuntu: ~$ ^Dвыход
Connection to ubuntu closed.

Ана­логич­но, при уда­лен­ном дос­тупе по про­токо­лу SSH прог­рамма sshd, работая в качес­тве дис­петче­ра ① в одном про­цес­се, на каж­дое под­клю­чение порож­дает один свой клон ②, который, выпол­нив аутен­тифика­цию и авто­риза­цию поль­зовате­ля в сис­теме, порож­дает еще один свой клон ③, имперсо­ниру­ющий­ся в поль­зовате­ля и обслу­жива­ющий его зап­росы.

Параллельные многонитевые программы

Для управле­ния нитями в Linux исполь­зуют стан­дар­тный POSIX-интерфейс pthreads , реали­зующий­ся биб­лиоте­кой W:[NPTL], которая явля­ется частью биб­лиоте­ки libc . Интерфейс пре­дос­тавля­ет «нитевой» вызов соз­дания нити pthread_create , который явля­ется условным ана­логом «про­цес­сных» fork и exec , вызов завер­шения и унич­тожения нити pthread_exit , условно ана­логич­ный exit , и вызов для получе­ния ста­туса завер­шения нити pthread_join , условно ана­логич­ный wait .

В качес­тве типич­ных при­меров при­мене­ния нитей мож­но при­вес­ти сетевые сер­висы, которые для парал­лель­ного обслу­жива­ния кли­ент­ских зап­росов исполь­зуют нити вмес­то про­цес­сов. Нап­ример, WEB-сер­вер apache, как показа­но в сле­дующем лис­тинге, исполь­зует два мно­гони­тевых про­цес­са по 27 нитей в каж­дом, что поз­воля­ет эко­номить память (за счет работы всех нитей про­цес­са с общей памятью) при обслу­жива­нии боль­шого количес­тва одновре­мен­ных кли­ент­ских под­клю­чений.

Па­рал­лель­ные мно­гони­тевые сер­висы

fitz@ubuntu:~$ ps f -C apache2
PID TTY STAT TIME COMMAND
10129 ? Ss 0:00 /usr/sbin/apache2 -k start
10131 ? Sl 0:00 _ /usr/sbin/apache2 -k start
10132 ? Sl 0:00 _ /usr/sbin/apache2 -k start
fitz@ubuntu:~$ ps fo pid,nlwp,cmd -C apache2
PID NLWP CMD
10129 1 /usr/sbin/apache2 -k start
10131 27 _ /usr/sbin/apache2 -k start
10132 27 _ /usr/sbin/apache2 -k start

fitz@ubuntu:~$ ps -fLC rsyslogd
UID PID PPID LWP C NLWP STIME TTY TIME CMD
syslog 606 1 606 0 4 ноя18 ? 00:00:00 /usr/sbin/rsyslogd -n -iNONE
syslog 606 1 680 0 4 ноя18 ? 00:00:00 /usr/sbin/rsyslogd -n -iNONE
syslog 606 1 681 0  4 ноя18 ? 00:00:00 /usr/sbin/rsyslogd -n -iNONE
syslog 606 1 682 0 4 ноя18 ? 00:00:00 /usr/sbin/rsyslogd -n -iNONE

Ана­логич­но, сер­вис цен­тра­лизо­ван­ной жур­нализа­ции событий rsyslogd исполь­зует нити для парал­лель­ного сбо­ра событий­ной информа­ции из раз­ных источни­ков, ее обра­бот­ки и жур­нализа­ции. Одна нить счи­тыва­ет события ядра из / proc/ kmsg , вто­рая при­нима­ет события дру­гих служб из фай­лового сокета / run/ systemd/ journal/ syslog ( / dev/ log в ран­них, до systemd сис­темах), третья филь­тру­ет поток при­нятых событий и записы­вает в жур­наль­ные фай­лы катало­га / var/ log/ * и т. д. Парал­лель­ная обра­бот­ка потоков пос­тупа­ющих событий при помощи нитей про­изво­дит­ся с минималь­но воз­можны­ми нак­ладны­ми рас­ходами, что поз­воля­ет дос­тигать колос­саль­ной про­изво­дитель­нос­ти по количес­тву обра­баты­ваемых сооб­щений в еди­ницу вре­мени.

Рас­парал­лелива­ние исполь­зует­ся не толь­ко для псев­доод­новре­мен­ного выпол­нения вет­вей парал­лель­ной прог­раммы, но и для их нас­тояще­го одновре­мен­ного выпол­нения нес­коль­кими цен­траль­ными про­цес­сорами. В при­мере из сле­дующе­го лис­тинга показа­но, как сок­раща­ется вре­мя сжа­тия ISO-обра­за фай­ла при исполь­зовании парал­лель­ного упа­ков­щика pbzip2 по срав­нению с пос­ледова­тель­ным bzip2. Для изме­рения вре­мени упа­ков­ки при­меня­ется встро­енная коман­да интер­пре­тато­ра time , при этом сна­чала изме­ряет­ся вре­мя упа­ков­ки ❶ и вре­мя рас­паков­ки ❷ пос­ледова­тель­ным упа­ков­щиком, а затем — вре­мя упа­ков­ки ① и вре­мя рас­паков­ки ② парал­лель­ным упа­ков­щиком. Коман­ды упа­ков­ки запус­кают­ся на «зад­нем фоне», оце­нива­ется наличие про­цес­сов и нитей паков­щиков, пос­ле чего они перево­дят­ся на «перед­ний фон» встро­енной коман­дой интер­пре­тато­ра fg (foreground) и оце­нива­ются зат­раты вре­мени.

Па­рал­лель­ные мно­гони­тевые ути­литы

fitz@ubuntu:~$ ls -lh plan9.iso
-rw-r—r— 1 fitz fitz 287M нояб. 28 15:47 plan9.iso
❶ fitz@ubuntu:~$ time bzip2 plan9.iso &
[ 1] 5545
fitz@ubuntu:~$ ps f
PID TTY STAT TIME COMMAND
4637 pts/0 S 0:00 -bash
5545 pts/0 S 0:00 _ -bash
5546 pts/0 R 0:12 _ bzip2 plan9.iso
5548 pts/0 R+ 0:00 _ ps f
fitz@ubuntu:~$ ps -fLp 5546
UID PID PPID LWP C NLWP STIME TTY TIME CMD
fitz 5546 5545 5546 96  1 10:50 pts/0 00:00:22 bzip2 plan9.iso
fitz@ubuntu:~$ fg
time bzip2 plan9.iso

real 0m54.780s
user 0m51.772s
sys 0m0.428s
fitz@ubuntu:~$ ls -lh plan9.iso.bz2
-rw-r—r— 1 fitz fitz 89M нояб. 28 15:47 plan9.iso.bz2
❷ fitz@ubuntu:~$ time bzip2 -d plan9.iso.bz2

real 0m20.705s
user 0m19.044s
sys 0m1.168s
① fitz@ubuntu:~$ time pbzip2 plan9.iso &
[ 1] 5571
fitz@ubuntu:~$ ps f
PID TTY STAT TIME COMMAND
4637 pts/0 S 0:00 -bash
5571 pts/0 S 0:00 -bash
5572 pts/0 Sl 0:03 _ pbzip2 plan9.iso
5580 pts/0 R+ 0:00 _ ps f
fitz@ubuntu:~$ ps -fLp 5572
UID PID PPID LWP C NLWP STIME TTY TIME CMD
fitz 5572 5571 5578 92  8 10:52 pts/0 00:00:43 pbzip2 plan9.iso
.
fitz 5572 5571 5579 1 8 10:52 pts/0 00:00:00 pbzip2 plan9.iso
fitz@ubuntu:~$ fg
time pbzip2 plan9.iso

real 0m24.259s
user 1m22.940s
sys 0m1.888s
fitz@ubuntu:~$ ls -lh plan9.iso.bz2
-rw-r—r— 1 fitz fitz 89M нояб. 28 15:47 plan9.iso.bz2
② fitz@ubuntu:~$ time pbzip2 -d plan9.iso.bz2

real 0m7.384s
user 0m25.972s
sys 0m1.396s

В резуль­тате оцен­ки ока­зыва­ется, что пос­ледова­тель­ный упа­ков­щик bzip2 исполь­зует один одно­ните­вой про­цесс и зат­рачива­ет ≈54,7 с реаль­ного вре­мени на упа­ков­ку, из них ≈51,7 с про­водит в поль­зователь­ском режиме user и лишь ≈0,4 с в режиме ядра sys (выпол­няя сис­темные вызовы, нап­ример read или write ). Соот­ношение меж­ду вре­менем режимов говорит о вычис­литель­ном харак­тере прог­раммы, т. е. о сущес­твен­ном пре­вали­рова­нии вре­мени вычис­литель­ных опе­раций упа­ков­ки над вре­менем опе­раций вво­да‑вывода для чте­ния исходных дан­ных и записи резуль­татов. Это озна­чает, что наг­рузка пос­ледова­тель­ного упа­ков­щика на цен­траль­ный про­цес­сор (в слу­чае, если бы он был единс­твен­ный) близ­ка к мак­сималь­ной, и его парал­лель­ная реали­зация для псев­доод­новре­мен­ного выпол­нения вет­вей (которые прак­тичес­ки никог­да не спят) лишена смыс­ла.

Па­рал­лель­ный упа­ков­щик pbzip2 исполь­зует один мно­гони­тевой про­цесс из вось­ми нитей и зат­рачива­ет ≈24,4 с реаль­ного вре­мени на упа­ков­ку, при этом ≈1 мин 22,9 с (!) про­водит в поль­зователь­ском режиме и ≈1,8 с в режиме ядра. При­рост про­изво­дитель­нос­ти упа­ков­ки и, как следс­твие, сок­ращение вре­мени упа­ков­ки дос­тига­ются за счет нас­тояще­го парал­лель­ного выпол­нения нитей на нес­коль­ких про­цес­сорах (раз­ных ядрах про­цес­сора). Соот­ношение меж­ду реаль­ным вре­менем упа­ков­ки и сум­марно зат­рачен­ным вре­менем режима поль­зовате­ля, которое при­мер­но в 3 раза боль­ше, озна­чает исполь­зование в сред­нем трех про­цес­соров для парал­лель­ного выпол­нения вычис­литель­ных опе­раций упа­ков­ки.

Двойственность процессов и нитей Linux

Как ука­зыва­лось ранее, про­цес­сы и нити в ядре Linux сво­дят­ся к уни­вер­саль­ному понятию «задача». Задача, все ресур­сы которой (память, откры­тые фай­лы и т. д.) исполь­зуют­ся сов­мес­тно с дру­гими такими же задача­ми, явля­ется нитью. И наобо­рот, про­цес­сами явля­ются такие задачи, которые обла­дают набором сво­их час­тных, инди­виду­аль­ных ресур­сов.

Уни­вер­саль­ный сис­темный вызов clone поз­воля­ет ука­зать, какие ресур­сы ста­нут общи­ми в порож­даемой и порож­дающей задачах, а какие — час­тны­ми. Сис­темные вызовы порож­дения POSIX-про­цес­сов fork и POSIX-нитей pthread_create ока­зыва­ются в Linux все­го лишь «обер­тка­ми» над clone , что про­иллюс­три­рова­но в двух сле­дующих лис­тингах.

В пер­вом при­мере архи­ватор tar PID = 11801 соз­дает при помощи сис­темно­го вызова clone дочер­ний про­цесс PID = 11802 , в который помеща­ет прог­рамму ком­прес­сора gzip, исполь­зуя сис­темный вызов execve . В резуль­тате парал­лель­ной работы двух вза­имо­дей­ству­ющих про­цес­сов будет соз­дан ком­прес­сирован­ный архив docs. tgz катало­га / usr/ share/ doc .

Сис­темный вызов clone — порож­дение нового про­цес­са

fitz@ubuntu:~$ strace -fe clone,fork,execve tar czf docs.tgz /usr/share/doc
execve(«/usr/bin/tar», [«tar», «czf», «docs.tgz», «/usr/share/doc»], . ) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID| . ) = 12403
tar: Уда­ляет­ся началь­ный / ‘ из имен объектов
strace: Process 12403 attached [pid 12403] execve(«/bin/sh», [«/bin/sh», «-c», «gzip»], 0x7ffd8dd597c0 . ) = 0 [pid 12403] clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID| . ) = 12404 strace: Process 12404 attached [pid 12404] execve(«/usr/bin/gzip», [«gzip»], 0x55e2e45bbb48 /* 35 vars */) = 0`

В при­мере из сле­дующе­го лис­тинга ком­прес­сор pbzip2 соз­дает при помощи сис­темно­го вызова clone семь «дочер­них» нитей ❶. ❼ PID = 12514-> 12520 , которые име­ют общую память CLONE_VM , общие откры­тые фай­лы CLONE_FILES и про­чие общие ресур­сы.

Сис­темный вызов clone — порож­дение новой нити

fitz@ubuntu:~$ strace -fe clone,fork,execve pbzip2 plan9.iso
execve(«/usr/bin/pbzip2», [«pbzip2», «plan9.iso»], 0x7ffd28884938 /* 35 vars */) = 0
❶ clone(child_stack=0x7f1d46d38fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|. ) = 12514
5 .
❼ clone(child_stack=0x7f1d46537fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|. ) = 12520
strace: Process 12520 attached
5 .
strace: Process 12514 attached
[ pid 12514] +++ exited with 0 +++
5 .
[ pid 12520] +++ exited with 0 +++
+++ exited with 0 +++

Дерево процессов

Про­цес­сы, попар­но свя­зан­ные дочер­не‑родитель­ски­ми отно­шени­ями, фор­миру­ют дерево про­цес­сов опе­раци­онной сис­темы. Пер­вый про­цесс init , называ­емый пра­роди­телем про­цес­сов, порож­дает­ся ядром опе­раци­онной сис­темы пос­ле ини­циали­зации и мон­тирова­ния кор­невой фай­ловой сис­темы, отку­да и счи­тыва­ется прог­рамма / sbin/ init (в сов­ремен­ных сис­темах явля­ется сим­воличес­кой ссыл­кой на акту­аль­ный / lib/ systemd/ systemd ). Пра­роди­тель про­цес­сов всег­да име­ет PID = 1 , а его основной задачей явля­ется запуск раз­нооб­разных сис­темных служб, вклю­чая запуск обра­бот­чиков алфа­вит­но‑циф­рового тер­миналь­ного дос­тупа getty, менед­жера дис­пле­ев гра­фичес­кого дос­тупа, служ­бы дис­танци­онно­го дос­тупа SSH и про­чих (см. гла­ву 10). Кро­ме того, systemd наз­нача­ется при­емным родите­лем для «оси­ротев­ших» про­цес­сов, а так­же отсле­жива­ет ава­рий­ные завер­шения запус­каемых им служб и переза­пус­кает их.

В при­мере из сле­дующе­го лис­тинга показа­но дерево про­цес­сов, пос­тро­енное при помощи спе­циаль­ной коман­ды pstree , а в лис­тинге “Про­цес­сы ядра, демоны, прик­ладные про­цес­сы” — «клас­сичес­кое» пред­став­ление дерева про­цес­сов при помощи коман­ды ps .

Де­рево про­цес­сов

fitz@ubuntu:~$ pstree -cnAhT
systemd-+-systemd-journal
❷ |-systemd-udevd
❷ |-systemd-resolve
❷ |-rsyslogd
.
|-gdm3—gdm-session-wor-+-gdm-session-wor
| |-gdm-x-session-+-Xorg
| | -gnome-session-b
.
|-systemd-+-( sd-pam)
.
| |-gnome-terminal—+-bash—man—pager ❸
| | -bash
.
❷ |-postgres-+-postgres
| |-postgres
| |-postgres
| |-postgres
| |-postgres
| -postgres
❷ |-apache2-+-apache2
| -apache2
.
❷ |-sshd-+-sshd—sshd—bash
| `-sshd—sshd—bash
.
|-agetty
|-login—bash—pstree ❸
.

Про­цес­сы опе­раци­онной сис­темы при­нято клас­сифици­ровать на сис­темные (ядер­ные), де­моны и прик­ладные, исхо­дя из их наз­начения и свой­ств (см. лис­тинг “Про­цес­сы ядра, демоны, прик­ладные про­цес­сы”).

Прик­ладные про­цес­сы ❸ выпол­няют обыч­ные поль­зователь­ские прог­раммы (нап­ример, ути­литу man ), для чего им выделя­ют инди­виду­аль­ную память, объ­ем которой ука­зан в стол­бце VSZ вывода коман­ды ps . Такие про­цес­сы обыч­но инте­рак­тивно вза­имо­дей­ству­ют с поль­зовате­лем пос­редс­твом управля­юще­го тер­минала (за исклю­чени­ем гра­фичес­ких прог­рамм), ука­зан­ного в стол­бце TTY.

Де­моны (daemons) ❷ выпол­няют сис­темные прог­раммы, реали­зующие те или иные служ­бы опе­раци­онной сис­темы. Нап­ример, cron реали­зует служ­бу пери­оди­чес­кого выпол­нения заданий, atd — служ­бу отло­жен­ного выпол­нения заданий, rsyslogd — служ­бу цен­тра­лизо­ван­ной жур­нализа­ции событий, sshd — служ­бу дис­танци­онно­го дос­тупа, systemd-udevd — служ­бу «регис­тра­ции» под­клю­чаемых устрой­ств, и т. д. Демоны запус­кают­ся на ран­них ста­диях заг­рузки опе­раци­онной сис­темы и вза­имо­дей­ству­ют с поль­зовате­лем не инте­рак­тивно при помощи тер­минала, а опос­редован­но — при помощи сво­их ути­лит. Таким обра­зом, отсутс­твие управля­юще­го тер­минала в стол­бце TTY отли­чает их от прик­ладных про­цес­сов.

Про­цес­сы ядра, демоны, прик­ладные про­цес­сы

fitz@ubuntu:~$ ps faxu
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 2 0.0 0.0 0 0 ? S ноя18 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? I< ноя18 0:00 _ [rcu_gp]
root 4 0.0 0.0 0 0 ? I< ноя18 0:00 _ [rcu_par_gp]
root 6 0.0 0.0 0 0 ? ❶ I< ноя18 0:00 _ [kworker/0:0H. ]
root 8 0.0 0.0 0 0 ? I< ноя18 0:00 _ [mm_percpu_wq]
root 9 0.0 0.0 0 0 ? S ноя18 0:09 _ [ksoftirqd/0]
.
root 1 0.0 0.2 168400 11684 ? Ss ноя18 0:12 /sbin/init splash
.
root 333 0.0 0.1 21844 5348 ? Ss ноя18 0:07 /lib/systemd/systemd-udevd
syslog 606 0.0 0.1 224360 4244 ? Ssl ноя18 0:01 /usr/sbin/rsyslogd -n –i.
.
root 649 0.0 0.0 20320 3036 ? ❷ Ss ноя18 0:00 /usr/sbin/cron -f
daemon 675 0.0 0.0 3736 2184 ? Ss ноя18 0:00 /usr/sbin/atd –f
.
root 21545 0.0 0.0 5560 3420 tty4 Ss ноя18 0:00 /bin/login -p —
fitz 28152 0.0 0.0 2600 1784 tty4 S 01:38 0:00 _ -sh
fitz 28162 0.0 0.0 12948 3584 tty4 S+ 01:38 0:00 _ bash
finn 12989 0.2 0.012092 3988 tty4 ❸ S+ 13:47 0:00 _ man ps
finn 13000 0.0 0.0 10764 2544 tty4 S+ 13:47 0:00 _ pager

info

За­час­тую демоны име­ют суф­фикс d в кон­це наз­вания, нап­ример sshd — это secure shell daemon, а rsyslogd — rocket system logging daemon, и т. д.

Сис­темные (ядер­ные) ❶ про­цес­сы (gра­виль­нее — ядер­ные нити, т. к. выпол­няют­ся они в общей памяти ядра опе­раци­онной сис­темы) выпол­няют парал­лель­ные час­ти яд­ра опе­раци­онной сис­темы, поэто­му не обла­дают ни инди­виду­аль­ной вир­туаль­ной памятью VSZ, ни управля­ющим тер­миналом TTY. Более того, ядер­ные про­цес­сы не выпол­няют отдель­ную прог­рамму, заг­ружа­емую из ELF-фай­ла, поэто­му их име­на COMMAND явля­ются условны­ми и изоб­ража­ются в квад­ратных скоб­ках, а кро­ме того, они име­ют осо­бое сос­тояние I в стол­бце STAT.

Атрибуты процесса

Про­цесс в опе­раци­онной сис­теме явля­ется основным активным субъ­ектом, вза­имо­дей­ству­ющим с окру­жающи­ми его объ­екта­ми — фай­лами и фай­ловыми сис­темами, дру­гими про­цес­сами, устрой­ства­ми и пр. Воз­можнос­ти про­цес­са выпол­нять те или иные дей­ствия по отно­шению к дру­гим объ­ектам опре­деля­ются его спе­циаль­ными свой­ства­ми — атри­бута­ми про­цес­са.

Маркеры доступа

Воз­можнос­ти про­цес­са по отно­шению к объ­ектам, дос­туп к которым раз­гра­ничи­вает­ся при помощи дис­кре­цион­ных механиз­мов (в час­тнос­ти, к фай­лам дерева катало­гов) опре­деля­ются зна­чени­ями его атри­бутов, фор­миру­ющих его DAC-мар­кер дос­тупа, а имен­но — атри­бута­ми RUID, RGID, EUID, EGID, см. credentials .

Эф­фектив­ные иден­тифика­торы EUID (effective user identifier) и EGID (effective group identifier) ука­зыва­ют на «эффектив­ных» поль­зовате­ля и груп­пу, исполь­зующих­ся дис­кре­цион­ными механиз­мами для опре­деле­ния прав дос­тупа про­цес­са к фай­лам и дру­гим объ­ектам сог­ласно наз­начен­ному им режиму или спис­ку дос­тупа. Атри­буты RUID (real user identifier) и RGID (real group identifier) ука­зыва­ют на «нас­тоящих» поль­зовате­ля и груп­пу, «управля­ющих» про­цес­сом.

Пер­вому про­цес­су поль­зователь­ско­го сеан­са (в слу­чае регис­тра­ции в сис­теме
с исполь­зовани­ем алфа­вит­но‑циф­рового тер­минала — коман­дно­му интер­пре­тато­ру) наз­нача­ют атри­буты RUID/EUID и RGID/EGID рав­ными иден­тифика­торам зарегис­три­ровав­шегося поль­зовате­ля и его пер­вичной груп­пы. Пос­леду­ющие про­цес­сы поль­зователь­ско­го сеан­са нас­леду­ют зна­чения атри­бутов, т. к. порож­дают­ся в резуль­тате кло­ниро­вания при помощи fork . В при­мере из сле­дующе­го лис­тинга при помощи коман­ды id показа­ны зна­чения EUID/EGID поль­зователь­ско­го сеан­са и их нас­ледова­ние от коман­дно­го интер­пре­тато­ра, что явным обра­зом под­твержда­ет коман­да ps .

DAC-мар­кер дос­тупа про­цес­са — атри­буты RUID, EUID, RGID, EGID

fitz@ubuntu:~$ id
uid=1006(fitz) gid=1008(fitz) груп­пы=1008(fitz)
fitz@ubuntu:~$ ps fo euid,ruid,egid,rgid,user,group,tty,cmd
EUID RUID EGID RGID USER GROUP TT CMD
1006 1006 1008 1008 fitz fitz pts/2 -bash
1006 1006 1008 1008 fitz fitz pts/2 _ ps fo euid,uid,egid. tty,cmd

Из­менение иден­тифика­торов EUID/EGID про­цес­са про­исхо­дит при сра­баты­вании механиз­ма неяв­ной переда­чи пол­номочий, осно­ван­ном на допол­нитель­ных атри­бутах SUID/SGID фай­лов прог­рамм. При запус­ке таких прог­рамм пос­редс­твом сис­темно­го вызова exec атри­буты EUID/EGID запус­кающе­го про­цес­са уста­нав­лива­ются рав­ными иден­тифика­торам UID/GID вла­дель­ца запус­каемой прог­раммы. В резуль­тате про­цесс, в который будет заг­ружена такая прог­рамма, будет обла­дать пра­вами вла­дель­ца прог­раммы, а не пра­вами поль­зовате­ля, запус­тивше­го эту прог­рамму.

В сле­дующем лис­тинге при­веден типич­ный при­мер исполь­зования механиз­ма неяв­ной переда­чи пол­номочий при выпол­нении команд passwd и wall . При сме­не пароля поль­зовате­лем при помощи прог­раммы / usr/ bin/ passwd ее про­цесс получа­ет необ­ходимое пра­во записи ① в файл / etc/ shadow в резуль­тате переда­чи пол­номочий ❶ супер­поль­зовате­ля root ( UID=0) . При переда­че широко­веща­тель­ного сооб­щения всем поль­зовате­лям при помощи / usr/ bin/ wall необ­ходимо иметь пра­во записи ② в их фай­лы устрой­ств / dev/ tty* , которое появ­ляет­ся ❷ в резуль­тате переда­чи пол­номочий груп­пы tty ( GID = 5) .

Ат­рибуты фай­ла SUID/SGID и атри­буты про­цес­са RUID, EUID, RGID, EGID

fitz@ubuntu:~$ who
fitz pts/0 2019-11-22 00:52 (:0.0)
fitz pts/1 2019-11-22 00:53 (:0.0)
fitz pts/2 2019-11-22 01:06 (:0.0)

fitz@ubuntu:~$ ls -la /etc/shadow /dev/pts/*
crw—w—- 1 fitz tty 136, 2 ноя 19 12:00 /dev/pts/1
② crw—w—- 1 fitz tty 136, 3 ноя 19 13:53 /dev/pts/2
c——— 1 root root 5, 2 ноя 17 03:30 /dev/pts/ptmx
① -rw-r—— 1 root shadow 1647 ноя 19 12:27 /etc/shadow

fitz@ubuntu:~$ ls -l /usr/bin/passwd /usr/bin/wall
-rwsr-xr-x 1 root root 67992 авг 29 16:00 /usr/bin/passwd
-rwxr-sr-x 1 root tty 35048 авг 21 16:19 /usr/bin/wall

fitz@ubuntu:~$ ls -ln /usr/bin/passwd /usr/bin/wall
-rwsr-xr-x 1 0 0 67992 авг 29 16:00 /usr/bin/passwd
-rwxr-sr-x 1 0 5 35048 авг 21 16:19 /usr/bin/wall

fitz@ubuntu:~$ ps ft pts/1,pts/2 o pid,ruid,rgid,euid,egid,tty,cmd
PID RUID RGID EUID EGID TT CMD
27883 1006 1008 1006 1008 pts/2 bash
❷ 27937 1006 1008 1006 5 pts/2 _ wall
27124 1006 1008 1006 1008 pts/1 bash
❶ 27839 1006 1008 0 1008 pts/1 _ passwd

По отно­шению к объ­ектам, дос­туп к которым огра­ничи­вает­ся при помощи ман­датных механиз­мов, воз­можнос­ти про­цес­са опре­деля­ются зна­чени­ями его МАС‑мар­кера дос­тупа, а имен­но — атри­бутом ман­датной мет­ки LABEL. Как и RUID/EUID/RGID/EGID, атри­бут LABEL наз­нача­ется пер­вому про­цес­су сеан­са поль­зовате­ля явным обра­зом, а затем нас­леду­ется при кло­ниро­вании про­цес­сами‑потом­ками от про­цес­сов‑родите­лей. В при­мере из при­веден­ного ниже лис­тинга при помощи коман­ды id показан атри­бут LABEL сеан­са поль­зовате­ля, а при помощи коман­ды ps — его явное нас­ледова­ние от про­цес­са‑родите­ля.

Ана­логич­но изме­нени­ям EUID/EGID про­цес­са, про­исхо­дящим при запус­ке SUID-ной/SGID-ной прог­раммы, изме­нение мет­ки LABEL про­цес­са про­исхо­дит (сог­ласно ман­датным пра­вилам ❶) в сис­темном вызове exec при запус­ке прог­раммы, помечен­ной соот­ветс­тву­ющей ман­датной мет­кой фай­ла. Так, нап­ример, при запус­ке прог­раммы / usr/ sbin/ dhclient с типом dhcpc_exec_t ее ман­датной мет­ки ❸ про­цесс при­обре­тает тип dhcpc_t сво­ей ман­датной мет­ки ❹, в резуль­тате чего сущес­твен­но огра­ничи­вает­ся в пра­вах дос­тупа к раз­ным объ­ектам опе­раци­онной сис­темы.

MAC-мар­кер дос­тупа про­цес­са — ман­датная мет­ка selinux

fitz@ubuntu:~$ ssh lich@fedora
lich@fedora’s password:
Last login: Sat Nov 21 14:25:16 2015

[ lich@centos ~] $ id -Z
staff_u:staff_r:staff_t:s0-s0:c0.c1023

[ lich@centos ~] $ ps Zf
LABEL PID TTY STAT TIME COMMAND
staff_u:staff_r:staff_t:s0-s0:c0.c1023 31396 pts/0 Ss 0:00 -bash
staff_u:staff_r:staff_t:s0-s0:c0.c1023 31835 pts/0 R+ 0:00 _ ps Zf
staff_u:staff_r:staff_t:s0-s0:c0.c1023 31334 tty2 Ss+ 0:00 -bash
[ lich@centos ~] $ sesearch -T -t dhcpc_exec_t -c process
Found 19 semantic te rules:
.
❶ type_transition NetworkManager_t dhcpc_exec_t : process dhcpc_t;
.

[ lich@centos ~] $ ls -Z / usr/ sbin/ dhclient
❷ -rwxr-xr-x. root root system_u:object_r:dhcpc_exec_t:s0 /usr/sbin/dhclient
[ lich@centos ~] $ ps -ZC dhclient
LABEL PID TTY TIME CMD
❸ system_u:system_r:dhcpc_t:s0 2120 ? 00:00:00 dhclient
system_u:system_r:dhcpc_t:s0 4320 ? 00:00:00 dhclient

Привилегии

Еще одним важ­ным атри­бутом про­цес­са, опре­деля­ющим его воз­можнос­ти по исполь­зованию сис­темных вызовов, явля­ются при­виле­гии про­цес­са cababilities . Нап­ример, обла­дание при­виле­гией CAP_SYS_PTRACE раз­реша­ет про­цес­сам трас­сиров­щиков strace и ltrace , исполь­зующих сис­темный вызов ptrace , трас­сировать про­цес­сы лю­бых поль­зовате­лей (а не толь­ко «свои», EUID которых сов­пада­ет с EUID трас­сиров­щика). Ана­логич­но, при­виле­гия CAP_SYS_NICE раз­реша­ет изме­нять при­ори­тет, уста­нав­ливать при­вяз­ку к про­цес­сорам и наз­начать алго­рит­мы пла­ниро­вания про­цес­сов и нитей лю­бых поль­зовате­лей, а при­виле­гия CAP_KILL раз­реша­ет посылать сиг­налы про­цес­сам лю­бых поль­зовате­лей.

Яв­ная при­виле­гия «вла­дель­ца» CAP_FOWNER поз­воля­ет про­цес­сам изме­нять режим и спис­ки дос­тупа, ман­датную мет­ку, рас­ширен­ные атри­буты и фла­ги любых фай­лов так, слов­но про­цесс выпол­няет­ся от лица вла­дель­ца фай­ла. При­виле­гия CAP_LINUX_IMMUTABLE раз­реша­ет управлять фла­гами фай­лов i , immutable и a , append , а при­виле­гия CAP_SETFCAP — уста­нав­ливать «фай­ловые» при­виле­гии запус­каемых прог­рамм.

Не­обхо­димо отме­тить, что имен­но обла­дание пол­ным набором при­виле­гий дела­ет поль­зовате­ля root ( UID=0) в Linux супер­поль­зовате­лем. И наобо­рот, обыч­ный, неп­ривиле­гиро­ван­ный поль­зователь (в смыс­ле UID≠0 ) не обла­дает никаки­ми явны­ми при­виле­гиями (неяв­но он обла­дает при­виле­гией вла­дель­ца для всех сво­их объ­ектов). Наз­начение при­виле­гий про­цес­са (здесь допуще­но намерен­ное упро­щение механиз­ма нас­ледова­ния и наз­начения при­виле­гий при fork и exec без потери смыс­ла) про­исхо­дит при запус­ке прог­раммы при помощи сис­темно­го вызова exec , исполня­емый файл которо­го помечен «фай­ловыми» при­виле­гиями.

В при­мере из сле­дующе­го лис­тинга иллюс­три­рует­ся получе­ние спис­ка при­виле­гий про­цес­са при помощи ути­литы getpcaps . Как и ожи­далось, про­цесс postgres ( PID=6711) , работа­ющий от лица обыч­ного (неп­ривиле­гиро­ван­ного, в смыс­ле UID≠0 ) псев­дополь­зовате­ля postgres , не име­ет ❶ никаких при­виле­гий, а про­цесс apache2 ( PID=10129) , работа­ющий от лица супер­поль­зовате­ля root ( UID=0) , име­ет пол­ный ❷ набор при­виле­гий. Одна­ко про­цесс NetworkManager ( PID=646) выпол­няет­ся от лица «супер­поль­зовате­ля», лишен­ного ❸ боль­шинс­тва сво­их при­виле­гий, т. к. ему их умыш­ленно умень­шили при его запус­ке (см. systemd в гла­ве 8) до минималь­но необ­ходимо­го набора, дос­таточ­ного для выпол­нения его фун­кций (xто спо­собс­тву­ет обес­печению защищен­ности опе­раци­онной сис­темы).

При­виле­гии (capabilities) про­цес­са

fitz@ubuntu:~$ ps fo user,pid,cmd -C NetworkManager,postgres,apache2
USER PID CMD
root 10129 /usr/sbin/apache2 -k start
www-data 10131 _ /usr/sbin/apache2 -k start
www-data 10132 _ /usr/sbin/apache2 -k start
postgres 6711 /usr/lib/postgresql/11/bin/postgres -D /var/lib/postgresql/11/main .
postgres 6713 _ postgres: 11/main: checkpointer
postgres 6714 _ postgres: 11/main: background writer
postgres 6715 _ postgres: 11/main: walwriter
postgres 6716 _ postgres: 11/main: autovacuum launcher
postgres 6717 _ postgres: 11/main: stats collector
postgres 6718 _ postgres: 11/main: logical replication launcher
root 646 /usr/sbin/NetworkManager —no-daemon

fitz@ubuntu:~$ getpcaps 6711
❶ Capabilities for 6711′: =
❷ fitz@ubuntu: ~$ getpcaps 10129
Capabilities for 10129′: = 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+ep
❸ fitz@ubuntu:~$ getpcaps 646
Capabilities for `646′: = cap_dac_override,cap_kill,cap_setgid,cap_setuid,cap_net_bind_service,cap_net_admin,
cap_net_raw,cap_sys_module,cap_sys_chroot,cap_audit_write+ep

В лис­тинге ниже показан типич­ный при­мер при­мене­ния от­дель­ных при­виле­гий там, где клас­сичес­ки при­меня­ется неяв­ная переда­ча всех пол­номочий супер­поль­зовате­ля при помощи механиз­ма SUID/SGID. Нап­ример, «обыч­ная» ути­лита ping для выпол­нения сво­ей работы дол­жна соз­дать «необ­работан­ный» raw сетевой сокет, что явля­ется с точ­ки зре­ния ядра при­виле­гиро­ван­ной опе­раци­ей. В ста­рых сис­темах (акту­аль­но для Ubuntu до вер­сии 18.10 вклю­читель­но, начиная с 19.04 все уже «пра­виль­но из короб­ки») прог­рамма / bin/ ping наделя­лась атри­бутом SUID ❶ и находи­лась во вла­дении супер­поль­зовате­ля root , чьи пра­ва и переда­вались при ее запус­ке. С точ­ки зре­ния защищен­ности сис­темы это не соот­ветс­тву­ет здра­вому смыс­лу, под­ска­зыва­юще­му наделять прог­раммы минималь­но необ­ходимы­ми воз­можнос­тями, дос­таточ­ными для их фун­кци­они­рова­ния. Для соз­дания «необ­работан­ных» raw и пакет­ных packet сокетов дос­таточ­но толь­ко при­виле­гии CAP_NET_RAW , а весь супер­поль­зователь­ский набор при­виле­гий более чем избы­точен.

Де­леги­рова­ние при­виле­гий прог­раммы ping

fitz@ubuntu-1804:~$ ls -l /bin/ping
❶ -rwsr-xr-x 1 root root 64424 Jun 28 11:05 /bin/ping
fitz@ubuntu-1804:~$ ping ubuntu-1804
PING ubuntu-1804 (127.0.1.1) 56(84) bytes of data.
64 bytes from ubuntu-1804 (127.0.1.1): icmp_req=1 ttl=64 time=0.074 ms
^C
— ubuntu ping statistics —
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.074/0.074/0.074/0.000 ms

fitz@ubuntu-1804:~$ sudo chmod u-s /bin/ping
fitz@ubuntu-1804:~$ ls -l /bin/ping
-rwxr-xr-x 1 root root 64424 Jun 28 11:05 /bin/ping
fitz@ubuntu-1804:~$ ping ubuntu-1804
ping: icmp open socket: Operation not permitted

❸ fitz@ubuntu-1804:~$ sudo setcap cap_net_raw+ep /bin/ping
fitz@ubuntu-1804:~$ getcap /bin/ping
/bin/ping = cap_net_raw+ep
fitz@ubuntu-1804:~$ ping ubuntu-1804
PING ubuntu (127.0.1.1) 56(84) bytes of data.
64 bytes from ubuntu (127.0.1.1): icmp_req=1 ttl=64 time=0.142 ms
^C
— ubuntu ping statistics —
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.142/0.142/0.142/0.000 ms

При отклю­чении переда­чи пол­номочий ❷ прог­рамма / bin/ ping лиша­ется воз­можнос­ти выпол­нять свои фун­кции, а при наз­начении ей при помощи коман­ды setcap «фай­ловой» при­виле­гии CAP_NET_RAW ❸ фун­кци­ональ­ность воз­вра­щает­ся в пол­ном объ­еме, т. к. при­водит к уста­нов­ке «про­цес­сной» при­виле­гии CAP_NET_RAW при запус­ке этой прог­раммы. Для прос­мотра при­виле­гий, делеги­руемых при запус­ке прог­рамм, исполь­зует­ся пар­ная коман­да getcap .

Ана­логич­но, при исполь­зовании ана­лиза­торов сетево­го тра­фика tshark и/или wireshark, вызыва­ющих для зах­вата сетевых пакетов ути­литу dumpcap, тре­бует­ся откры­вать как «необ­работан­ные» raw , так и пакет­ные packet сетевые сокеты, что тре­бует той же при­виле­гии CAP_NET_RAW . Клас­сичес­кий спо­соб при­мене­ния ана­лиза­торов пакетов сос­тоит в исполь­зовании явной переда­чи всех пол­номочий супер­поль­зовате­ля (при помощи su или sudo ) при их запус­ке, что опять не соот­ветс­тву­ет минималь­но необ­ходимым и дос­таточ­ным тре­бова­ниям к раз­решен­ным воз­можнос­тям прог­рамм.

Де­леги­рова­ние при­виле­гий прог­рамме tshark

fitz@ubuntu:~$ tshark
tshark: There are no interfaces on which a capture can be done
itz@ubuntu:~$ strace -fe execve tshark
execve( «/ usr/ bin/ tshark», [ «tshark»], [/ * 23 vars */]) = 0
Process 8951 attached
[ pid 8951] execve( «/ usr/ bin/ dumpcap», [ «/ usr/ bin/ dumpcap», «-D», «-Z», «none»]. ) = 0
Process 8951 detached
— SIGCHLD ( Child exited) @ 0 ( 0) —
tshark: There are no interfaces on which a capture can be done
fitz@ubuntu:~$ ls -la /usr/bin/dumpcap
-rwxr-xr-x 1 root root 104688 Sep 5 19:43 /usr/bin/dumpcap
fitz@ubuntu:~$ getcap /usr/bin/dumpcap

fitz@ubuntu:~$ sudo setcap cap_net_raw+ep /usr/bin/dumpcap
fitz@ubuntu:~$ getcap /usr/bin/dumpcap
/usr/bin/dumpcap = cap_net_raw+ep
fitz@ubuntu:~$ tshark -i wlan0
Capturing on wlan0
0.307205 fe80::895d:9d7d:f0b3:a372 → ff02::1:ff96:2df6 ICMPv6 86 Neighbor Solicitation
0.307460 SuperMic_74:0e:90 → Spanning-tree-(for-bridges)_00 STP 60 Conf. Root = 32768/0/00:25:90:74:0e:90 Cost = 0 Port = 0x8001
.

Для эффектив­ного исполь­зования ана­лиза­торов тра­фика неп­ривиле­гиро­ван­ными поль­зовате­лями дос­таточ­но делеги­ровать их про­цес­сам зах­вата пакетов при­виле­гию CAP_NET_RAW при помощи «фай­ловых» при­виле­гий CAP_NET_RAW для прог­раммы зах­вата /usr/bin/dumpcap, что и про­иллюс­три­рова­но в пре­дыду­щем лис­тинге.

info

Не­обхо­димо заметить, что все это уже дос­таточ­но дав­но уме­ет про­делы­вать инстал­лятор при уста­нов­ке пакета wireshark-common (от которо­го зависят пакеты tshark и wireshark), если утверди­тель­но отве­тить на воп­рос инстал­лятора ‘Should non-superusers be able to capture packets?’. Одна­ко для более прос­того tcpdump такой услу­ги не пре­дос­тавле­но ☺.

Другие атрибуты

Пе­ремен­ные окру­жения и текущий рабочий каталог на повер­ку тоже ока­зыва­ются атри­бута­ми про­цес­са, которые мож­но получить при помощи команд ps и pwdx соот­ветс­твен­но.

Пе­ремен­ные окру­жения про­цес­са

fitz@ubuntu:~$ ps fe
PID TTY STAT TIME COMMAND
21872 pts/2 S 0:00 -bash USER=fitz LOGNAME=fitz HOME=/home/fitz PATH=/usr/.
22904 pts/2 R+ 0:00 _ ps fe LANGUAGE=ru:ko:en LC_ADDRESS=ru_RU.UTF-8 .

Те­кущий рабочий каталог про­цес­са

fitz@ubuntu:~$ ps fx
PID TTY STAT TIME COMMAND
22984 pts/0 S 0:00 -bash
23086 pts/0 S+ 0:00 _ man ps
23097 pts/0 S+ 0:00 _ pager
21872 pts/2 S 0:00 -bash
23103 pts/2 R+ 0:00 _ ps fx

fitz@ubuntu:~$ pwdx 23097 22984
23097: /home/fitz
22984: /home/fitz

What does pam_systemd.so do?

I switched my SD card from the fast RaspberryPi 4 to the RaspberryPi 2. Now, logging into it with ssh -vv took about 3 minutes and got stuck at pledge: network . This question discusses such behaviour and my solution was to comment out session optional pam_systemd.so in /etc/pam.d/common-session . But I would like to know what this actually does. I understand that it is related to openening a user-session but I am not familiar with why it is important. My journalctl | grep pam shows this:

Dec 29 15:59:07 RPi4 sshd[1392]: pam_unix(sshd:session): session opened for user admin by (uid=0) Dec 29 15:59:08 RPi4 systemd: pam_unix(systemd-user:session): session opened for user admin by (uid=0) Dec 29 16:02:01 RPi4 sudo: pam_unix(sudo:session): session opened for user root by admin(uid=0) Dec 29 16:02:01 RPi4 sudo: pam_unix(sudo:session): session closed for user root Dec 29 16:02:23 RPi4 sudo: pam_unix(sudo:session): session opened for user root by admin(uid=0) 

asked Dec 29, 2020 at 16:33
439 5 5 silver badges 18 18 bronze badges
Have you already read the output of man pam_systemd ?
Dec 29, 2020 at 16:48

Well, I did now. But I am not able to grasp the thing. Why do I need such a module to register a user session with the systemd login manager? Why am I able to login without this module beeing active? What is the difference? Maybe the environment variables are important. Does it make a difference if my server is headless?

Dec 29, 2020 at 17:52

1 Answer 1

pam_systemd is the plug-in that makes the difference between the classic (pre-systemd) login process and the systemd -aware one.

Without it, the login process works as it did with SysVinit: if a user process daemonizes (i.e. closes its standard input, output & error streams, forks twice, then has the child process die leaving the grandchild an orphan, reparented to UID #1 by the kernel), there will be no way to track which session it belonged to. Instead of the entire login session and all its children being reliably encapsulated into a separate control group, all the processes go into the common pile. So the enforcement of per-session resource limits can’t be done either.

Also, the user run-time directory /run/user// won’t get created, which might disable some features of some desktop environments, and things that attempt to be multi-session friendly like GnuPG Agent for example. And last but not least, the user@.service system service and any per-user systemd services managed by it will not be started: there will be no session D-Bus for this user/session, nor Pulseaudio. See systemctl —user (in a system with a working per-user systemd services).

At logout, without pam_systemd being in play, the logout process won’t be able to cleanly enforce that all the processes of the user session are definitely cleaned up at end of session (should the system administrator wish so; see KillUserProcesses= in logind.conf(5) ).

You’ll also lose a simple way to plug in non-root actions to events like your user login/logout, or non-root actions conditional to things like filesystems being mounted or hotpluggable network/storage/bluetooth/other devices being present or appearing later during the login session.

If your goal is a lean, mean single-task machine, you might regard this as a successful amputation of a lot of unnecessary stuff; but depending on your goal, you might not.

Anyway, the question you referred to indicates the problem might be caused by something causing the system D-Bus to restart, which would require restarting systemd-logind and possibly other system services that depend on the system D-Bus.

The root cause for your login slowness problem might also have been something like Pulseaudio being still configured to expect RasPi 4 hardware and being confused on not finding it.

On a systemd -based installation, there may be at least two relevant instances of D-Bus for each user session: a system D-Bus that enables selective passing of system-wide status information and control as configured by polkit , and a session D-Bus for user-level things. Some GUI desktop environments may fire up a small extra D-Bus instance or two for handling accessibility and/or internationalization (input methods for Chinese/Japanese/Korean characters and similar).

Статус сервисов systemd

Перевод: systemd services status

systemctl status

systemctl status

Совсем недавно узнал для себя, что можно запускать systemctl status без параметров – никакого имени сервиса не указывать. И тогда получается очень полезный список в виде дерева сервисов и процессов на вашей Linux системе. Сервисы systemd

Как вы уже можете знать, в современных Linux системах уже не используются скрипты инициализации в /etc/init.d. Вместо них создаются и используются сервисы systemd – очень удобно и для обслуживания сервисов, и для подтверждения их текущего статуса (команда journalctl отлично подходит для просмотра логов).

Смотрим на сервисы systemd: команда systemctl

Без всяких дополнительных параметров, systemctl status показывает дерево вроде такого:

greys@sd-147674:~$ systemctl status ● sd-147674 State: running Jobs: 0 queued Failed: 0 units Since: Sat 2019-11-23 08:45:20 CET; 1 months 20 days ago CGroup: / ├─user.slice │ └─user-1000.slice │ ├─[email protected] │ │ └─init.scope │ │ ├─19250 /lib/systemd/systemd --user │ │ └─19251 (sd-pam) │ └─session-1309.scope │ ├─19247 sshd: greys [priv] │ ├─19264 sshd: greys@pts/0 │ ├─19265 -bash │ ├─19278 systemctl status │ └─19279 pager ├─init.scope │ └─1 /sbin/init └─system.slice ├─systemd-udevd.service │ └─361 /lib/systemd/systemd-udevd ├─cron.service │ └─541 /usr/sbin/cron -f ├─bind9.service │ └─587 /usr/sbin/named -u bind ├─systemd-journald.service │ └─345 /lib/systemd/systemd-journald ├─mdmonitor.service │ └─484 /sbin/mdadm --monitor --scan ├─ssh.service │ └─599 /usr/sbin/sshd -D ├─openntpd.service │ ├─634 /usr/sbin/ntpd -f /etc/openntpd/ntpd.conf │ ├─635 ntpd: ntp engine │ └─637 ntpd: dns engine ├─rsyslog.service │ └─542 /usr/sbin/rsyslogd -n -iNONE . 

Например, видно названия systemd сервисов вроде cron.service или ssh.service, а также название процесса, который эти сервисы предоставляет, и номер этого процесса (PID).

ИНТЕРЕСНО: заметили, как сервис времени openNTPd.service теперь предоставляется аж тремя процессами сразу: ntpd и ещё две его вариации (NTP engine и DNS engine).

Полезные Ссылки

  • systemd reference
  • systemctl command
  • journalctl command
  • Linux Commands

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *