Использование $ORIGIN с приложением setuid не прерывается, как ожидалось

У меня есть библиотека librandom.so и main exectuable, которая была скомпилирована следующим образом:

$ clang++ -o main main.o -lrandom -L. -Wl,-rpath,"\$ORIGIN"

Они оба находятся в одном каталоге. Поскольку main имеет $ORIGIN в своем rpath, он отлично работает - ./main возвращается без ошибок.

Теперь я устанавливаю main для запуска с setuid как root:

$ sudo chown root main
$ sudo chmod a+s main
$ ./main

Я ожидал, что main завершится с ошибкой, так как $ORIGIN не будет расширен в приложениях setuid. Удивительно, но это работает.

Если я запустил main из другого каталога, он не работает, как ожидалось:

$ cd /tmp    
$ /path/to/main
/path/to/main: error while loading shared libraries: librandom.so: cannot open shared object file: No such file or directory

Почему это работает, когда я запускаю main из его содержащей каталог?

Ответ 1

Я ожидал, что основная ошибка завершится неудачей, поскольку $ORIGIN не расширяется в приложениях setuid. Удивительно, но это работает.

Glibc имеет длинную историю расширения $ORIGIN даже для двоичных файлов suid (см., например, CVE-2010-3847). Мотивация заключается в том, что суицидальные двоичные файлы, использующие $ORIGIN для rpath, разбиты по дизайну, поэтому разработчикам Glibc никогда не очень хотелось это исправлять. Некоторые дистрибутивы, расположенные ниже по потоку, предоставляют исправления на складе Glibc, которые отключают расширение ORIGIN, поэтому точное соответствие зависит от вашего дистрибутива.

Забавно, только свободностоящий $ORIGIN будет расширен - если вы замените его, например. $ORIGIN/libs он начнет сбой.

Почему это работает, когда я запускаю main из его содержащей директории?

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