Каждый процесс имеет как минимум два набора UID (обычно три или более). Одним из них является "реальный" UID, который определяет, кому принадлежит процесс. Другой - это "эффективный" UID, который определяет разрешения, которыми обладает процесс. Вы можете найти описание Linux в учетных данных (7).
Когда запускается программа setuid, изменяется только ее "эффективный" UID, так что она получает новые привилегии, но все же знает, кто ее запустил. (Вот как sudo знает, кто вы, даже если это setuid.)
Пример:
$ sudo cp /bin/id /bin/test-id
$ sudo chmod u+s,g+s /bin/test-id
$ ls -la /bin/test-id
-rwsr-sr-x 1 root root 42K Jan 4 11:59 /bin/test-id*
$ /bin/test-id
uid=1000(grawity) gid=1000(grawity) euid=0(root) egid=0(root) groups=1000(grawity),3(sys),4(adm),10(wheel),100(users)
У недавно запущенной программы, подобной этой, уже будут права суперпользователя. Например, если вы передадите бит setuid для cat
или less
, любой пользователь сможет читать файлы только для root.
Программы могут изменить это состояние в двух направлениях: они могут изменить оба UID на EUID (полностью "становясь root"), или они могут изменить оба на реальный UID (отбрасывание привилегий и возврат к "обычному" пользователю). Я думаю, что sudo делает первое, но вы также часто будете видеть, как многие программы делают второе.
Обратите внимание, что оболочка bash также выполняет последнее: если вы попытаетесь задать бит setuid для /bin/bash
, то при запуске она откажется от своих привилегий setuid, если только она не была запущена с параметром -p
(--privileged). Вы можете увидеть это в bash's flags.c и shell.c.
Это важно, потому что, когда вы используете !
в ftp предоставленная команда не выполняется напрямую; на самом деле он запускается через оболочку, и то, что относится к оболочке, также применимо к! -командам. То есть процесс sh, запущенный ftp, фактически унаследует состояние setuid (euid = 0) точно так, как вы ожидаете, но перед тем, как выполнить предоставленную команду, откажется от него.
(Это значит что входишь !/bin/bash
фактически запускает * два * процесса оболочки: первый имеет правильный euid, но отбрасывает привилегии перед запуском второго.)
Вы можете проверить (и обойти) это, сказав ftp использовать что-то еще в качестве начальной оболочки:
$ ls -l /bin/id /bin/test-ftp
-rwxr-xr-x 1 root root 42K Aug 19 12:54 /bin/id*
-rwsr-sr-x 1 root root 137K Jan 4 12:08 /bin/test-ftp*
$ SHELL=/bin/id /bin/test-ftp
ftp> !
uid=1000(grawity) gid=1000(grawity) euid=0(root) egid=0(root) groups=0(root),3(sys),4(adm),10(wheel),100(users)
ftp>
(Примечание: не все программы смотрят на $ SHELL; некоторые всегда используют /bin /sh или вообще не используют оболочку.)