Linux에서 관련 없는 프로세스에서 실행 중인 파일 설명자를 복사하고 싶습니다. 나는 대해 알고있다메시지 보내기(2)그리고 SCM_RIGHTS
(예를 들어https://stackoverflow.com/questions/4489433/sending-file-descriptor-over-unix-domain-socket-and-select), 그러나 이는 다른 프로세스가 협력하는 경우에만 작동합니다. 다른 프로세스의 적극적인 협력이 필요하지 않은 솔루션이 필요합니다. 또한 파일 설명자를 먼저 만들고 복사본을 보관한 다음 다른 프로세스를 만들 수 있다는 것도 알고 있지만 다른 프로세스가 자체 파일 설명자를 만들 수 있도록 하는 솔루션이 필요합니다.
파일 설명자를 볼 수 있습니다.
$ ls -l /proc/13115/fd/3
lrwx------ 1 pts pts 64 2013-05-04 13:15 /proc/13115/fd/3 -> socket:[19445454]
그러나 open("/proc/13115/fd/3", O_RDWR)
다른 프로세스에서 실행하면 오류가 반환됩니다.해당 장치 또는 주소가 없습니다.. 다른 효율적인 방법이 있나요? 함께 있을 수도 있음길?
답변1
이는 의도적으로 설계된 것입니다. 파일 설명자를 다른 프로세스와 공유하는 것은 명시적입니다. 기본적으로 파일 설명자는 프로세스 자체 메모리만큼 비공개입니다.
평소처럼, 권리가 있다면길이 프로세스 동안 호출을 포함하여 원하는 모든 작업을 수행할 수 있습니다 sendmsg
. 전통적으로 호출은 ptrace
SELinux, 기능, 감옥 등과 같은 보안 제한으로 실행되어야 하며 ptrace
제한이 더욱 엄격해질 수 있습니다. 예를 들어 기본 Ubuntu 구성에서 루트가 아닌 프로세스는 ptrace
AppArmor를 통해 자신의 하위 프로세스만 호출할 수 있습니다.
강력하게 사용하는 것은 약간 까다롭습니다 ptrace
. 올바른 데이터를 주입해야 하고, 아무것도 덮어쓰지 않았는지 확인하고, 스스로 정리해야 합니다. 그래서 제가 제안하는 것은 로터리 방식으로 코드를 삽입하고 기존 도구를 사용하여 코드를 트리거하는 것입니다.
코드가 포함된 작은 공유 라이브러리를 작성 sendmsg
하고 LD_PRELOAD
다른 프로세스에서 사용할 수 있도록 합니다. 여기 몇 가지가 있습니다테스트되지 않은스켈레톤 코드 누락 오류 검사.
int pts_gift_fd (char *path, int fd) {
int sock;
struct sockaddr_un addr = {0};
struct msghdr msg = {0};
struct iovec iov = {0};
addr.sun_family = AF_UNIX;
strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
/* Populate msg, iov as in the code you've already found */
sock = socket(AF_UNIX, SOCK_STREAM, 0);
connect(sock, (struct sockaddr*)&addr, sizeof(addr));
sendmsg(sock, &msg, 0);
close(sock);
}
그런 다음 코드를 트리거하려면 다음과 같이 실행 gdb -n -pid 13115 -batch -x /dev/stdin
하고 popen
입력합니다( %d
가져오려는 fd는 어디에 있고, %s
이전에 생성하여 수신 대기 중인 Unix 소켓의 경로는 어디에 있습니까?).
call pts_gift_fd("%s", %d)
detach
quit
답변2
이렇게 할 수 없는 이유는 관련 없는 프로세스의 메모리에 접근할 수 없는 것과 같은 이유입니다.예다른 프로세스의 메모리 일부입니다. 이와 같은 정보가 존재하는 유일한 이유 /proc
는 커널이 해당 정보를 제공하고 읽기 전용이기 때문입니다.사본프로세스 메모리).
파일과 관련된 경우 해당 파일에 액세스해 볼 수 있습니다. 소켓이라면 다음을 사용하여 스누핑할 수 있습니다.libpcap또는 그로부터 파생된 것.
기본적으로 상황은 다음과 같습니다. 파일 설명자는 (다시) 프로세스 메모리의 일부입니다. 디스크립터에는 커널 공간에 존재하는 기본 버퍼가 있습니다. 프로세스가 디스크립터에서 읽거나 쓸 때 해당 버퍼에 쓰거나 쓰는 것입니다. 데이터 출력의 경우 커널은 버퍼(하드웨어로)를 적절하게 플러시합니다. 들어오는 데이터의 경우 프로세스가 버퍼를 지울 때 하드웨어에서 버퍼를 다시 채웁니다. AFAIK, 일부 방법(예: libpcap)이 있지만 이러한 버퍼는 다른 프로세스에서 액세스할 수 없습니다.읽다proc 인터페이스와 마찬가지로 특정 커널 인터페이스에 의해 결정되는 일부 데이터 형태는 프로세스의 사용자 공간 메모리에서 일부 데이터를 제공할 수 있습니다.