dup entre processos no Linux

5

Gostaria de digitar um descritor de arquivo em execução em um processo não relacionado no Linux. Eu sei sobre sendmsg (2) e SCM_RIGHTS (por exemplo, link ), mas isso funciona somente se o outro processo estiver cooperando. Eu preciso de uma solução que não precise de cooperação ativa do outro processo. Eu também sei que eu poderia criar o descritor de arquivo primeiro, manter uma cópia e depois criar o outro processo, mas preciso de uma solução na qual o outro processo crie seu próprio descritor de arquivo.

Eu posso ver o descritor de arquivo:

$ ls -l /proc/13115/fd/3
lrwx------ 1 pts pts 64 2013-05-04 13:15 /proc/13115/fd/3 -> socket:[19445454]

No entanto, open("/proc/13115/fd/3", O_RDWR) executado em outro processo retorna o erro Nenhum dispositivo ou endereço . Há algo mais que funcionaria? Provavelmente com ptrace ?

    
por pts 04.05.2013 / 13:36

2 respostas

4

Isso ocorre por design: o compartilhamento de descritores de arquivos com outros processos é explícito. Por padrão, os descritores de arquivos são tão particulares quanto a própria memória do processo.

Como de costume, se você tem o direito de ptrace o processo, você pode fazer o que quiser, inclusive fazê-lo chame sendmsg . Tradicionalmente, chamar ptrace requer a execução como o mesmo ID do usuário; restrições de segurança, como SELinux, capacidades, cadeias, etc., podem tornar ptrace mais restritivas. Por exemplo, na configuração padrão do Ubuntu, um processo não-raiz só pode chamar ptrace em seus próprios descendentes (por meio do AppArmor).

Usar ptrace de maneira robusta é um pouco complicado: você precisa injetar os dados corretos, certificar-se de não sobrescrever nada e limpar a si mesmo. Então, minha recomendação é injetar o código de forma indireta e acionar esse código com uma ferramenta existente.

Escreva uma pequena biblioteca compartilhada contendo o código sendmsg e LD_PRELOAD para o outro processo. Veja alguns códigos esqueléticos não testados com a verificação de erros em falta.

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);
}

Em seguida, para acionar o código, execute gdb -n -pid 13115 -batch -x /dev/stdin com popen e insira-o dessa forma (onde %d é o fd que você deseja obter e %s é um caminho para um soquete unix que você vimos anteriormente e estamos ouvindo):

call pts_gift_fd("%s", %d)
detach
quit
    
por 05.05.2013 / 21:01
4

Você não pode fazer isso pelo mesmo motivo que não pode acessar a memória de um processo não relacionado, porque um descritor de arquivo é parte da memória de outro processo. A única razão pela qual há informações sobre coisas como essa em /proc é porque o kernel fornece lá, e é somente leitura (portanto, há meios para examinar uma cópia da memória de processo).

Se estiver relacionado a um arquivo, você pode, é claro, tentar acessar o arquivo. Se for um socket, você pode espioná-lo usando libpcap ou algo derivado dele.

A situação é basicamente esta: um descritor de arquivo é (novamente) parte da memória de um processo. O descritor tem um buffer subjacente que existe no espaço do kernel; quando o processo lê ou grava para / do descritor, ele está gravando para e desse buffer. Para os dados que saem, o kernel libera o buffer (para hardware) apropriadamente; para os dados que chegam, ele recarrega o buffer (do hardware) quando o processo o esvazia. Esses buffers não são, AFAIK, acessíveis a outros processos, embora existam alguns meios (ex. Libpcap) de ler os dados de alguma forma determinada pela interface do kernel em particular, assim como a interface proc pode fornecer alguns dados da memória do espaço do usuário do processo.

    
por 04.05.2013 / 14:12