LINUX.ORG.RU

Вроде просто пометь пользователя как user_u и ему по умолчанию будет запрещён вызов setuid()

[root@0x61s ~]# useradd -m test1
[root@0x61s ~]# semanage login -l

Login Name           SELinux User         MLS/MCS Range        Service

__default__          unconfined_u         s0-s0:c0.c1023       *
root                 unconfined_u         s0-s0:c0.c1023       *
[root@0x61s ~]# semanage login -a -s user_u test1
[root@0x61s ~]# semanage login -l

Login Name           SELinux User         MLS/MCS Range        Service

__default__          unconfined_u         s0-s0:c0.c1023       *
root                 unconfined_u         s0-s0:c0.c1023       *
test1                user_u               s0                   *
[root@0x61s ~]# su - test1
[test1@0x61s ~]$ su -
Password: 
su: Authentication failure
[test1@0x61s ~]$ exit
logout
[root@0x61s ~]# grep test1 /var/log/audit/audit.log
...
type=USER_AUTH msg=audit(1710274096.627:305): pid=1303 uid=1001 auid=1000 ses=4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 msg='op=PAM:authentication grantors=? acct="root" exe="/usr/bin/su" hostname=? addr=? terminal=/dev/pts/0 res=failed'UID="test1" AUID="sparks"
...
sparks ★★★
()
Последнее исправление: sparks (всего исправлений: 1)

Смена UID, GID это capcbilities процесса. Если у процесса есть такие capabilities, то он cможет менять UID, GID вне зависимости от пользователя, который его запустил. Capabilities это свойства программ и от пользователя они не зависят.

Соотв. тебе нужно как-то ловить процессы, которые запускает пользователь и отбирать у них соотв. capabilities. Единственное, что приходит в голову, это запускать пользователя в chroot окружении, в котором ты убрал у всех программ CAP_SETUID, CAP_CHOWN и пр… Будет ли такая система работать с нужным тебе функционалом – вопрос.

soomrack ★★★★
()
Ответ на: комментарий от sparks
type=USER_AUTH msg=audit(1710274096.627:305): pid=1303 uid=1001 auid=1000 ses=4 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 msg='op=PAM:authentication grantors=? acct="root" exe="/usr/bin/su" hostname=? addr=? terminal=/dev/pts/0 res=failed'UID="test1" AUID="sparks"

во-первых, тут видно, что auid=sparks, поэтому это не аргумент. во-вторых, тут видно, что failure случилось на USER_AUTH на не на системном вызове, скорее всего, где-то внутри PAM с поддержкой SE Linux.

Но да, можно, вероятно, написать (или найти в существующей) полиси, где setuid() запрещён. Возможно, это так для user_u, просто, но судя по https://github.com/fedora-selinux/selinux-policy/pull/625/commits/e967b31972e6e52d3d2694e64f60742c893ff920 полиси просто запрещает запускать su и sudo, а не setuid() если он где-то ещё возьмётся.

Альтернативно можно попробовать запретить setuid() через seccomp.

ivlad ★★★★★
()

Тут все почему-то про setuid() пишут, но дело не совсем не в нём. setuid() обычно и так, кроме рута, никому не доступен. У тебя ж пользователь - не рут?

Уточни что ты имеешь ввиду. «Опасная» смена пользоватиеля в su происходит вовсе не в момент вызова setuid(), а в момент запуска самого su - на нём стоит setuid-бит, и программа эта запускается от рута. Так что смотреть надо, видимо, запрет обработки setuid-битов для конкретного контекста. Но учти, setuid-биты есть не только у программ, меняющих в итоге пользователя, а и, например, у программы passwd, которая это использует чтобы уметь записывать в /etc/shadow, и даже более того - какие-то функции glibc внутри используют запуск setuid-бинарника-помощника, всё это тоже сломается.

firkax ★★★★★
()
Ответ на: комментарий от ivlad

во-первых, тут видно, что поле auid

auid - Records the Audit user ID. This ID is assigned to a user upon login and is inherited by every process even when the user’s identity changes (for example, by switching user accounts with su - john).

т.е. тот кто изначально залогинился в систему, а поле type

USER_AUTH - Triggered when a user-space authentication attempt is detected.

это «общий» эвент попытки аутентификации пользователя

sparks ★★★
()
Ответ на: комментарий от firkax

У тебя ж пользователь - не рут?

Уточни что ты имеешь ввиду.

Пользователь не рут.
Хочу реализовать следущую модель безопасности: пользователи не имеют пароля, в том числе рут (я один пользователь компьютера, не хочу вводить пароли, считаю это неудобным); обычные пользователи никак не должны иметь возможность делать смену пользователей, даже основной пользователь, под которым сижу в GUI (важно); чтобы иметь рутовый терминал, предпологаю запуск отдельного терминала с автоматическим рутовым логином, где-то из init-скриптов (пока не знаю как запускать такой терминал, подскажите), доступ к которому осуществляется по хоткею (хардварно с клавиатуры, пока не знаю, нужно ли как-то дополнительно ограничивать другие гуёвые программы от возможности эмулировать нажатие хоткея). Т.е. будет система, в которой обычные пользователи никак не могут повышать привилегии (в моей системе также нет sudo), будет работать гуёвый рутовый терминал, на который основной пользователь может переключаться по хоткею.

«Опасная» смена пользоватиеля в su происходит вовсе не в момент вызова setuid(), а в момент запуска самого su - на нём стоит setuid-бит, и программа эта запускается от рута.

Т.е. достаточно всего лишь запретить запуск su, и моя модель будет работать? Какие-то другие программы не смогут выполнять системные вызовы setuid()?

teod0r ★★★★★
() автор топика
Ответ на: комментарий от teod0r

обычные пользователи никак не должны иметь возможность делать смену пользователей

чтобы иметь рутовый терминал, предпологаю запуск отдельного терминала с автоматическим рутовым логином

Здравствуйте, хочу запретить огнестрел в стране, но чтобы у каждого была кнопка запуска ядерных ракет

PPP328 ★★★★★
()
Ответ на: комментарий от teod0r

Если предполагать, что в софте нет багов, и что у тебя там не спрятался ещё какой-то клон su (sudo, doas, pkexec, их полно) - то да. Программы, которые переключаются на рута (с помощью бита setuid), всё равно будут, но они будут это делать для своих внутренних нужд и запустить с помощью них что-то ещё (если не найдётся баг) невозможно.

Собственно, то, что один юзер не может сам собой превратиться в другого - это дефолт. su и подобные проги создают исключения в этом дефолте. Наличие или отсутствие паролей вызову setuid() опять же не важно, пароль проверяет всё то же su, или другие «проги для логина» юзерспейсным кодом.

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

firkax ★★★★★
()
Ответ на: комментарий от PPP328

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

firkax ★★★★★
()
Ответ на: комментарий от PPP328

Здравствуйте, хочу запретить огнестрел в стране, но чтобы у каждого была кнопка запуска ядерных ракет

Не у каждого, а только у основного юзера, и только переключением хоткеем на УЖЕ запущенный при старте терминал с рутом (запуск новых копий терминала с рутом будет невозможен).
Чем это менее безопасно всеми любимого sudo без пароля?

teod0r ★★★★★
() автор топика
Ответ на: комментарий от firkax

юзеру с доступом к физической клаве выдать беспарольный доступ везде, а у софта его полностью забрать

да, никакие юзеры впринципе никак не смогут повышать привелегии )))

teod0r ★★★★★
() автор топика
Ответ на: комментарий от sparks

это «общий» эвент попытки аутентификации пользователя

который где-то внутри PAM. а опу нужен системный вызов.

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

ivlad ★★★★★
()
Последнее исправление: ivlad (всего исправлений: 1)
Ответ на: комментарий от firkax

запуска самого su - на нём стоит setuid-бит

такой вопрос. вот я убрал setuid-бит с /usr/bin/su и теперь обычные пользователи не могут переключаться на других пользователей. что если всё же иногда нужно менять пользователя, например для понижения привелегий — запуск firefox от другого, ещё более ограниченного пользователя? или выпонение выключения/перезагрузки компьютера пользователем из GUI или по кнопке. Как реальзовать? Через suid-ные скрипты, запускающие нужную функцию от другого пользователя? а если надо poweroff запускать, то вешеть рутовый suid на скрипт? на сколько это безопасно?

teod0r ★★★★★
() автор топика
Ответ на: комментарий от teod0r

Самый нормальный вариант, на мой взгляд - это написать программу на Си (и сделать её setuid-root), которая реализует ровно то, что ты хочешь разрешить и проверяя что оно действительно разрешено именно текущему юзеру. И никаких тупых пробрасываний аргументов куда-то - что-нить забудешь и получишь дыру, всё строго сначала парсим, потом выполняем действия. Узнать uid пользователя, её запустившего, можно через getuid(), а полученный из setuid-а root возвращается в geteuid().

запуск firefox от другого, ещё более ограниченного пользователя

Тут надо не забыть доступ к иксам пробросить ещё будет скорее всего - что очередная задача для кастомной проги с контролями доступа.

suid-ные скрипты

Скрипты нельзя suid. Можно си-обёртки, которые внутри запускают скрипты через system() или execve(), но как я уже выше написал, лучше по возможности вообще обойтись без скриптов и всё написать на Си.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от teod0r

Первый способ - вызов статической команды шелла

#include <stdlib.h>
int main(int argc, char **argv) {
  system("echo 123");
  reutrn 0;
}

Второй способ - вызов команды шелла с меняющимися аргументами

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
  char buf[10000];
  snprintf(buf, sizeof(buf), "echo %d", atoi(argv[1]));
  if(strlen(buf)>=sizeof(buf)-1) { fprintf(stderr, "cmd too long\n"); return -1; }
  system(buf);
  reutrn 0;
}
тут надо обратить внимание на две вещи:

1) делать тупо printf всего подряд нельзя, если хочешь передать строку, предоставленную юзером - её надо экранировать (это отдельная возня), иначе юзер может передать строку типа " ; echo qwe > /etc/passwd" которую шелл (функция system вызывает его) распарсит как команду

2) надо следить чтобы не переполнился буфер

Вобщем, не рекомендую этот способ, он чреват дырами, поэтому см. третий.

Третий способ - вызов нужной программы или скрипта без шелла

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
extern char **environ;
int main(int argc, char **argv) {
  argv[0] = "/usr/local/sbin/wrapped_script.sh";
  execve("/usr/local/sbin/wrapped_script.sh", argv, environ);
  fprintf(stderr, "execve(/usr/local/sbin/wrapped_script.sh) error %d (%s)\n", errno, strerror(errno));
  return -1;
}

Тут программа просто запускает скрипт и передаёт ему все свои аргументы как есть. Опасности того, что на этом этапе что-то не так распарсится, нет - никакого парсинга тут не происходит. Вся ответственность за парсинг будет лежать на скрипте. На такую программу уже можно поставить setuid-root, в отличие от шелл-скрипта.

Но как скрипту в такой схеме узнать какой юзер его запустил я не знаю. Возможно там есть какой-нить аналог getuid().

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от firkax

а если проще? если для каждого скрипта своя обёртка? Т.е. есть скрипт, запускающий telinit 0, и есть обёртка, которая только это и запускает, без парсинга. ??? т.е. из обёртки только запускать /my_scripts/power_off или сразу /sbin/telinit 0 ??

teod0r ★★★★★
() автор топика
Ответ на: комментарий от teod0r

Можно и свою для каждого, тогда можно даже убрать проверку прав из обёрток или скриптов и сделать её с помощью unix-прав доступа к запуску обёртки через группы.

Вообще делать одну обёртку для вообще всего я и не предлагал. Речь была про то, что какие-нить действия могут обязательно требовать какие-то параметры, которые придётся всё-таки брать от юзера.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от anonymous

достаточно им не быть в группе wheel и тогда никуда они не переключатся

нет. пользователь не в группе wheel может вызывая su переключаться на других пользователей

teod0r ★★★★★
() автор топика
Ответ на: комментарий от teod0r

Использовать пароли, но для актуального пользователя установить автологин. При этом вся ХХ-летняя история развития Линука будет работать на то, чтобы было невозможно сменить пользователя, не зная пароля

Jurik_Phys ★★★★★
()
Ответ на: комментарий от firkax

запуск firefox от другого, ещё более ограниченного пользователя

Тут надо не забыть доступ к иксам пробросить ещё будет скорее всего - что очередная задача для кастомной проги с контролями доступа.

можно с этого места по-подробнее?

teod0r ★★★★★
() автор топика
Ответ на: комментарий от teod0r

У иксов есть авторизация по uid и она часто используется. Сменишь юзера - может перестать работать. Если нет uid то нужен пароль от сессии - он обычно хранится в файле, имя которого указано в $XAUTHORITY. Если у проги и uid неподходящий и этот файл ты ей не подсунешь (чтоб смогла его прочесть) - подключение скорее всего не состоится. Можно настроить иксы чтобы пускали с локалхоста всех подряд без проверок, но это не очень хороший способ, лучше прокидывать Xauthority куда надо.

firkax ★★★★★
()
Ответ на: комментарий от teod0r

Симлинк права доступа не даст, он может быть полезен только если юзер тот же но $HOME переназначено. Скорее копировать этот файл перед запуском проги.

firkax ★★★★★
()
Ответ на: комментарий от PeachBlossoms

setpriv

Поддерживаю: https://www.man7.org/linux/man-pages/man1/setpriv.1.html

Посмотреть доступные привилегии:

setpriv --list-caps

Запрещаем всё:

setpriv --groups `id -g groupname`,audio,input,video --no-new-privs --securebits +noroot,+noroot_locked,+no_setuid_fixup,+no_setuid_fixup_locked,+keep_caps_locked --pdeathsig clear --reset-env --ambient-caps -all --inh-caps -all --bounding-set -all /bin/bash

прописать в /etc/passwd или ещё жеще в /etc/inittab для agetty.

Играюсь с capability в Linux: https://www.opennet.ru/openforum/vsluhforumID10/5622.html

pscap у меня выводит необходимые и достаточные CAP для процессов. Сделал костылём-скриптом с помощью setpriv. Пользователю root привилегии с помощью CAP можно порезать сильно. Но буддте готовы, что если вы перезапустите какой-то сервис, то у него может не хватить привилегий для работы. init имеет больше привилегий чем пользователь root.

Реализация CAP в Linux мне не нравится. Хочу обработку filecapabilities для пользователя root как для всех, чтобы можно было xattr, setfcap отбирать привилегии у рутовых процессов, а не только раздавать обычным пользователям. Но Линус Торвальдс лично против. Он считает что админ не может знать какие привилегии необходимы процессу и дал возможность только программистам сбрасывать привилегии самому процессу. Но практически никто с разрабов ПО этим не пользуется. Правильное решение заметил только в smartd.

А давайте патч для ядра Linux напишем чтобы необходимые и достаточные CAP для root процесса можно было выставить filecapabilities.

anonymous
()
Ответ на: комментарий от anonymous

Важное дополнение, вышеописанное даст гарантии для дистров без systemd, dbus, polkitd+JS понятно почему?

Потеринг проделал дырище в классической модели безопасности Linux - всё для удобства пользователей. Чтобы обычные пользователи имели возможность запускать процессы с рутовыми привилегиями. И права в этом случае контролируются polkitd, а правила контроля доступа пишутся на джава скрыпт. Это не шутка.

anonymous
()