추가 읽기

추가 읽기

다음 환경의 프로세스가 있습니다.

root@a-vm:/proc/1363# hexdump -C environ
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
0000016c

나는 이와 같은 것을 본 적이 없습니다. environnull로 끝나는 key=value쌍이 포함될 것으로 예상되므로 이 출력은 다양한 주장을 위반합니다. 알려진 커널 버그를 보고 있는 건가요? 아니면 Unix/Linux에서 이를 수행할 수 있는 합법적인 방법이 있나요? (…그렇다면 왜? 커널이 이런 말도 안되는 일을 허용하는 이유는 무엇입니까?)

(리눅스에서는 3.13.0/Ubuntu Trusty)

(프로세스가 일부 임시 출력을 올바른 위치에 쓰지 않는 이유를 알아내려고 노력하는 동안 이 문제에 부딪혔습니다. 임시 저장을 위해 특정 디렉터리를 사용하고 있어야 했으며 환경 변수를 설정하여 해당 디렉터리에 대한 정보를 받았습니다. TMP; 그러나 나는 TMP많은 null 값이 아닌 매우 평범해 보이는 경로를 설정하고 있으며 완전히 비어 있는 환경을 본 적이 없습니다.

답변1

헛소리가 아닙니다. Linux에는 이를 수행할 수 있는 합법적인 방법이 있지만 여러분의 기대는 틀렸습니다.

커널이 프로그램 시작 코드에 전달한 인수 및 환경 문자열은 다른 프로그램 데이터와 마찬가지로 일반 응용 프로그램 공간 가상 메모리에 저장되며 다른 프로그램 데이터 변수와 마찬가지로 수정할 수 있습니다. 프로그램이 이를 수정하는 것은 완전히 합법적입니다.

(이것은 커널 제공 및 강제 관점에서 나온 것입니다. 특정 프로그래밍 언어에 대한 표준이 반드시 동일한 것을 말하는 것은 아닙니다. 그러나 커널에 관한 한 이는 읽을 수 있는 응용 프로그램 공간 영역일 뿐입니다. 프로그램 데이터를 위한 쓰기 가능한 가상 메모리, 커널은 기계어 코드를 컴파일한 프로그래밍 언어에 관심이 없습니다.

/proc/${PID}/environ파일은 응용 프로그램 공간의 가상 메모리에 대한 창일 뿐입니다. Linux는 프로세스의 실제 환경 데이터를 기억하지 않고 프로세스가 시작된 환경 영역의 시작 및 끝 주소만 기억하며 파일은 /proc/${PID}/environ현재 메모리에 있는 모든 것을 읽어옵니다. 이 파일에 ␀로 끝나는 문자열 목록이 포함될 것이라고 예상해서는 안됩니다. 이것은 잘못된 기대입니다.

이러한 문자열을 포함하는 메모리를 수정하는 GNU C 라이브러리 함수는 없습니다. 하지만 다양한 프로그램에는 이를 수행하는 고유한 기능이 있습니다.

예를 들어 OpenSSH를 고려해보세요. OpenSSH 서버는 ps매개변수 벡터의 표시 내용을 수정하여 읽습니다 sshd: JdeBP [priv].

OpenSSH 서버에는 Linux의 OpenBSD에서 BSD C 라이브러리의 기능을 에뮬레이션하려는 코드가 포함되어 있습니다. OpenBSD에는 명령에 의해 보고된 프로세스 인수 벡터를 setproctitle()무시할 수 있는 BSD C 라이브러리 함수가 호출됩니다 . ps해당 호출은 sysctl()커널에 새로운 인수 벡터를 전달하며, 이는 를 ps사용하여 읽을 수 있습니다 sysctl(). FreeBSD에도 비슷한 기능이 있습니다.

설명했듯이 Linux에서 커널은 실제 매개변수와 환경을 기억하지 않고 프로세스를 시작할 때 원래 배치되었던 메모리 영역의 시작 및 끝 주소만 기억합니다. 따라서 OpenSSH의 Linux 포트에는 setproctitle()위의 메모리 영역을 덮어쓰는 호환성 기능이 있습니다.

이 호환성 함수는 환경 영역의 전체 크기를 계산합니다.그리고매개변수 영역 및 재정의모두새 매개변수 문자열을 사용합니다. 이는 정상적인 상황에서 호출 프로그램이 setproctitle()프로세스가 원래 가지고 있던 매개변수 데이터 세트보다 긴 매개변수 데이터를 쓰려고 하기 때문에 수행됩니다. sshd이것을 자주 하십시오. 따라서 새 매개변수가 매개변수 영역 뒤의 환경 영역을 덮어쓸 수 있도록 하여 더 긴 매개변수 문자열 세트를 수용할 수 있는 더 많은 공간을 프로그램에 제공합니다.

중요한 것은 또한사용하지 않는 부분을 채워주세요전체 매개변수 및 환경 데이터의 원래 길이를 ␀s로 덮어쓸 필요가 없습니다.

당신이 보는 것은 이것의 정확한 결과입니다. 시스템에서 OpenSSH 서버 프로세스를 찾으면 찾을 수 있습니다 /proc/${PID}/environ.

추가 읽기

답변2

NUL이는 환경 변수가 있는 메모리 위치에 s를 쓰면 전적으로 가능합니다 .

#include <stdio.h>
#include <unistd.h>

extern char **environ;

int main(void)
{
    int i;
    char *p = *environ;
    /* hopefully your ENV is longer than this */
    for (i = 0; i < 10; i++) *(p + i) = 0;
    printf("hexdump -C /proc/%d/environ\n", getpid());
    sleep(99999);
}

빈 환경에서 프로그램을 시작하면 파일은 environ완전히 비어 있게 됩니다.

execle("/bin/sleep", "sleep", "999", (char *)NULL, (char *const) NULL)

따라서 이 상황은 프로세스가 실행된 후 프로세스가 수행하는 작업입니다(그리고 메모리를 어떻게든 잠그지 않으면 setenv(3)호출에 문제가 발생할 수 있지만 이러한 상황을 방지할 수 있는 방법은 거의 없습니다...).

관련 정보