BashTex | Linux
Open in Telegram
Авторский канал для тех, кто хочет глубже погрузиться в мир Linux. Подойдет для разработчиков, системных администраторов и DevOps Реклама: @dad_admin
Show more2 521
Subscribers
-124 hours
-77 days
+1730 days
Posts Archive
2 521
Проверка времени отклика сервисов
Когда сервис работает, но пользователи жалуются на медлительность, нужно мерить не аптайм, а отклик. Это легко сделать обычным curl.
▪️ Самый простой замер
time curl -s https://bashtex.com > /dev/null
Показывает общее время выполнения запроса и быстро понять, тормозит или нет.
▪️ Точнее: только сетевое время
curl -s -o /dev/null -w "time_total: %{time_total}\n" https://bashtex.com
Полезные метрики:
time_namelookup
time_connect
time_starttransfer
time_total
Пример:
curl -w "DNS:%{time_namelookup} CONNECT:%{time_connect} TTFB:%{time_starttransfer} TOTAL:%{time_total}\n" \
-o /dev/null -s https://bashtex.com
▪️ Проверка нескольких сервисов
for url in https://a.ru https://b.ru; do
curl -o /dev/null -s -w "$url %{time_total}\n" "$url"
done
▪️ Таймаут обязателен
curl --connect-timeout 3 --max-time 5 https://bashtex.com
Без таймаута любой мониторинг бесполезен.
BashTex 📱 #bash #utils2 521
eval: почему опасен и когда реально нужен
В Bash почти любую строку можно превратить в команду через eval. Он берёт переданный текст и запускает его как новый Bash-код.
Именно поэтому это один из самых спорных инструментов в shell-скриптах.
▪️Как работает eval
Простой пример:
cmd="ls -la"
eval "$cmd"
Bash сначала получает строку:
ls -la
а затем выполняет её как обычную команду.
▪️Где возникает проблема
Если данные приходят от пользователя:
read input
eval "$input"
Теперь введённый текст становится кодом.
Например, вместо ожидаемого аргумента можно передать дополнительные команды, которые Bash выполнит при обработке строки.
Главная проблема eval - повторный разбор данных как команд.
▪️Почему кавычки не всегда спасают
Например:
file="test.txt"
eval "cat $file"
Пока значение простое - всё работает.
Но если внутри появятся специальные символы:
file="file name.txt"
или другие управляющие конструкции, поведение может отличаться от ожидаемого.
▪️Частая замена eval
Вместо хранения команды строкой:
cmd="ls -la /tmp"
eval "$cmd"
лучше использовать массив:
cmd=(ls -la /tmp)
"${cmd[@]}"
Теперь Bash хранит команду и аргументы отдельно.
▪️Когда eval действительно нужен
Иногда без него сложно обойтись. Например, при работе с динамическими именами переменных:
name="USER"
eval "echo \$$name"
Но даже здесь часто есть более безопасные варианты:
declare -n ref="$name"
echo "$ref"
▪️Проверка перед использованием
Если всё же нужен eval, данные должны быть полностью контролируемыми:
case "$action" in
start|stop|restart)
eval "service_$action"
;;
esac
Здесь значение ограничено заранее известным списком.
▪️Почему это важно
eval не является “плохой” командой сам по себе. Проблема появляется, когда данные превращаются в код.
В большинстве случаев массивы, case, функции или declare решают задачу безопаснее. eval стоит оставлять только для ситуаций, где действительно нужен второй проход парсинга Bash.
BashTex 📱 #eval2 521
Проверка доступности локальных Unix-сервисов:
nc -U и curl --unix-socket
Не все сервисы в Linux слушают TCP-порты. Многие приложения работают только через UNIX-сокеты - локальные каналы связи между процессами.
Например:
/run/docker.sock
/run/php/php-fpm.sock
/run/containerd/containerd.sock
Снаружи такие сервисы не видны через обычный nmap, но внутри системы они могут иметь важное значение.
▪️Найти активные UNIX-сокеты
ss -xlПример:
u_str LISTEN 0 128 /run/docker.sockТеперь можно проверить, отвечает ли сервис. ▪️Проверка через
nc
Netcat умеет подключаться к UNIX-сокетам:
nc -U /run/docker.sock
Если соединение установлено - сокет доступен.
Для HTTP-сервисов можно отправить запрос вручную:
printf "GET / HTTP/1.0\r\n\r\n" | nc -U /run/service.sock▪️Проверка HTTP API через
curl
Многие локальные API работают через UNIX-сокеты:
curl --unix-socket /run/docker.sock http://localhost/version
Здесь localhost не используется как сетевой адрес - он нужен только для формирования HTTP-запроса.
▪️Пример с Docker
Вместо:
docker version
можно напрямую обратиться к API:
curl --unix-socket /var/run/docker.sock \
http://localhost/_ping
Ответ:
OKозначает, что Docker daemon доступен. ▪️Проверка прав доступа Даже если сервис работает, доступ может быть ограничен:
ls -l /run/docker.sock
Например:
srw-rw---- root docker docker.sockТолько пользователи группы
docker смогут подключиться.
▪️Почему это важно
UNIX-сокеты часто остаются вне стандартного мониторинга. Администратор проверяет открытые порты, но забывает про локальные API и IPC-каналы.
Проверка через ss, nc -U и curl --unix-socket помогает быстро понять:
жив ли сервис;
кто имеет к нему доступ;
отвечает ли локальное API;
нет ли неожиданного открытого канала между процессами.
BashTex 📱 #sort2 521
Почему
sort | uniq не всегда работает так, как ожидается
Когда нужно убрать дубликаты, многие сразу пишут:
sort file.txt | uniq
Работает. Но только если понимать, что именно делает каждая команда.
▪️Как работает uniq
Распространённое заблуждение - uniq ищет все повторяющиеся строки.
На самом деле он удаляет только соседние дубликаты.
Например:
apple banana apple orangeЕсли выполнить:
uniq file.txtполучим тот же самый список - одинаковые строки не стоят рядом. ▪️Зачем нужен
sort
После сортировки одинаковые строки оказываются соседними:
sort file.txt | uniq
Результат:
apple banana orangeИменно поэтому эти команды почти всегда используются вместе. ▪️Когда сортировка не подходит Если порядок строк важен,
sort изменит его.
Например, при анализе логов или событий по времени это может полностью исказить картину.
В таких случаях лучше использовать:
awk '!seen[$0]++'
Команда удаляет дубликаты, но сохраняет исходный порядок строк.
▪️Найти только повторяющиеся строки
Иногда нужны не уникальные записи, а наоборот - только дубликаты:
sort file.txt | uniq -d
Или вывести количество повторений:
sort file.txt | uniq -c
Получим:
15 nginx 8 sshd 3 cron▪️Почему это важно
uniq кажется простой утилитой, но ошибка в понимании её работы часто приводит к неверным результатам. Перед использованием всегда стоит помнить: она сравнивает только соседние строки, а не весь файл целиком.
BashTex 📱 #sort2 521
mkfifo: обмен данными между процессами через именованные каналы
Обычный pipe:
command1 | command2работает только пока запущены обе команды. Но иногда нужен постоянный канал, к которому разные процессы могут подключаться позже. Для этого в Linux есть FIFO (named pipe). ▪️Создание именованного канала
mkfifo /tmp/my_pipe
Теперь /tmp/my_pipe выглядит как файл:
ls -l /tmp/my_pipe
Вывод:
prw-r--r-- 1 user user 0 Aug 4 12:00 my_pipeБуква
p означает pipe.
▪️Передача данных между двумя процессами
Терминал 1:
cat /tmp/my_pipe
Терминал 2:
echo "hello from process" > /tmp/my_pipe
Первый процесс сразу получит сообщение.
▪️Пример с логированием
Можно отправлять события из одного скрипта в другой:
mkfifo /tmp/events.pipe
tail -f /var/log/app.log > /tmp/events.pipe &
А отдельный обработчик:
while read line; do
echo "EVENT: $line"
done < /tmp/events.pipe
Теперь обработка логов отделена от источника данных.
▪️Важный момент
FIFO блокирует процесс:
echo "data" > /tmp/my_pipe
будет ждать, пока кто-то откроет канал на чтение.
Поэтому в автоматизации часто используют фоновые процессы:
cat /tmp/my_pipe &
echo "start" > /tmp/my_pipe
▪️Чем отличается от обычного файла
Данные в FIFO не сохраняются на диске.
Если никто не читает:
процесс → FIFO → процесс
данные не складываются в очередь, а ждут получателя.
▪️Где полезно
• связь между Bash-скриптами;
• простые IPC-механизмы;
• обработка потоков данных;
• разделение генератора и обработчика.
▪️Почему это важно
mkfifo часто заменяет временные файлы и сложные конструкции с перенаправлениями. Это простой способ построить связь между независимыми процессами прямо средствами Linux без дополнительных сервисов.
BashTex 📱 #mfifo2 521
Когда переменные пропадают
Одна из частых ловушек в bash - переменная изменилась… но снаружи осталась прежней. Причина почти всегда одна - subshell.
▪️ Что такое subshell. Subshell - это дочерний процесс bash. Он получает копию переменных, но изменения не возвращаются назад. Создается, например, здесь:
( command )
или в пайпах:
command | while read ...
▪️ Классическая проблема
count=0
echo -e "a\nb\nc" | while read -r line; do
((count++))
done
echo "$count"
Результат: 0
Почему? Цикл while выполняется в subshell.
▪️ Правильный вариант
count=0
while read -r line; do
((count++))
done < <(echo -e "a\nb\nc")
echo "$count"
Результат: 3
Теперь цикл работает в текущем shell.
▪️ Ещё пример
x=1
( x=5 )
echo "$x"
Результат: 1
Изменение потерялось.
▪️ Когда это полезно. Subshell - это не баг, а инструмент. Например:
( cd /tmp && ls )
внутри меняем каталог, а снаружи остаемся там же
BashTex 📱 #scripts2 521
env -i: запуск программы в полностью “чистом” окружении
Большинство программ наследуют десятки переменных окружения: PATH, HOME, LANG, LD_LIBRARY_PATH, прокси, токены и многое другое.
Иногда именно они становятся причиной странного поведения приложения.
▪️Посмотреть текущее окружение
env или: printenvВы увидите все переменные, которые будут унаследованы дочерними процессами. ▪️Запуск без окружения Команда:
env -i bash
запустит новый Bash практически без переменных окружения.
Если выполнить:
env
вывод окажется пустым или почти пустым.
▪️Передать только нужные переменные
Например:
env -i PATH=/usr/bin:/bin HOME=/tmp bash
Теперь программа получит только PATH и HOME.
Это особенно удобно при поиске ошибок.
▪️Практический пример
Есть скрипт:
./deploy.sh
У одного пользователя он работает, у другого - нет.
Проверяем:
env -i PATH=/usr/bin:/bin ./deploy.sh
Если проблема исчезла или, наоборот, воспроизвелась, причина, скорее всего, в одной из переменных окружения, а не в самом скрипте.
▪️Где ещё используется
• отладка CI/CD;
• проверка зависимостей от окружения;
• запуск сервисов в предсказуемых условиях;
• поиск проблем с PATH, LANG, HOME и прокси.
▪️Почему это важно
Ошибки, связанные с окружением, часто трудно воспроизвести: скрипт работает у одного администратора и ломается у другого. env -i позволяет полностью исключить влияние наследуемых переменных и быстро понять, зависит ли программа от окружения больше, чем кажется.
BashTex 📱 #bash #linux2 521
find -exec против -exec {} +: почему одна команда может быть в десятки раз быстрее
Многие используют find так:
find /var/log -name "*.log" -exec gzip {} \;
Команда работает, но есть нюанс: для каждого найденного файла запускается отдельный процесс gzip.
▪️Что происходит
Если найдено 5000 файлов, Bash выполнит примерно 5000 запусков gzip.
Это лишние создания процессов, переключения контекста и заметная потеря производительности.
▪️Более эффективный вариант
find /var/log -name "*.log" -exec gzip {} +
Теперь find собирает несколько файлов и передаёт их одной команде:
gzip file1.log file2.log file3.log ...Количество запусков сокращается в десятки или даже сотни раз. ▪️В чём разница Вариант с
\;:
gzip file1 gzip file2 gzip file3Вариант с
+:
gzip file1 file2 file3Логика обработки не меняется, но накладные расходы становятся значительно меньше. ▪️Когда
+ использовать нельзя
Если команда должна выполняться отдельно для каждого файла, например:
find . -type f -exec mv {} {}.bak \;
или внутри используется сложная оболочка:
find . -type f -exec sh -c '...' \;
В таких случаях объединение аргументов может изменить поведение команды.
▪️Как выбрать
Используйте -exec {} +, когда команда умеет принимать сразу несколько файлов:
rm
chmod
chown
gzip
cp
mv (при копировании в каталог)
ls
Если же обработка должна происходить строго по одному файлу — остаётся -exec {} \;.
▪️Почему это важно
Во многих скриптах find -exec {} \; используется по привычке. Замена всего одного символа — \; на + - позволяет значительно сократить число создаваемых процессов и ускорить обработку больших каталогов без изменения логики скрипта.
BashTex 📱 #bash #linux2 521
exec: замена процесса без создания дочернего
Обычно при запуске команды Bash создаёт новый процесс:
sleep 60
После завершения sleep управление возвращается обратно в shell.
Но exec работает иначе - он заменяет текущий процесс новым. Старый процесс исчезает, а его PID сохраняется.
▪️Простой пример
echo $$
exec sleep 60
После выполнения вы больше не вернётесь в текущий shell. Процесс Bash будет полностью заменён на sleep.
▪️Почему PID не меняется
Запустим:
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 📱 #bash #linux2 521
readarray: читаем вывод команды в массив без циклов
Часто в Bash список файлов или строк читают через while read. Но если нужно просто получить все данные в массив, есть более короткий и быстрый способ - readarray (или его синоним mapfile).
▪️Классический подход
files=()
while IFS= read -r file; do
files+=("$file")
done < <(find /var/log -name "*.log")
Работает, но код получается довольно громоздким.
▪️То же самое через readarray
readarray -t files < <(
find /var/log -name "*.log"
)
Теперь весь вывод команды сразу окажется в массиве files.
▪️Что делает ключ -t
Без него каждый элемент массива будет содержать символ новой строки (\n) в конце.
Практически всегда стоит использовать:
readarray -t lines < file.txt
Так строки попадут в массив уже без лишних символов.
▪️Работа с массивом
Например, узнать количество найденных файлов:
echo "${#files[@]}"
Или пройтись по ним:
for file in "${files[@]}"; do
echo "$file"
done
▪️Когда использовать не стоит
readarray считывает весь поток целиком. Если команда выводит миллионы строк или очень большой файл, массив займёт соответствующий объём памяти.
В таких случаях потоковая обработка через while read остаётся более подходящим вариантом.
▪️Почему это важно
Во многих скриптах while read используется просто по привычке. Если задача - получить список строк для дальнейшей работы, readarray делает то же самое в одну команду, сохраняя код компактным и избавляя от ручного заполнения массива.
BashTex 📱 #bash #linux2 521
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 📱 #bash #linux2 521
🤖 Программирование — ВСЁ?
В 2026 году голым кодингом уже никого не удивишь - рутину за секунды набрасывают нейросети. Новая и прибыльная перспектива - разработка ИИ-агентов и автоматизация процессов.
Хватит тратить токены на генерацию картинок и базовых текстов, пора внедрять ИИ в реальный продакшн. Ловите канал, который тащит только отборное технологическое мясо:
👨💻 ИИнтеллигенция • Нейросети - канал для бэкендеров, автоматизаторов и инди-хакеров. Глубокие разборы ИИ-инструментов, промпт-инжиниринг и архитектура агентов без хайпа и копипасты.
⚡️ Разборы софта: от консольных плагинов вроде Claude SEO до платформ от NVIDIA.
⚡️ Экономика токенов: честные тесты, где Grok 4.5 или DeepSeek выгоднее, чем дорогие модели.
⚡️ Практика: как разворачивать бэкграунд-воркеров и автоматизировать рутину до одной кнопки.
⬇️ Вступай и качай навыки будущего: @clucai
2 521
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
}
level1
caller 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 📱 #bash #linux2 521
Проверка процессов с изменённым OOM Score:
/proc/*/oom_score_adj
Когда Linux заканчивается память, ядро запускает OOM Killer. Он выбирает процесс для завершения не случайно - решение зависит от внутренней оценки процесса.
Этой оценкой можно управлять через oom_score_adj.
▪️Посмотреть текущий OOM score процесса
У каждого процесса есть файлы в /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 📱 #bash #linux2 521
Проверка изменения списка загруженных модулей ядра:
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 📱 #bash #linux2 521
Поиск бинарников с Linux Capabilities:
getcap -r /
В Linux привилегии процесса не всегда завязаны только на root. Существуют capabilities - отдельные разрешения ядра, которые можно выдавать конкретным бинарникам.
Например, программе можно дать возможность менять сетевые настройки без полного root-доступа.
▪️Посмотреть capabilities у файла
getcap /usr/bin/pingПример вывода:
/usr/bin/ping cap_net_raw=ep
Это означает, что ping имеет право создавать raw-сокеты.
▪️Поиск всех бинарников с capabilities
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=ep
e (effective) — разрешение активно при запуске;
p (permitted) — процесс может его использовать.
Чаще всего встречается комбинация ep.
▪️Некоторые capabilities фактически дают очень широкие возможности:
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
Ядро хранит их в виде битовых масок.
▪️Удаление capability
Если разрешение больше не требуется:
setcap -r /path/to/binary
После этого файл вернётся к обычной модели прав.
▪️Почему это важно
При аудите Linux недостаточно искать только SUID-биты:
find / -perm -4000
Современные системы активно используют capabilities, и иногда один бинарник с лишним разрешением может иметь больше привилегий, чем ожидается.
BashTex 📱 #bash #linux2 521
Поиск процессов с удалённым исполняемым файлом
В 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 📱 #bash #linux2 521
Поиск файлов с расширенными ACL:
getfacl и find для выявления нестандартных прав
В Linux права доступа обычно проверяют через:
ls -l
Но этого недостаточно. Если у файла есть ACL (Access Control List), дополнительный пользователь или группа могут иметь доступ, которого не видно в стандартном выводе.
▪️Проверяем ACL у файла
getfacl /etc/passwd
Обычный вывод:
user::rw- group::r-- other::r--
Если есть дополнительные правила:
user::rw- user:backup:r-- group::r-- mask::r-- other::---
Здесь пользователь backup получил отдельное разрешение.
▪️Как найти файлы с ACL
Команда 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:
Они показывают дополнительные разрешения.
▪️Удаление лишних ACL
Если доступ больше не нужен:
setfacl -b file.txt
Ключ -b удаляет все дополнительные ACL, оставляя только обычные Unix-права.
▪️Почему ACL часто забывают
Администратор может изменить права:
chmod 600 secret.txt
и считать файл закрытым.
Но если раньше был добавлен ACL:
user:john:r--
пользователь John всё ещё может читать файл.
▪️Почему это важно
ACL полезны для сложных систем с большим количеством пользователей, но они усложняют аудит. При расследовании проблем с доступом всегда нужно проверять не только chmod, но и расширенные правила через getfacl.
BashTex 📱 #bash #linux2 521
Анализ активных UNIX-сокетов:
ss -xl и неожиданные IPC-соединения
Когда ищут открытые сервисы на сервере, обычно проверяют TCP и UDP:
ss -tulpn
Но часть процессов вообще не использует сеть. Они общаются через UNIX-сокеты - локальный механизм IPC между процессами.
▪️Посмотреть активные UNIX-сокеты
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 📱 #bash #linux