LINUX.ORG.RU

glibc небезопасна

 , ,


0

7

Привет, ЛОР!

Наткнулся тут на прекрасную историю о том, как использование казалось бы обычных функций из libc может оторвать жопу. И даже Rust не поможет!

Ссылка: https://www.edgedb.com/blog/c-stdlib-isn-t-threadsafe-and-even-safe-rust-didn-t-save-us

Для Ъ:

Функции getenv() и setenv() небезопасны в многопоточных программах. В частности, вызов setenv() во время выполнения getenv() в другом потоке может привести к порче памяти и падению программы. Это особенно релевантно на ARM64, потому как архитектура предоставляет меньше гарантий по части очерёдности выполнения команд.

И если бы это можно было списать на кривые руки авторов статьи, проблемы бы не было. Но тут суть в том, что огромное количество библиотек дёргают getenv() и setenv() под капотом с разными целями, в том числе гнутое gettext и прочие openssl.

Скажи, ЛОР, сишники совсем разучились писать безопасный код? Как с этим жить-то вообще?

UPD:

Подробный пост об этой проблеме: https://www.evanjones.ca/setenv-is-not-thread-safe.html

Прекрасное оттуда:

glibc uses an array to hold pointers to the "NAME=value" strings. It holds a lock in setenv() when changing this array, but not in getenv(). If a thread calling setenv() needs to resize the array of pointers, it copies the values to a new array and frees the previous one. This can cause other threads executing getenv() to crash, since they are now iterating deallocated memory.

То есть, вызов getenv() из glibc потенциально является use-after-free в многопоточной программе и от этого никак нельзя защититься.

★★★★★

Последнее исправление: hateyoufeel (всего исправлений: 3)

Не понятно только зачем может понадобиться setenv. Это само по себе – костыль.

Типа, а зачем?

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

там тоже был execve()

Раз в стандарт в таком виде не прошло, значит был конфликт с какой-то из реализаций.

И везде фразы про то, что такое char **environ.

А ты точно везде посмотрел что же это такое? Потому что он везде extern и это - единственное, что про него известно. Говоря по-простому модифицировать его (в обход puttenv()) нельзя.

Более того, хорошо видно, что изначально это был read-only блок памяти:

The function putenv was added to System V in System V Release 2.0.

The function putenv manipulates the environment pointed to by environ, and can be used in conjunction with getenv. However, envp, the third argument to main, is not changed [see EXEC(BA_OS)]. A potential error is to call the function putenv with a pointer to an automatic variable as the argument and to then exit the calling function while string is still part of the environment.

Unix Seventh Edition Manual.

В шестом массив заканчивался -1, а не NULL.

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

Понятно, что «envp, the third argument to main, is not changed». Так как:

The C run-time start-off routine places a copy of envp in the global cell environ, which is used by execv and execl to pass the environment to any subprograms executed by the current program.

environ — копия, с чего он становится read-only?

А в Sys 5R2 этот кусок убрали, дали putenv(), который, ну такое счастье.

mky ★★★★★
()

setenv

Какие-то линуксячие или посиксные костыли. Переменные среды должны задаваться один раз при старте. Никаких изменений во время работы быть не должно. Так что проблема фикситься простым выпиливанием setenv.

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

добавили в POSIX только в 2001-ом.

Нашёл я как-бы POSIX'ы 1988 и 1990 года, в виде FIPS (Federal Information Processing Standard) https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub151-1.pdf https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub151-2.pdf
Там есть execve(). И FIPS был актуальнее POSIX, так как все хотели поставить свою ОС за деньги правительства США.

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

environ — копия, с чего он становится read-only?

Я не сказал, что он становится, я сказал что он был в более ранних версиях. При putenv ты должен следить за временем жизни строки, что говорит о многом. setenv / unsetenv в целом логично заменили всю эту клоунаду на что-то человеческое, но привкус остался, конечно.

И FIPS был актуальнее POSIX, так как все хотели поставить свою ОС за деньги правительства США.

Нет, не все - Open Group была создана для продаж в Европе.

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

Open Group была создана

Ну создана и создана. Конкретно в какой версии POSIX нет execve()? Про POSIX.1-1996 пишут, что он согласован Single UNIX Specification version 2, но там есть execve().

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

Самого лучшего и единственного стабильного api под линукс – wine/win32api.

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

Конкретно в какой версии POSIX нет execve()? Про POSIX.1-1996

Да, там есть execve(), но там же написано и следующее:

3.1.2.2 Description
...
When a C program is executed as a result of this call, it shall be entered as a C language function call as follows:

     int main(int argc, char *argv[]);
where argc is the argument count and argv is an array of character pointers to the arguments themselves. In addition, the following variable:
     extern char **environ;
is initialized as a pointer to an array of character pointers to the environment strings.
...
For those forms not containing an envp pointer [execl(), execv(), execlp(), and execvp()], the environment for the new process image is taken from the external variable environ in the calling process.

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

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

Что, во всём перечисленном нет нативных функций для задания настроек?

иногда есть, но их например проблемно передать если MPI, исполнение на другом хосте, узле, ноде..

Во-первых что это за клевета про то что питон мой любимый, а во-вторых причём тут вообще питон?

про любимый язык - неважно. Важно что до первого обращения к dlopen должна быть определена PYTHON_HOME. Для прочих somelang - соотв. прочие.

ИТОГО, от общения и обращений к env никуда не деться. И этот грёбанный env - он исторически так сложился, и порой надо атомарно менять собственный.

MKuznetsov ★★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.