nameref (
В Bash функции по умолчанию работают с копиями значений или с глобальными переменными. Но есть механизм, который позволяет имитировать “ссылки” -
▪️ Что такое nameref
▪️ Передача массива в функцию без копирования
Классическая проблема:
С
▪️ Модификация массива внутри функции
▪️ Где это особенно полезно
функции обработки конфигураций
парсинг JSON → массивы ключей/значений
работа с таблицами данных
построение библиотек на Bash без глобальных переменных
▪️ Важный момент
• значения
• выражения
• результаты команд
Только имя переменной.
▪️ Ограничения
нельзя безопасно переиспользовать ссылку на разные переменные в одном scope без переопределения
сложнее отлаживать (меняется оригинальный объект)
требует Bash 4.3+
▪️ Почему это важно
Без
BashTex📱 #scripts #linux
declare -n): ссылки на переменные и передача массивов в функцииВ Bash функции по умолчанию работают с копиями значений или с глобальными переменными. Но есть механизм, который позволяет имитировать “ссылки” -
nameref.declare -n создаёт ссылку на другую переменную:arr=(1 2 3)
declare -n ref=arr
ref[0]=999
echo "${arr[0]}"
Результат:999
ref не хранит данные - он указывает на arr.Классическая проблема:
func() {
local arr=("$@")
}
Это создаёт копию массива.С
nameref:func() {
local -n arr=$1
echo "${arr[0]}"
}
Вызов:data=(10 20 30)
func data
Функция работает с оригинальным массивом.func() {
local -n arr=$1
arr[1]=999
}
data=(10 20 30)
func data
echo "${data[@]}"
Результат:
10 999 30
функции обработки конфигураций
парсинг JSON → массивы ключей/значений
работа с таблицами данных
построение библиотек на Bash без глобальных переменных
nameref работает только с именами переменных:local -n ref=$1
Нельзя передавать:• значения
• выражения
• результаты команд
Только имя переменной.
нельзя безопасно переиспользовать ссылку на разные переменные в одном scope без переопределения
сложнее отлаживать (меняется оригинальный объект)
требует Bash 4.3+
Без
nameref Bash-функции либо копируют данные, либо используют глобальное состояние. declare -n даёт третий вариант — передачу по ссылке, что делает сложные скрипты заметно чище и ближе к языкам общего назначения.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Автоматическая реакция на OOM через systemd и cgroups: перезапуск и контроль памяти
OOM (Out Of Memory) - это не просто “закончилась память”. В Linux это механизм, при котором ядро начинает принудительно завершать процессы, чтобы система не упала целиком.
Проблема в том, что без контроля первым под нож часто попадает не тот процесс, который должен.
▪️ Как systemd влияет на OOM
systemd работает поверх cgroups и может задавать приоритеты “жертвенности” процессов:
▪️ Влияние на OOM Killer
Можно управлять приоритетом уничтожения:
▪️ Автоматический перезапуск после OOM
systemd может перезапускать сервис даже после убийства ядром:
▪️ Практический сценарий
Типичная ситуация:
• сервис разогнал память
• ядро убивает его через OOM
• systemd фиксирует падение
• запускает новый экземпляр
• cgroups не дают повторно выйти за лимит
▪️ Где начинается реальный контроль
Ключевой момент - сочетание:
• MemoryMax (жёсткий лимит)
• MemoryHigh (раннее давление)
• OOMScoreAdjust (приоритет убийства)
• Restart=on-failure (самовосстановление)
▪️ Почему это важно
Без cgroups OOM - это хаос: ядро выбирает жертву само.
С systemd это превращается в управляемую систему: процесс либо не доходит до OOM, либо корректно переживает его через перезапуск и ограничение ресурсов.
BashTex📱 #scripts #linux
OOM (Out Of Memory) - это не просто “закончилась память”. В Linux это механизм, при котором ядро начинает принудительно завершать процессы, чтобы система не упала целиком.
Проблема в том, что без контроля первым под нож часто попадает не тот процесс, который должен.
systemd работает поверх cgroups и может задавать приоритеты “жертвенности” процессов:
systemd-cgtop
Показывает, какие группы потребляют память.
▪️Контроль памяти на уровне unit
Можно ограничить сервис:
[Service]
MemoryMax=500M
Теперь процесс физически не сможет превысить лимит.
Дополнительно:
MemoryHigh=400M
Это мягкий порог - systemd начинает давить на процесс раньше, чем наступит OOM.Можно управлять приоритетом уничтожения:
OOMScoreAdjust=-500
или наоборот:
OOMScoreAdjust=500
Чем выше значение - тем выше шанс, что процесс будет убит первым.systemd может перезапускать сервис даже после убийства ядром:
[Service]
Restart=on-failure
RestartSec=2
Это работает и для OOM-kill, потому что процесс считается завершённым с ошибкой.Типичная ситуация:
• сервис разогнал память
• ядро убивает его через OOM
• systemd фиксирует падение
• запускает новый экземпляр
• cgroups не дают повторно выйти за лимит
Ключевой момент - сочетание:
• MemoryMax (жёсткий лимит)
• MemoryHigh (раннее давление)
• OOMScoreAdjust (приоритет убийства)
• Restart=on-failure (самовосстановление)
Без cgroups OOM - это хаос: ядро выбирает жертву само.
С systemd это превращается в управляемую систему: процесс либо не доходит до OOM, либо корректно переживает его через перезапуск и ограничение ресурсов.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Проверка файловых систем, смонтированных с опасными опциями
При аудите Linux обычно проверяют права доступа и SUID-биты. Но не менее важно посмотреть, как смонтированы файловые системы.
Если временный каталог или пользовательский раздел смонтирован с
▪️ Посмотреть все точки монтирования
Самый удобный способ:
▪️ На что обратить внимание
Опции монтирования:
•
•
•
Для каталогов вроде
▪️ Пример проверки
Более безопасный вариант:
▪️ Проверка через fstab
Чтобы убедиться, что настройки сохранятся после перезагрузки:
▪️ Почему это важно
Представьте, что злоумышленник смог записать файл в
Несколько минут на проверку параметров монтирования могут устранить целый класс потенциальных проблем ещё до того, как они будут использованы.
BashTex📱 #scripts #linux
При аудите Linux обычно проверяют права доступа и SUID-биты. Но не менее важно посмотреть, как смонтированы файловые системы.
Если временный каталог или пользовательский раздел смонтирован с
exec, suid или dev, это может значительно расширить поверхность атаки.Самый удобный способ:
findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS
Или классический вариант:mount
Опции монтирования:
•
exec - разрешает запуск исполняемых файлов.•
suid - позволяет работать SUID/SGID-битам.•
dev - разрешает использование файлов устройств.Для каталогов вроде
/tmp, /var/tmp или /dev/shm обычно безопаснее использовать противоположные опции:noexec,nosuid,nodev
findmnt -no TARGET,OPTIONS /tmp
Если вывод содержит:rw,relatime
значит ограничения отсутствуют.Более безопасный вариант:
rw,nosuid,nodev,noexec
Чтобы убедиться, что настройки сохранятся после перезагрузки:
grep -vE '^\s*#|^$' /etc/fstab
Ищите разделы, где для временных или пользовательских файловых систем не заданы защитные опции.Представьте, что злоумышленник смог записать файл в
/tmp. Если раздел смонтирован с exec, его можно сразу запустить. Если ещё и разрешён suid или dev, последствия могут быть значительно серьёзнее.Несколько минут на проверку параметров монтирования могут устранить целый класс потенциальных проблем ещё до того, как они будут использованы.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Скрипт поиска процессов с аномальным потреблением памяти
Когда на сервере заканчивается память, первое желание - открыть
▪️ Быстрый рейтинг по RSS
Размер физической памяти, занимаемой процессом (RSS), можно посмотреть так:
▪️ Автоматическая проверка
Например, вывести процессы, использующие больше 1 ГБ памяти:
▪️ Если нужен максимум информации
Часть данных о процессе хранится в
Эти значения могут сильно отличаться.
▪️ Не путайте RSS и VSZ
Большой
При поиске “пожирателей” памяти обычно ориентируются именно на
▪️ Почему это важно
Периодическая сортировка процессов по RSS помогает заметить утечки памяти ещё до того, как сработает OOM Killer. Особенно полезно для Java, Python, Node.js и других долгоживущих сервисов.
BashTex📱 #bash #linux
Когда на сервере заканчивается память, первое желание - открыть
top. Но он показывает только текущее состояние. Для автоматизации удобнее получить список самых “тяжёлых” процессов и использовать его в скриптах.Размер физической памяти, занимаемой процессом (RSS), можно посмотреть так:
ps -eo pid,user,comm,rss --sort=-rss | head -10
Поле rss выводится в килобайтах, поэтому сразу видно, кто потребляет больше всего ОЗУ.Например, вывести процессы, использующие больше 1 ГБ памяти:
ps -eo pid,comm,rss \
| awk '$3 > 1048576 {
printf "%-8s %-20s %.1f MB\n", $1, $2, $3/1024
}'
Такой вывод уже удобно отправлять в отчёт или систему мониторинга.Часть данных о процессе хранится в
/proc:grep -E 'VmRSS|VmSize' /proc/1234/status
VmRSS - реально занятая физическая память.VmSize - всё адресное пространство процесса, включая ещё не загруженные страницы.Эти значения могут сильно отличаться.
Большой
VSZ ещё не означает проблему. Многие приложения резервируют память заранее, но фактически используют лишь небольшую её часть.При поиске “пожирателей” памяти обычно ориентируются именно на
RSS.Периодическая сортировка процессов по RSS помогает заметить утечки памяти ещё до того, как сработает OOM Killer. Особенно полезно для Java, Python, Node.js и других долгоживущих сервисов.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Анализ активных UNIX-сокетов: поиск неожиданных IPC-соединений
При аудите обычно смотрят TCP- и UDP-порты, но многие сервисы вообще не используют сеть. Вместо этого они обмениваются данными через UNIX-сокеты.
Именно поэтому их тоже стоит периодически проверять.
▪️ Посмотреть все UNIX-сокеты
Самый удобный способ:
▪️ Получить больше информации
Если нужны процессы-владельцы:
▪️ На что обратить внимание
Особый интерес представляют сокеты в нестандартных местах:
▪️ Найти сокеты через файловую систему
▪️ Когда это полезно
UNIX-сокеты используют Docker, Podman, PostgreSQL, Redis, Nginx, PHP-FPM, systemd и десятки других сервисов.
Неожиданный сокет может указывать на недавно установленное ПО, самописный сервис или процесс, который не должен работать на сервере.
▪️ Почему это важно
Во многих инцидентах внимание уделяют только открытым сетевым портам. Но локальный IPC тоже может стать точкой входа или способом взаимодействия между процессами. Проверка UNIX-сокетов помогает увидеть часть инфраструктуры, которая остаётся незаметной при обычном аудите сети.
BashTex📱 #bash #linux
При аудите обычно смотрят TCP- и UDP-порты, но многие сервисы вообще не используют сеть. Вместо этого они обмениваются данными через UNIX-сокеты.
Именно поэтому их тоже стоит периодически проверять.
Самый удобный способ:
ss -xl
Ключ -x показывает UNIX-сокеты, а -l - только те, которые находятся в режиме ожидания соединений.Если нужны процессы-владельцы:
ss -xlp
Например:u_str LISTEN 0 128 /run/docker.sock
users:(("dockerd",pid=812,fd=7))
Сразу видно, какой процесс создал сокет.Особый интерес представляют сокеты в нестандартных местах:
/tmp/
/dev/shm/
/home/user/
Большинство системных сервисов используют /run или /var/run. Если сокет появился в /tmp, стоит проверить, кто его создал и зачем.find / -type s 2>/dev/null
Это покажет все файлы типа socket, даже если они сейчас не используются.UNIX-сокеты используют Docker, Podman, PostgreSQL, Redis, Nginx, PHP-FPM, systemd и десятки других сервисов.
Неожиданный сокет может указывать на недавно установленное ПО, самописный сервис или процесс, который не должен работать на сервере.
Во многих инцидентах внимание уделяют только открытым сетевым портам. Но локальный IPC тоже может стать точкой входа или способом взаимодействия между процессами. Проверка UNIX-сокетов помогает увидеть часть инфраструктуры, которая остаётся незаметной при обычном аудите сети.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥1
xargs против while read: где быстрее и безопаснееОбе конструкции позволяют обработать список файлов или строк, но работают они по-разному. Из-за этого одна может быть заметно быстрее, а другая - безопаснее.
xargsДопустим, нужно удалить все
.log-файлы:find . -name "*.log" | xargs rm
xargs собирает несколько аргументов и передаёт их одной команде, поэтому вместо сотен запусков rm будет всего несколько.Для большого количества файлов разница в производительности может быть существенной.
По умолчанию
xargs разделяет вход по пробелам и переводам строки.Если встретится файл:
my file.log
илиbackup
2025.log
команда отработает некорректно.Безопасный вариант:
find . -name "*.log" -print0 | xargs -0 rm
Здесь разделителем становится символ NULL, поэтому пробелы и спецсимволы больше не проблема.while read
Если над каждой строкой нужно выполнить несколько действий:
find . -name "*.log" -print0 |
while IFS= read -r -d '' file; do
echo "Deleting: $file"
rm "$file"
done
Такой код легче расширять: добавить проверки, логирование, условия или обработку ошибок.Для простого запуска одной команды обычно выигрывает
xargs.Для сложной логики, где каждая строка проходит несколько этапов обработки, удобнее использовать
while read.Многие используют
xargs и while read как взаимозаменяемые инструменты. На практике выбор зависит не только от скорости, но и от формата входных данных. Если есть вероятность встретить пробелы, переносы строк или необычные символы в именах файлов, безопасные варианты - xargs -0 или while read -d ''.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
shopt: малоизвестные настройки Bash, которые меняют поведение shellБольшинство пользователей знают про
set -e или set -u, но в Bash есть ещё один мощный инструмент настройки - shopt.С его помощью можно включать и отключать десятки дополнительных возможностей оболочки.
shopt
Или только включённые:shopt -s
globstar - рекурсивный поиск без findПо умолчанию:
ls **/*.log
не сработает.Включаем:
shopt -s globstar
Теперь:ls **/*.log
найдёт все .log-файлы во вложенных каталогах.nullglob - если файлов нетБез этой опции:
for file in *.log; do
echo "$file"
done
выведет:*.log
Вместо пустого списка.Исправляем:
shopt -s nullglob
Теперь цикл просто не выполнится.dotglob - учитывать скрытые файлыПо умолчанию
* не включает файлы, начинающиеся с точки.После:
shopt -s dotglob
они тоже попадут в результат.failglob - защита от опечатокЕсли шаблон не совпал ни с одним файлом:
rm *.bak
с failglob Bash сразу сообщит об ошибке вместо передачи шаблона команде.shopt -s failglob
Это помогает избежать неожиданных сценариев в автоматизации.Несколько опций
shopt способны заметно изменить поведение Bash без переписывания скриптов. Особенно полезны globstar, nullglob и failglob - они делают работу с шаблонами более удобной и предсказуемой.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥1
Аудит переменной
Переменная
Именно поэтому
▪️ Посмотреть порядок поиска
▪️ Поиск дубликатов
Повторяющиеся каталоги не ломают систему, но замедляют поиск команд и усложняют отладку:
▪️ Опасные записи
Особое внимание стоит обратить на:
Если он находится в
▪️ Проверка прав доступа
Даже “нормальный” каталог может быть проблемой, если в него могут писать другие пользователи:
▪️ Какая команда будет запущена?
Не всегда очевидно, какой бинарник использует shell:
▪️ Почему это важно
Ошибки в
BashTex📱 #bash #linux
$PATH: поиск небезопасных директорий и дубликатовПеременная
$PATH определяет, где shell ищет исполняемые файлы. Один лишний каталог - и вместо системной утилиты может запуститься совсем другая программа.Именно поэтому
$PATH стоит периодически проверять.echo "$PATH" | tr ':' '\n'
Shell просматривает каталоги сверху вниз. Если команда встречается в нескольких местах, будет использована первая найденная.Повторяющиеся каталоги не ломают систему, но замедляют поиск команд и усложняют отладку:
echo "$PATH" | tr ':' '\n' | sort | uniq -d
Если вывод не пустой - есть дубликаты.Особое внимание стоит обратить на:
.
./bin
/tmp
/var/tmp
/home/user/bin
Каталог . означает “текущая директория”. Если он находится в
$PATH, достаточно оказаться в папке с вредоносным файлом ls или ssh, чтобы по ошибке запустить его вместо системной утилиты.Даже “нормальный” каталог может быть проблемой, если в него могут писать другие пользователи:
find $(echo "$PATH" | tr ':' ' ') \
-maxdepth 0 -perm -0002 -ls 2>/dev/null
World-writable директории в $PATH - серьёзный повод для проверки.Не всегда очевидно, какой бинарник использует shell:
type -a python
илиwhich -a python
Это покажет все найденные версии в порядке поиска.Ошибки в
$PATH могут приводить не только к странному поведению скриптов, но и к компрометации системы. Несколько минут аудита помогут обнаружить небезопасные каталоги, лишние записи и потенциальную подмену исполняемых файлов ещё до того, как это станет проблемой.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
wait и wait -n: управление несколькими фоновыми задачамиЗапустить процесс в фоне через
& умеют почти все. Проблемы начинаются, когда таких процессов становится несколько и нужно понять, кто завершился и с каким кодом ошибки.wait
sleep 2 &
sleep 5 &
wait
echo "Все процессы завершились"
Без аргументов wait ждёт завершения всех фоновых задач текущего shell.sleep 10 &
pid=$!
wait "$pid"
echo "Процесс завершён"
$! - PID последнего фонового процесса.wait -n
Появился в Bash 4.3+ и решает важную задачу: ждать не всех, а первого завершившегося процесса.
sleep 5 &
sleep 2 &
sleep 8 &
wait -n
echo "Кто-то уже завершился"
Скрипт продолжит работу через 2 секунды, а не через 8.Параллельная обработка файлов:
for file in *.log; do
gzip "$file" &
done
while wait -n; do
echo "Одна задача завершилась"
done
Так можно реагировать на завершение задач по мере их выполнения, а не ждать самый медленный процесс.Без
wait Bash может завершить скрипт раньше фоновых процессов. А wait -n позволяет строить простые очереди задач и параллельную обработку без GNU Parallel, Python и других внешних инструментов. Для многих серверных скриптов этого уже достаточно.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
tee не только для логов: запись сразу в несколько потоковБольшинство используют
tee только для сохранения вывода команды в файл:command | tee output.log
Но возможности tee этим не ограничиваются. Он позволяет разветвлять поток данных и отправлять его сразу в несколько мест.Например, сохранить один и тот же вывод сразу в два файла:
dmesg | tee kernel.log backup.log >/dev/null
Не нужно запускать команду дважды - tee сам продублирует поток.Если скрипт должен писать лог, но при этом вывод оставаться в терминале:
./backup.sh | tee backup.log
Пользователь видит процесс выполнения, а лог сохраняется автоматически.По умолчанию
tee перезаписывает файл.Чтобы дописывать:
echo "Started" | tee -a app.log
Ключ -a работает так же, как >>.Вместе с process substitution можно построить разветвление потока:
journalctl -f \
| tee >(grep ERROR > errors.log) \
>(wc -l > count.txt) \
> /dev/null
Теперь один поток одновременно:фильтруется по ошибкам;
подсчитывается;
может использоваться в других обработчиках.
Команда
journalctl при этом запускается только один раз.tee - это не просто инструмент для записи логов. Он позволяет строить конвейеры, где один источник данных обслуживает сразу несколько получателей. Это особенно полезно при анализе логов, мониторинге и автоматизации, когда дорого или невозможно повторно запускать исходную команду.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍2
Анализ активных UNIX-сокетов:
Когда ищут открытые сервисы на сервере, обычно проверяют TCP и UDP:
▪️ Посмотреть активные UNIX-сокеты
Чтобы увидеть только ожидающие подключения:
▪️ Найти владельца сокета
Добавляем информацию о процессе:
▪️ Проверка прав доступа
UNIX-сокет - это файл, поэтому у него есть обычные права:
▪️ Найти все сокеты на диске
▪️ Посмотреть, кто держит конкретный сокет
Через
▪️ Почему это важно
Открытый TCP-порт виден сразу при сетевом сканировании. UNIX-сокеты остаются внутри системы и часто забываются при аудите.
При проверке сервера стоит смотреть не только наружные соединения, но и локальные каналы связи между процессами: именно там могут находиться Docker API, базы данных, агенты мониторинга и другие сервисы с важными правами доступа.
BashTex📱 #bash #linux
ss -xl и неожиданные IPC-соединенияКогда ищут открытые сервисы на сервере, обычно проверяют TCP и UDP:
ss -tulpn
Но часть процессов вообще не использует сеть. Они общаются через UNIX-сокеты - локальный механизм IPC между процессами.ss -x
Ключ -x включает UNIX-сокеты.Чтобы увидеть только ожидающие подключения:
ss -xl
Пример:u_str LISTEN 0 128 /run/docker.sock
Это означает, что какой-то процесс принимает локальные подключения через этот сокет.Добавляем информацию о процессе:
ss -xlp
Пример:users:(("dockerd",pid=842,fd=7))
Теперь понятно, какой процесс создал точку обмена.UNIX-сокет - это файл, поэтому у него есть обычные права:
ls -l /run/docker.sock
Например:srw-rw---- root docker docker.sock
Группа с правом записи может управлять Docker через этот сокет.find / -type s 2>/dev/null
Особое внимание:/tmp
/dev/shm
/home/*
Системные сервисы чаще используют:/run
/var/run
Через
lsof:lsof /run/docker.sock
или:fuser /run/docker.sock
Открытый TCP-порт виден сразу при сетевом сканировании. UNIX-сокеты остаются внутри системы и часто забываются при аудите.
При проверке сервера стоит смотреть не только наружные соединения, но и локальные каналы связи между процессами: именно там могут находиться Docker API, базы данных, агенты мониторинга и другие сервисы с важными правами доступа.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Поиск файлов с расширенными ACL:
В Linux права доступа обычно проверяют через:
▪️ Проверяем ACL у файла
▪️ Как найти файлы с ACL
Команда
▪️ Проверка конкретного каталога
Например, ищем нестандартные права в
▪️ Удаление лишних ACL
Если доступ больше не нужен:
▪️ Почему ACL часто забывают
Администратор может изменить права:
Но если раньше был добавлен ACL:
▪️ Почему это важно
ACL полезны для сложных систем с большим количеством пользователей, но они усложняют аудит. При расследовании проблем с доступом всегда нужно проверять не только
BashTex📱 #bash #linux
getfacl и find для выявления нестандартных правВ Linux права доступа обычно проверяют через:
ls -l
Но этого недостаточно. Если у файла есть ACL (Access Control List), дополнительный пользователь или группа могут иметь доступ, которого не видно в стандартном выводе.getfacl /etc/passwd
Обычный вывод:user::rw-
group::r--
other::r--
Если есть дополнительные правила:user::rw-
user:backup:r--
group::r--
mask::r--
other::---
Здесь пользователь backup получил отдельное разрешение.Команда
find умеет искать расширенные ACL:find / -type f -acl 2>/dev/null
Но на многих системах удобнее использовать проверку через getfacl:find /etc -type f -exec getfacl -p {} \; 2>/dev/null | grep "^user:"
Например, ищем нестандартные права в
/srv:getfacl -R /srv
Обращаем внимание на строки:user:name:
group:name:
Они показывают дополнительные разрешения.Если доступ больше не нужен:
setfacl -b file.txt
Ключ -b удаляет все дополнительные ACL, оставляя только обычные Unix-права.Администратор может изменить права:
chmod 600 secret.txt
и считать файл закрытым.Но если раньше был добавлен ACL:
user:john:r--
пользователь John всё ещё может читать файл.ACL полезны для сложных систем с большим количеством пользователей, но они усложняют аудит. При расследовании проблем с доступом всегда нужно проверять не только
chmod, но и расширенные правила через getfacl.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Поиск процессов с удалённым исполняемым файлом
В Linux процесс продолжает работать, даже если его исполняемый файл уже удалён с диска. Пока процесс не завершится, ядро держит файл открытым через файловый дескриптор.
Такие процессы стоит периодически искать - особенно после обновлений ПО, удаления пакетов или при аудите безопасности.
▪️ Быстрая проверка
Исполняемый файл каждого процесса доступен через
Например:
Это означает, что процесс продолжает использовать уже удалённый бинарник.
▪️ Более удобный вариант
С помощью
Команда покажет не только исполняемые файлы, но и удалённые библиотеки, логи и другие объекты, которые всё ещё удерживаются процессами.
▪️ Почему это происходит
Типичный сценарий:
Во время обновления старый бинарник удаляется и заменяется новым. Но уже запущенный процесс продолжает выполнять старую версию из памяти.
Пока сервис не будет перезапущен, он работает с удалённым файлом.
▪️ Когда это становится проблемой
Если удерживается исполняемый файл или библиотека - система использует устаревший код.
Если удерживается большой удалённый лог:
место на диске не освободится, пока процесс не закроет файл или не завершится.
▪️ Какие процессы требуют внимания
Не все записи
системные сервисы после обновлений;
процессы с удалёнными библиотеками (
файлы в
▪️ Почему это важно
Поиск процессов с
BashTex📱 #bash #linux
В Linux процесс продолжает работать, даже если его исполняемый файл уже удалён с диска. Пока процесс не завершится, ядро держит файл открытым через файловый дескриптор.
Такие процессы стоит периодически искать - особенно после обновлений ПО, удаления пакетов или при аудите безопасности.
Исполняемый файл каждого процесса доступен через
/proc/<PID>/exe:ls -l /proc/*/exe 2>/dev/null | grep '(deleted)'
Например:
/proc/2841/exe -> /usr/bin/python3.12 (deleted)
Это означает, что процесс продолжает использовать уже удалённый бинарник.
С помощью
lsof:lsof | grep '(deleted)'
Команда покажет не только исполняемые файлы, но и удалённые библиотеки, логи и другие объекты, которые всё ещё удерживаются процессами.
Типичный сценарий:
apt upgrade
Во время обновления старый бинарник удаляется и заменяется новым. Но уже запущенный процесс продолжает выполнять старую версию из памяти.
Пока сервис не будет перезапущен, он работает с удалённым файлом.
Если удерживается исполняемый файл или библиотека - система использует устаревший код.
Если удерживается большой удалённый лог:
/var/log/app.log (deleted)
место на диске не освободится, пока процесс не закроет файл или не завершится.
Не все записи
(deleted) опасны. В первую очередь стоит проверить:системные сервисы после обновлений;
процессы с удалёнными библиотеками (
.so);файлы в
/tmp или /dev/shm, которые продолжают использоваться после удаления.Поиск процессов с
(deleted) помогает обнаружить сервисы, которые давно требуют перезапуска, понять, почему не освобождается место на диске, и выявить подозрительные процессы, работающие с уже отсутствующими файлами.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Поиск бинарников с Linux Capabilities:
В Linux привилегии процесса не всегда завязаны только на
Например, программе можно дать возможность менять сетевые настройки без полного root-доступа.
▪️ Посмотреть capabilities у файла
Пример вывода:
Это означает, что
▪️ Поиск всех бинарников с capabilities
Команда рекурсивно проверяет файловую систему и показывает файлы с назначенными capabilities.
Пример:
▪️ Что означают флаги
Capability может иметь разные состояния:
Чаще всего встречается комбинация
▪️ Некоторые capabilities фактически дают очень широкие возможности:
Например:
•
•
•
▪️ Проверка конкретного процесса
У работающего процесса capabilities находятся здесь:
Ядро хранит их в виде битовых масок.
▪️ Удаление capability
Если разрешение больше не требуется:
После этого файл вернётся к обычной модели прав.
▪️ Почему это важно
При аудите Linux недостаточно искать только SUID-биты:
Современные системы активно используют capabilities, и иногда один бинарник с лишним разрешением может иметь больше привилегий, чем ожидается.
BashTex📱 #bash #linux
getcap -r /В Linux привилегии процесса не всегда завязаны только на
root. Существуют capabilities - отдельные разрешения ядра, которые можно выдавать конкретным бинарникам.Например, программе можно дать возможность менять сетевые настройки без полного root-доступа.
getcap /usr/bin/ping
Пример вывода:
/usr/bin/ping cap_net_raw=ep
Это означает, что
ping имеет право создавать raw-сокеты.getcap -r / 2>/dev/null
Команда рекурсивно проверяет файловую систему и показывает файлы с назначенными capabilities.
Пример:
/usr/bin/python3 cap_net_bind_service=ep
/usr/local/bin/app cap_sys_admin=ep
Capability может иметь разные состояния:
cap_net_raw=epe (effective) — разрешение активно при запуске;p (permitted) — процесс может его использовать.Чаще всего встречается комбинация
ep.cap_sys_admin
cap_dac_override
cap_setuid
cap_sys_ptrace
Например:
•
cap_dac_override позволяет обходить обычные проверки прав файлов;•
cap_setuid позволяет менять UID процесса;•
cap_sys_ptrace даёт возможность взаимодействовать с другими процессами.У работающего процесса capabilities находятся здесь:
cat /proc/1234/status | grep Cap
Ядро хранит их в виде битовых масок.
Если разрешение больше не требуется:
setcap -r /path/to/binary
После этого файл вернётся к обычной модели прав.
При аудите Linux недостаточно искать только SUID-биты:
find / -perm -4000
Современные системы активно используют capabilities, и иногда один бинарник с лишним разрешением может иметь больше привилегий, чем ожидается.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Проверка изменения списка загруженных модулей ядра:
Ядро Linux работает с модулями, которые можно загружать и выгружать без перезагрузки системы.
Это удобно для драйверов и расширений, но неожиданные изменения списка модулей могут быть важным сигналом при аудите.
▪️ Получить текущий список модулей
Пример:
Но для автоматического сравнения лучше сохранить только имена:
▪️ Создание базового снимка
После установки и настройки сервера можно сохранить эталон:
Позже сравнить:
▪️ Поиск новых модулей
Например:
Покажет только то, что появилось после создания снимка.
▪️ Проверка загрузки модулей в логах
Ядро пишет события загрузки:
Или:
▪️ Кто загрузил модуль?
Информацию о самом модуле можно получить через:
Покажет:
файл модуля;
автора;
версию;
зависимости.
▪️ Почему это важно
Большинство администраторов контролируют процессы и сетевые порты, но забывают про уровень ядра.
Неожиданный модуль может появиться после установки нового ПО, драйвера или изменения конфигурации. Сравнение снимков
BashTex📱 #bash #linux
lsmod + сравнение снимковЯдро Linux работает с модулями, которые можно загружать и выгружать без перезагрузки системы.
Это удобно для драйверов и расширений, но неожиданные изменения списка модулей могут быть важным сигналом при аудите.
lsmod
Пример:
Module Size Used by
nf_conntrack 176128 1
veth 32768 2
Но для автоматического сравнения лучше сохранить только имена:
lsmod | awk 'NR>1 {print $1}' | sort > modules.currentПосле установки и настройки сервера можно сохранить эталон:
lsmod | awk 'NR>1 {print $1}' | sort > /var/lib/modules.snapshotПозже сравнить:
diff /var/lib/modules.snapshot modules.current
Например:
comm -13 /var/lib/modules.snapshot modules.current
Покажет только то, что появилось после создания снимка.
Ядро пишет события загрузки:
journalctl -k | grep -i module
Или:
dmesg | grep -i module
Информацию о самом модуле можно получить через:
modinfo veth
Покажет:
файл модуля;
автора;
версию;
зависимости.
Большинство администраторов контролируют процессы и сетевые порты, но забывают про уровень ядра.
Неожиданный модуль может появиться после установки нового ПО, драйвера или изменения конфигурации. Сравнение снимков
lsmod помогает быстро увидеть изменения в состоянии ядра и понять, что именно изменилось на сервере.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Проверка процессов с изменённым OOM Score:
Когда Linux заканчивается память, ядро запускает OOM Killer. Он выбирает процесс для завершения не случайно - решение зависит от внутренней оценки процесса.
Этой оценкой можно управлять через
▪️ Посмотреть текущий OOM score процесса
У каждого процесса есть файлы в
И значение корректировки:
▪️ Найти процессы с изменённым приоритетом
Если процесс имеет значение отличное от
▪️ Что означают значения
Например:
Процесс сложнее убить при OOM.
Процесс становится более вероятной жертвой.
Особое значение:
полностью запрещает OOM Killer выбирать этот процесс.
▪️ Посмотреть, кто занимает память и имеет высокий приоритет убийства
Получаем одновременно:
PID;
имя процесса;
потребление памяти;
настройку OOM.
▪️ Где это встречается
systemd может задавать параметр прямо в unit:
Также это часто используют контейнерные системы, чтобы защитить критичные процессы.
▪️ Почему это важно
Иногда при расследовании OOM кажется, что ядро “выбрало неправильный процесс”. Но причина может быть в изменённом
Аудит этого параметра помогает понять, почему один сервис пережил нехватку памяти, а другой был завершён.
BashTex📱 #bash #linux
/proc/*/oom_score_adjКогда Linux заканчивается память, ядро запускает OOM Killer. Он выбирает процесс для завершения не случайно - решение зависит от внутренней оценки процесса.
Этой оценкой можно управлять через
oom_score_adj.У каждого процесса есть файлы в
/proc:cat /proc/$(pidof nginx)/oom_score
И значение корректировки:
cat /proc/$(pidof nginx)/oom_score_adj
oom_score — итоговый рейтинг для OOM Killer.oom_score_adj — ручная поправка от -1000 до 1000.for f in /proc/[0-9]*/oom_score_adj; do
value=$(cat "$f" 2>/dev/null)
if [ "$value" != "0" ]; then
pid=${f#/proc/}
pid=${pid%/oom_score_adj}
echo "$pid: $value"
fi
done
Если процесс имеет значение отличное от
0, кто-то явно менял его приоритет.Например:
-500Процесс сложнее убить при OOM.
500Процесс становится более вероятной жертвой.
Особое значение:
-1000полностью запрещает OOM Killer выбирать этот процесс.
ps -eo pid,comm,rss,oom_score_adj --sort=-rss | head
Получаем одновременно:
PID;
имя процесса;
потребление памяти;
настройку OOM.
systemd может задавать параметр прямо в unit:
[Service]
OOMScoreAdjust=-500
Также это часто используют контейнерные системы, чтобы защитить критичные процессы.
Иногда при расследовании OOM кажется, что ядро “выбрало неправильный процесс”. Но причина может быть в изменённом
oom_score_adj.Аудит этого параметра помогает понять, почему один сервис пережил нехватку памяти, а другой был завершён.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
caller: определение места вызова функции в BashПри отладке больших Bash-скриптов часто недостаточно знать, какая функция упала. Нужно понять, откуда именно она была вызвана.
Для этого есть встроенная команда
caller.function test_func() {
caller
}
test_funcВывод:
5 mainЭто означает: функция была вызвана из 5-й строки функции
main (или основного скрипта).Например, создаём функцию логирования:
log_error() {
echo "Error from:"
caller
}
backup() {
log_error
}
backupТеперь при ошибке видно не только сообщение, но и источник вызова.
caller умеет подниматься вверх по стеку:function level3() {
caller 0
caller 1
}
function level2() {
level3
}
function level1() {
level2
}
level1caller 0 покажет текущий уровень, а caller 1 - предыдущий.die() {
echo "Failed at:"
caller
exit 1
}
deploy() {
false || die
}
deployВместо:
Failedполучаем:
Failed at:12 deployСразу понятно, где искать проблему.
$FUNCNAMEВ Bash уже есть массивы:
echo "${FUNCNAME[@]}"Они показывают цепочку функций:
deploy backup main
А
caller дополнительно даёт:номер строки;
имя файла;
контекст вызова.
большие Bash-проекты;
библиотеки функций;
CI/CD-скрипты;
автоматизация с большим количеством уровней вызова.
В маленьких скриптах ошибка обычно очевидна. Но когда Bash превращается в несколько сотен строк с десятками функций, трассировка вызовов становится такой же важной, как в обычных языках программирования.
caller - простой встроенный инструмент, который превращает отладку Bash из поиска по всему файлу в точное указание места проблемы.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
BashTex | Linux
Авторский канал для тех, кто хочет глубже погрузиться в мир Linux.
Подойдет для разработчиков, системных администраторов и DevOps
Реклама: @dad_admin
Подойдет для разработчиков, системных администраторов и DevOps
Реклама: @dad_admin
👍8
hash: почему Bash иногда запускает “не ту” командуКаждый раз искать исполняемый файл в каталогах из
$PATH было бы дорого. Поэтому Bash запоминает найденные пути в собственном кэше команд.Из-за этого после обновления или перемещения бинарника можно столкнуться с неожиданным поведением.
hash
Пример вывода:
hits command
12 /usr/bin/git
5 /usr/bin/python3
8 /usr/bin/ssh
Здесь видно, какие команды Bash уже нашёл и закэшировал.
Допустим, Bash уже знает:
/usr/bin/python3
Но затем появился другой бинарник раньше в
$PATH:/usr/local/bin/python3
Shell может продолжить использовать старый путь, пока кэш не будет обновлён.
Полностью:
hash -r
После этого Bash снова выполнит поиск команды по
$PATH.Очистить только одну запись:
hash -d python3
При следующем запуске путь будет найден заново.
type -a python3
или
which -a python3
Это покажет все найденные бинарники, но именно Bash может использовать уже закэшированный путь.
Частые ситуации:
• установка новой версии программы в
/usr/local/bin;• изменение
$PATH внутри скрипта;• переключение между несколькими версиями Python, Java или Node.js;
• обновление исполняемых файлов без открытия нового терминала.
Если после изменения
$PATH или установки новой версии команда продолжает запускать старый бинарник, проблема может быть не в переменной окружения, а в кэше Bash.Одна команда
hash -r часто решает проблему быстрее, чем долгий поиск ошибок в конфигурации.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
readarray: читаем вывод команды в массив без цикловЧасто в Bash список файлов или строк читают через
while read. Но если нужно просто получить все данные в массив, есть более короткий и быстрый способ - readarray (или его синоним mapfile).files=()
while IFS= read -r file; do
files+=("$file")
done < <(find /var/log -name "*.log")
Работает, но код получается довольно громоздким.
readarrayreadarray -t files < <(
find /var/log -name "*.log"
)
Теперь весь вывод команды сразу окажется в массиве
files.-tБез него каждый элемент массива будет содержать символ новой строки (
\n) в конце.Практически всегда стоит использовать:
readarray -t lines < file.txt
Так строки попадут в массив уже без лишних символов.
Например, узнать количество найденных файлов:
echo "${#files[@]}"Или пройтись по ним:
for file in "${files[@]}"; do
echo "$file"
donereadarray считывает весь поток целиком. Если команда выводит миллионы строк или очень большой файл, массив займёт соответствующий объём памяти.В таких случаях потоковая обработка через
while read остаётся более подходящим вариантом.Во многих скриптах
while read используется просто по привычке. Если задача - получить список строк для дальнейшей работы, readarray делает то же самое в одну команду, сохраняя код компактным и избавляя от ручного заполнения массива.BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
exec: замена процесса без создания дочернего
Обычно при запуске команды Bash создаёт новый процесс:
После завершения sleep управление возвращается обратно в shell.
Но exec работает иначе - он заменяет текущий процесс новым. Старый процесс исчезает, а его PID сохраняется.
▪️ Простой пример
После выполнения вы больше не вернётесь в текущий shell. Процесс Bash будет полностью заменён на sleep.
▪️ Почему PID не меняется
Запустим:
И снова:
PID останется тем же. Новый экземпляр Bash не был создан - текущий процесс просто заменился.
▪️ Где это действительно полезно
Представьте простой launcher:
После запуска в системе не останется лишнего процесса Bash - только myapp.
Это особенно важно для:
контейнеров Docker;
systemd-сервисов;
entrypoint-скриптов.
▪️ Почему это лучше обычного запуска
Без exec:
С exec:
myapp
Нет промежуточного процесса, сигналы (SIGTERM, SIGINT) сразу получает приложение, а не оболочка.
▪️ Когда использовать нельзя
После exec текущий скрипт прекращает существование:
Строка After никогда не выполнится.
▪️ Почему это важно
Многие воспринимают exec как ещё один способ запуска команды. На самом деле это механизм замены процесса. Он позволяет убрать лишний уровень в дереве процессов, избежать проблем с обработкой сигналов и сделать запуск сервисов более предсказуемым.
BashTex📱 #bash #linux
Обычно при запуске команды Bash создаёт новый процесс:
sleep 60
После завершения sleep управление возвращается обратно в shell.
Но exec работает иначе - он заменяет текущий процесс новым. Старый процесс исчезает, а его PID сохраняется.
echo $$
exec sleep 60
После выполнения вы больше не вернётесь в текущий shell. Процесс Bash будет полностью заменён на sleep.
Запустим:
echo $$
exec bash
И снова:
echo $$
PID останется тем же. Новый экземпляр Bash не был создан - текущий процесс просто заменился.
Представьте простой launcher:
#!/bin/bash
echo "Starting application..."
exec /usr/local/bin/myapp
После запуска в системе не останется лишнего процесса Bash - только myapp.
Это особенно важно для:
контейнеров Docker;
systemd-сервисов;
entrypoint-скриптов.
Без exec:
bash
└── myapp
С exec:
myapp
Нет промежуточного процесса, сигналы (SIGTERM, SIGINT) сразу получает приложение, а не оболочка.
После exec текущий скрипт прекращает существование:
echo "Before"
exec sleep 5
echo "After"
Строка After никогда не выполнится.
Многие воспринимают exec как ещё один способ запуска команды. На самом деле это механизм замены процесса. Он позволяет убрать лишний уровень в дереве процессов, избежать проблем с обработкой сигналов и сделать запуск сервисов более предсказуемым.
BashTex
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍1🗿1