Прежде всего, обратите внимание на следующий абзац на странице руководства seccomp(2)
:
SECCOMP_RET_ERRNO
This value results in the SECCOMP_RET_DATA portion of the filter's return value being passed to user space as the errno value without executing the system call.
Таким образом, фильтр seccomp может заставить ядро пропустить реальное выполнение системного вызова и вместо этого вернуть некоторое значение в притвориться , что системный вызов был выполнен и дал указанный результат. Это также относится куспешному результату , если возвращаемое значение равно нулю.
Вот пример libseccomp
программы на основе (sec.c
), которая показывает, как это работает (все проверки ошибок опущены для краткости):
#include
#include
int main() {
scmp_filter_ctx seccomp;
seccomp = seccomp_init(SCMP_ACT_ALLOW);
// Make the `openat(2)` syscall always "succeed".
seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(0), SCMP_SYS(openat), 0);
// Install the filter.
seccomp_load(seccomp);
FILE *file = fopen("/non-existent-file", "r");
// Do something with the file and then perform the cleanup.
// <...>
return 0;
}
Компиляция и запуск этой программы при отслеживании выполнения показывает, что openat(2)
системный вызов возвращает ноль (, т.е. "выполнен" успешно ), хотя файл /non-existent-file
не существует в файловой системе:
$ gcc sec.c -lseccomp -o sec
# Run the program showing the openat(2) invocations and their results.
$ strace -e trace=openat./sec
...
openat(AT_FDCWD, "/non-existent-file", O_RDONLY) = 0
...
# Ensure that the file does not exist.
$ stat /non-existent-file
stat: cannot stat '/non-existent-file': No such file or directory
Что ж, теперь мы понимаем возможности фильтров seccomp. Давайте подойдем ближе к пункту абзаца, который вы процитировали в своем вопросе. Подумайте о двух вещах:
Типичным примером является sudo(8)
утилита, представляющая собой root
принадлежащий SUID-файл. Выполнение его в контексте непривилегированного процесса предоставляет вызывающему процессу полные полномочия суперпользователя (, за исключением некоторых особых случаев, таких как песочницы и контейнеры ), после чего sudo(8)
проверяет файл /etc/sudoers
, чтобы узнать, является ли вызывающий пользователь разрешено выполнение запрошенной операции или нет. Если да, то sudo(8)
приступает к исполнению, а если нет, то исполнение отклоняется. Кроме того, sudo(8)
разрешает выполнение от имени произвольного пользователя — в этом случае он установит соответствующие учетные данные перед выполнением запрошенной операции .
Например,предполагая, что файл /etc/sudoers
содержит следующую запись
testuser ALL=(anotheruser) NOPASSWD: /bin/bash
пользователь testuser
сможет запустить оболочку от имени anotheruser
с помощью следующей команды:
sudo -u anotheruser -i /bin/bash
Теперь мы приближаемся к точке :что, если testuser
процесс, принадлежащий владельцу, установит фильтр seccomp, который заставит ядро вернуться из setuid(2)
, фактически не выполняя его, а затем запустит sudo -u anotheruser -i /bin/bash
? Что ж, посмотрим:
sudo(8)
и соответствующим образом повышает привилегии вызывающего процесса; sudo(8)
проверяет /etc/sudoers
и гарантирует, что testuser
разрешено запускать /bin/bash
как anotheruser
; sudo(8)
вызывает setuid(2)
для соответствующего изменения учетных данных процесса и «понижения» его привилегий; sudo(8)
считает, что теперь процесс выполняется от имени anotheruser
и продолжает выполнение /bin/bash
... setuid(2)
был пропущен фильтром и на самом деле не выполнялся! Таким образом, разрешение непривилегированному пользователю устанавливать фильтры seccomp также позволяет этому пользователю «захватывать» привилегированные учетные данные, перехватывая вызовы setuid(2)
, в то время как временно работает с повышенными привилегиями, следовательно, существуют ограничения указано на справочной странице:
either the calling thread must have the CAP_SYS_ADMIN capability in its user namespace, or the thread must already have the no_new_privs bit set.
Ясно, что означает первая часть этого предложения:CAP_SYS_ADMIN
— это возможность, которая предоставляет процессу много привилегий, поэтому можно с уверенностью предположить, что процесс, обладающий ею, уже достаточно силен, чтобы посеять хаос в системе. система. Что насчет второй части?
Бит no_new_privs
— это свойство процесса, которое, если установлено, указывает ядру не использовать механизмы повышения привилегий, такие как бит SUID (, поэтому вызов таких вещей, как sudo(8)
, не будет работают вообще ),так что безопасно разрешить непривилегированному процессу с этим установленным битом использовать фильтры seccomp :у этого процесса не будет возможности повышать привилегии даже временно, таким образом, он не сможет «захватить» эти привилегии.
С помощью awk мы перебираем поля и, если находим выбранное, меняем местами со вторым полем.
awk -v p="Piebald" '{
for (i=2;i<=NF;i++) if ($i == p) {$i = $2; $2 = p; break}
}1' file
1
в конце означает print
строку. break
досрочно выходит из цикла после замены -v var="value"
— это стандартный способ передать переменную в awk
. Выход:
HR0024 Piebald pastel Black
HR0028 Piebald
MC0023 Piebald
MC0039 Piebald Fire
MC0075 Piebald VPI Axanthic
MC0082 Piebald Pastel
MC0120 Piebald Yellowbelly Het. lavender
Если порядок других строк не имеет значения, вы можете просто сделать:
$ sed -E 's/Piebald//g; s/^(\S+)/\1 Piebald/' file
HR0024 Piebald Black pastel
HR0028 Piebald
MC0023 Piebald
MC0039 Piebald Fire
MC0075 Piebald VPI Axanthic
MC0082 Piebald Pastel
MC0120 Piebald Yellowbelly Het-Lavender
MC0124 Piebald Super-Pastel Het-Clown
MC0126 Piebald Fire Pastel
MC0144 Piebald Vanilla
Или, если ваш sed
не поддерживает:
$ perl -pe 's/Piebald//g; s/^(\S+)/\1 Piebald/' file
HR0024 Piebald Black pastel
HR0028 Piebald
MC0023 Piebald
MC0039 Piebald Fire
MC0075 Piebald VPI Axanthic
MC0082 Piebald Pastel
MC0120 Piebald Yellowbelly Het-Lavender
MC0124 Piebald Super-Pastel Het-Clown
MC0126 Piebald Fire Pastel
MC0144 Piebald Vanilla