echo 'main(){}' | gcc -xc - -o /dev/stdout | ???
UNIX 계열 시스템에서 출력 바이너리를 실행하는 방법이 있습니까?
편집하다:출력을 작성할 수 없는 샌드박스 환경에서 g++를 실행하려면 이 것이 필요합니다.어느파일(악의적인 의도가 없음을 약속합니다).
답변1
나는 이것이 가능하다고 믿지 않습니다. 이것실행(2)시스템 호출에는 항상 파일 이름이나 절대 경로가 필요합니다(파일 이름은 항상 char*
). posix_spawn
파일 이름에도 비슷한 요구 사항이 있습니다.
가장 가까운 방법은 출력을 명명된 파이프로 연결하고 파이프에서 실행을 시도하는 것입니다. 비록 쉘이 비트가 설정되지 않은 파일의 실행을 거부할 수도 있지만 --x--x--x
이는 작동할 수 있습니다 . 파이프라인 생성mkfifo(1)
당신이 그것을 작동시킬 수 있는지 확인하십시오.
또 다른 접근 방식은 표준 입력을 읽고, 파일을 임시 영역에 쓰고, 거기에 --x 비트를 설정하고, 분기하고 실행한 다음 파일을 삭제하는 것을 작성하는 것입니다. inode와 내용은 프로그램 실행이 완료될 때까지 유지되지만 파일 시스템을 통해 액세스할 수는 없습니다. 프로세스가 종료되면 inode가 해제되고 저장 공간이 사용 가능 목록으로 반환됩니다.
편집하다:Mat가 지적했듯이 첫 번째 접근 방식은 로더가 실행 파일에서 페이지를 요청하려고 시도하기 때문에 작동하지 않습니다. 이로 인해 파이프에서는 불가능한 파일에 대한 임의 검색 트래픽이 생성됩니다. 이것은 두 번째 방법과 같은 것을 남깁니다.
답변2
당신은 시도 할 수 있습니다TCC, 중간 파일을 작성하지 않고 한 단계로 프로그램을 컴파일하고 실행합니다. 그것은 당신에게 문제가 될 수 있는 gcc가 아니지만 매우 빠르기 때문에 gcc보다 당신의 목적에 더 잘 맞을 수도 있습니다.
답변3
memfd 시스템 호출을 사용한 솔루션:https://github.com/abbat/elfexec
exec
.pseudocode 에서 찾을 수 있는 명명된 파일 설명자를 메모리에 생성합니다 .
#include <linux/memfd.h>
...
int memfd = syscall(SYS_memfd_create, "someName", 0);
...
write(memfd,... elf-content...);
...
fexecve(memfd, argv, environ);
답변4
그럼에도 불구하고 gcc
C 파일을 실행 파일로 컴파일할 때 많은 임시 파일이 생성됩니다.
$ echo 'int main(){}' | strace -fe /open -o >(grep CREAT) gcc -xc -
96706 openat(AT_FDCWD, "/tmp/ccxiPEgx.s", O_RDWR|O_CREAT|O_EXCL, 0600) = 3
96707 openat(AT_FDCWD, "/tmp/ccxiPEgx.s", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 0
96706 openat(AT_FDCWD, "/tmp/ccIBSUD4.o", O_RDWR|O_CREAT|O_EXCL, 0600) = 3
96711 openat(AT_FDCWD, "/tmp/ccIBSUD4.o", O_RDWR|O_CREAT|O_TRUNC, 0666) = 3
96706 openat(AT_FDCWD, "/tmp/cciAP0FV.res", O_RDWR|O_CREAT|O_EXCL, 0600) = 3
96712 openat(AT_FDCWD, "/tmp/ccfZa2PH.cdtor.c", O_RDWR|O_CREAT|O_EXCL, 0600) = 3
96712 openat(AT_FDCWD, "/tmp/cc4LkCnx.cdtor.o", O_RDWR|O_CREAT|O_EXCL, 0600) = 3
96713 openat(AT_FDCWD, "a.out", O_RDWR|O_CREAT|O_TRUNC, 0666) = 3
따라서 최종 실행 파일을 위해 또 하나를 만드는 것이 좋습니다.
Linux의 경우 사전 제거될 수 있습니다. 예를 들어 여기 문서 또는 여기 문자열을 삭제된 임시 파일(예: zsh)로 여전히 구현하는 셸의 경우:
$ echo 'int main(){puts("Hello World");}' | { gcc -o /dev/fd/3 -x c - && /dev/fd/3; } 3<<< ''
<stdin>: In function ‘main’:
<stdin>:1:12: warning: implicit declaration of function ‘puts’ [-Wimplicit-function-declaration]
<stdin>:1:1: note: include ‘<stdio.h>’ or provide a declaration of ‘puts’
Hello World