Стандартное использование C для getenv и безопасных методов

Я пытаюсь написать код C, который использует некоторые переменные ENV в среде UNIX. Возникает вопрос: может ли чтение переменных (например, getenv()) вызвать переполнение буфера? Кроме того, как я могу найти предел размера переменной env для моей платформы? Например, какой заголовочный файл?

Наконец, каковы самые безопасные методы чтения кода, предоставленные средой?


person user1944224    schedule 22.02.2013    source источник
comment
Один из самых безопасных способов — не предполагать, что вы всегда найдете искомую переменную, поскольку переменные env могут быть установлены/сброшены пользователем оболочки.   -  person SeedmanJ    schedule 23.02.2013
comment
безопасно ли использовать getenv(), чтобы избежать переполнения Не переполнить что? Вы не предоставили буфер, поэтому getenv должен позаботиться об этом сам.   -  person dmckee --- ex-moderator kitten    schedule 23.02.2013
comment
я пересмотрел вопрос   -  person user1944224    schedule 23.02.2013
comment
Обратите внимание, что в стандарте C сказано, что строка, на которую указывает указатель, может быть перезаписана последующим вызовом getenv(), что не соответствует ожиданиям большинства людей (и в системах Unix это не является проблемой). . Итак, строго говоря, вам нужно сделать копию любой переменной среды, возвращаемой getenv(), прежде чем снова вызывать getenv(). Нет заголовка, который напрямую определяет ограничение на размер имен или значений env var. В POSIX ограничение ARG_MAX (которое часто составляет 256 КиБ) представляет собой общий размер «среды плюс аргументы», но это довольно большой и не всегда жесткий предел.   -  person Jonathan Leffler    schedule 23.02.2013


Ответы (4)


Чтение переменной среды с помощью getenv() не приведет к переполнению буфера.

В Linux унаследованные переменные среды и их значения сохраняются в адресном пространстве процесса ядром во время exec(). Функция getenv() просто возвращает указатель на эти существующие данные. Поскольку он не копирует никаких данных, буфера нет, и не может быть переполнения буфера.

Если вы попытаетесь передать слишком много переменных среды новому процессу, exec() будет сигнализировать об ошибке E2BIG.

Вопросы безопасности

На самом деле нет никаких проблем с переполнением буфера с переменными среды.

Проблемы безопасности связаны с тем фактом, что вы не должны доверять содержимому среды. Если ваша программа запускается с setuid (или setgid и т. д.), то среда является вектором атаки. Пользователь может злонамеренно установить PATH или LD_PRELOAD или другие переменные.

Однако программы с setuid пишутся редко. Это хорошо, так как существует множество причин, по которым трудно сделать программы setuid безопасными.

person Dietrich Epp    schedule 22.02.2013
comment
getenv возвращает char*, а не const char*. Это означает, что должна быть возможность записи по возвращаемому адресу (и, следовательно, может произойти переполнение буфера). - person zneak; 23.02.2013
comment
@zneak: Вы не должны писать на него. Это было бы const char *, но это старый API, и если сделать его const сейчас, это сломает программы. - person Dietrich Epp; 23.02.2013
comment
@zneak: Конечно, вы можете написать ему, если вы действительно хотите изменить среду таким образом. Но переполнение буфера будет в вашем коде, а не в getenv(). - person Dietrich Epp; 23.02.2013
comment
Возможно, стоит предложить setenv в своем ответе. :) - person zneak; 23.02.2013
comment
@zneak: это не имеет отношения к вопросу. Вопрос касается чтения переменных среды. Цитата: Может ли чтение переменных (например, getenv()) вызвать переполнение буфера? - person Dietrich Epp; 23.02.2013
comment
Я указываю на это, потому что не думаю, что вопрос отражает то, что имел в виду спрашивающий. Совершенно очевидно, что вам не нужно знать, есть ли фиксированный размер для значений переменных среды, если только вы не хотите в них писать. - person zneak; 23.02.2013
comment
@zneak: Если вы хотите угадать вопрос, прокомментируйте вопрос. Если у вас есть свой ответ, напишите его как ответ. Попытка убедить меня, что я неправильно читаю вопрос, - просто пустая трата нашего времени. Ты лучше этого. - person Dietrich Epp; 23.02.2013

#include <stdio.h>
#include <stdlib.h>

int main()
{
    char *hai;
    printf("The current User name is\n");
    hai="USER";
    printf("%s\n",getenv(hai));
    printf("The current User Directory is\n");
    char *hai1="PWD";
    printf("%s\n",getenv(hai1));
    exit(0);
}

Эта программа передает аргумент функции getenv(), ее допустимое значение означает получение вывода

Output:
    The current User name is

    loganaayahee

    The current User Directory is

    /home/loganaayahee/AdvanceUnix/
(or)

Это не переменная среды означает, что функция getenv() возвращает NULL.

    hai="HELLO";
    if(getenv(hai)==NULL)
        printf("This is not Env\n");
    else
        printf("%s\n",getenv(hai));

Output:
    This is Not Env
person loganaayahee    schedule 23.02.2013
comment
Поскольку вы используете определения переменных C99, вы также должны использовать определения функций C99. Это означает, что вам нужен явный возвращаемый тип для main(), как и для int main(void). В целом избегайте глобальных переменных, таких как buf; вдвойне избегайте неиспользуемых глобальных переменных (таких как buf). Я рекомендую использовать return(0); в конце main(). Разберитесь с отступом. Используйте пробел между #include и <stdio.h>; так стандарт пишет такие строки. Строго говоря, вы можете получить нулевой указатель из getenv(), и в этом случае его печать ненадежна. В общем, немного сумбурно и небрежно. - person Jonathan Leffler; 23.02.2013
comment
Функция getenv() является аргументом и является одним указателем, и этот указатель указывает на одну строку, и если это неправильно, значит функция getenv() возвращает NULL. Так что же такое неправильный метод? я не понимаю - person loganaayahee; 23.02.2013
comment
Я не уверен, о чем вы спрашиваете, но если вы сделаете следующее: printf("NONEXISTENT=%s\n", getenv("NONEXISTENT")); и переменная окружения $NONEXISTENT не существует, вы можете получить дамп ядра. Некоторые версии printf() обнаруживают нулевой указатель и печатают что-то вроде (null) (это из Mac OS X 10.7.5), но вместо этого может произойти сбой. В целях безопасности вам нужно использовать что-то вроде: char *env = getenv("NONEXISTENT"); printf("NONEXISTENT=%s\n", var, (env == 0) ? "<undefined>" : env));, чтобы гарантировать отсутствие сбоя. Печать нулевого указателя в виде строки является поведением undefined, которого следует избегать любой ценой. - person Jonathan Leffler; 23.02.2013

Зависит от того, что вы подразумеваете под «чтением». Простой вызов getenv не вызовет никаких проблем. Однако, если вы попытаетесь скопировать возвращаемую строку в какой-либо буфер и не проверите предел буфера, вы можете получить переполнение буфера. Строка, возвращаемая getenv, может быть большой, без верхней границы, кроме доступной памяти, которую ваша система решает выделить среде.

Это не отличается от любого другого строкового ввода, который вы можете получить — остерегайтесь использования strcpy и sprintf, так как они не проверяют размер вашего выходного буфера.

person Chris Dodd    schedule 22.02.2013
comment
Иногда ARG_MAX является пределом (строго для аргументов командной строки плюс среда), но часто это очень существенно (256 КиБ), что достаточно много, чтобы большинство людей считали его «неограниченным». - person Jonathan Leffler; 23.02.2013

Вы должны быть осторожны с окружением, особенно если вы хотите передать его дочерним процессам. Например, среда должна содержать только одно значение для каждой переменной, но легко создать среду, содержащую несколько, если вы удалите первую и передадите результат, будет открыта другая. Если вы хотите очистить среду для детей, создайте ее с нуля, а не удаляя значения из той, что у вас есть. У Дэвида Уилера есть руководство по безопасному программированию в Unix/Linux на его веб-сайте.

person vonbrand    schedule 23.02.2013