스크립트에서 $0에 의존하는 것은 위험하다고 합니다(종종 가짜로 인용되는 경우: exec -a ...). 예, 쓰기 권한이 있는 디렉토리에서 $0를 위조하기 위해 스크립트에 심볼릭 링크를 걸 수 있습니다. 하지만 쓰기 권한이 없는 경로(예: 아래 /bin/pwd)를 $0으로 지정하려면 어떻게 해야 합니까?
아래에서 내 스크립트가 shebang을 사용한다고 가정하면 구현할 수 없습니다. 대상 스크립트가 shebang을 사용할 때 수행될 수 있습니까?
$ (exec -a /bin/pwd /tmp/a0.sh)
no-shebang: argv0=/bin/pwd /proc/.../cmdline=/bin/bash^@--noediting^@-i^@
$ (exec -a /bin/pwd /tmp/a1.sh)
yes-shebang: argv0=/tmp/a1.sh /proc/.../cmdline=/bin/sh^@/tmp/a1.sh^@
$ head /tmp/a0.sh /tmp/a1.sh
==> /tmp/a0.sh <==
echo no-shebang: argv0="$0" /proc/.../cmdline=$(cat -v /proc/$$/cmdline)
==> /tmp/a1.sh <==
#!/bin/sh
echo yes-shebang: argv0="$0" /proc/.../cmdline=$(cat -v /proc/$$/cmdline)
즉, 스크립트(및 해당 상위 디렉터리)가 쓰기 금지되어 있고 shebang을 사용하는 경우 다른 쓰기 금지 경로를 위조하지 않고 $0를 사용하는 것이 안전한가요?
이것은 $0의 간단한 위조로 bash의 exec 문(centos 7에서)을 사용합니다. execve()를 사용하는 C 프로그램은 다르지 않을까요? bash의 exec가 너무 약한 것이 아니라 execve() (커널 또는 shebang-target에서)의 다운스트림을 가짜로 만드는 것이 실패입니까?
편집: C의 execve()도 shebang의 경우 $0를 위조하지 않으며 출력은 위와 동일합니다.
#include <stdio.h>
int main(void) {
char* argv[] = { "/bin/pwd", NULL };
execve("/tmp/a1.sh", argv, NULL);
perror(NULL);
}
사용자에게 루트 액세스 권한이 있으면 가짜 $0이 문제가 되지 않는다는 것을 알고 있습니다. 그러나 내 쓰기 금지 스크립트(shebang 사용)는 루트가 아닌 사용자가 $0(다른 쓰기 금지 경로)를 위조하는 데 사용할 수 없습니다. $0의 위험("그냥 exec -a..."를 사용)은 잘못된 것 같습니다. .
답변1
훌륭한,매뉴얼 execve(2)
페이지설명하다:
통역사 스크립트
인터프리터 스크립트는 실행 권한이 활성화된 텍스트 파일이며 첫 번째 줄의 형식은 다음과 같습니다.
#!interpreter [optional-arg]
인터프리터는 실행 파일에 대한 유효한 경로 이름이어야 합니다.
execve()에 대한 경로 이름 인수가 인터프리터
스크립트를 지정하는 경우
인터프리터는 다음 인수를 사용하여 호출됩니다.interpreter [optional-arg] pathname arg...
그래서 를 실행하면 exec -a /bin/pwd /tmp/a1.sh
시스템이 실행되고 /bin/sh /tmp/a1.sh
, 이렇게 실행하면 $0
스크립트 파일 이름을 기준으로 쉘이 설정됩니다.
셸에서 가져온 값은 argv[0]
표시되지 않습니다. 예를 들어 에는 exec -a foobar /bin/sh /tmp/a1.sh
여전히 표시되며 의 내용으로 판단하면 스크립트를 실행할 때 설정된 값은 어쨌든 손실됩니다 ./tmp/a1.sh
$0
/proc/.../cmdline
그러나 이것이 스크립트에 표시된 값이 $0
위조될 수 없다는 의미는 아닙니다. 사용자는 스크립트에 대한 심볼릭 링크를 생성하고 링크를 통해 이를 호출하거나 다음을 수행할 수 있습니다.
/bin/sh -c ". /tmp/a1.sh" foobar
이는 단순히 소스를 $0
로 설정됩니다 .foobar
/tmp/a1.sh