Codificação não nula inesperada de / proc / pid / cmdline

1

Estou analisando o valor /proc/pid/cmdline para vários processos no meu sistema Linux (Ubuntu 16.04) e descobri que, embora a maioria das entradas seja codificada com nulo, como esperado , pelo menos um usa espaços para delimitadores que acho inesperados.

De a documentação para proc (5) não vejo nenhuma indicação que isso deveria estar acontecendo. Existe algum caso em que eu deveria esperar espaços como delimitadores em vez de valores nulos? Se sim, onde posso encontrar documentação que descreva o comportamento?

Comportamento

Isso é o que eu vejo quando tento catar o cmdline para um dos processos do navegador cromo (observe que o caractere de espaço é usado para delimitar os valores):

user@host:~$ cat /proc/2721/cmdline
/usr/lib/chromium-browser/chromium-browser --type=gpu-process --field-trial-handle=2073283832741738928,4790986738309707242,131072 --gpu-preferences=GAAAAAAAAAAAAQAAAQAAAAAAAAAAAGAA --gpu-vendor-id=0x15ad --gpu-device-id=0x0405 --gpu-driver-vendor=Mesa --gpu-driver-version=17.2.8 --gpu-driver-date --service-request-channel-token=3778166CAD6E96F44A7268DF1AB1DD53

Eu esperaria ver algo assim (valores nulos como delimitador), que é o que eu faço ver de outros processos no sistema:

 ~$ cat /proc/354/cmdline
vmware-vmblock-fuse/run/vmblock-fuse-orw,subtype=vmware-vmblock,default_permissions,allow_other,dev,suid
    
por bluemorpho 20.03.2018 / 22:02

1 resposta

6

at least one uses spaces for delimiters

Incorreto.

Se você olhar o final do pseudo-arquivo no FreeBSD / TrueOS, onde você pode encontrar exatamente o mesmo comportamento com o Chromium, você encontrará um . Este é terminado em.. É um único argumento .

O Chromium está sobrescrevendo seus argumentos após um fork() , para dar a você algo interessante para ver na saída de ps . Está usando a função de biblioteca setproctitle() . Isso faz parte das bibliotecas BSD C. Não faz parte da biblioteca GNU C. Nas plataformas GNU C, o Chromium usa um setproctitle() de sua própria que sobrescreve os dados argv diretamente.

setproctitle() não é de fato a ferramenta certa para este trabalho, porque não permite configurar mais de uma cadeia de argumento. Ele define o "título" formatado como o 0º argumento e define a contagem de argumentos como 1. Tudo é organizado através da função de biblioteca como um único argumento.

Este não é o único problema com setproctitle() . A versão da biblioteca FreeBSD / OpenBSD / NetBSD C também tem uma limitação arbitrária de 2KiB, herdada diretamente do antigo programa sendmail do BSD (do qual a função biblioteca foi originalmente levantada no caso do FreeBSD), que é muito curta para o que o Chromium define linhas de comando para. E tanto o próprio Chromium quanto a versão da biblioteca FreeBSD / OpenBSD / NetBSD C tem funcionalidade extra, sendo que a string de formato é um ponteiro nulo, que o Chromium não usa (mas, ironicamente, tem que lidar com sua própria implementação de setproctitle() ) .

Pode-se fazer muito melhor com menos código. A chamada de sistema subjacente no FreeBSD / TrueOS que a função de biblioteca chama para fazer o trabalho, uma vez que tenha construído os dados do argumento, é a função sysctl() , levando CTL_KERN , KERN_PROC , KERN_PROC_ARGS e um ID de processo como o endereço. Este pode aceitar várias sequências terminadas em ␀. Eu escrevi uma função setprocargv() razoavelmente simples para meus conjuntos de ferramentas que usam isso.

extern
void
setprocargv (
    size_t argc,
    const char * argv[]
) {
#if defined(__FreeBSD__) || defined(__DragonFly__)
    std::string s;
    for (size_t c(0); c < argc; ++c) {
        if (!argv[c]) break;
        s += argv[c];
        s += '
% /package/admin/nosh/command/exec foreground pause \; true &
[1] 30318
% hexdump -C /proc/30318/cmdline
00000000  66 6f 72 65 67 72 6f 75  6e 64 00 70 61 75 73 65  |foreground.pause|
00000010  00 3b 00 74 72 75 65 00                           |.;.true.|
00000018
% hexdump -C /proc/30319/cmdline
00000000  70 61 75 73 65 00                                 |pause.|
00000006
%
'; } const int oid[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, getpid() }; sysctl(oid, sizeof oid/sizeof *oid, 0, 0, s.data(), s.length()); #elif defined(__OpenBSD__) …

(o OpenBSD / NetBSD faz as coisas da maneira antiga que o FreeBSD / TrueOS costumava fazer, com uma estrutura ps_strings na memória do aplicativo, mas ainda é sysctl() que é a chamada de sistema subjacente usada para encontrar a localização desse estrutura.)

  for (size_t i = 1; i < command_line->argv().size(); ++i) {
    if (!title.empty())
      title += " ";
    title += command_line->argv()[i];
  }
  // Disable prepending argv[0] with '-' if we prepended it ourselves above.
  setproctitle(have_argv0 ? "-%s" : "%s", title.c_str());

Como setproctitle() é a ferramenta errada para o trabalho, Cromo está pegando os novos membros argv e construindo uma única string longa delimitada por ␠ deles , para ser passada como um único argumento para setproctitle() .

extern
void
setprocargv (
    size_t argc,
    const char * argv[]
) {
#if defined(__FreeBSD__) || defined(__DragonFly__)
    std::string s;
    for (size_t c(0); c < argc; ++c) {
        if (!argv[c]) break;
        s += argv[c];
        s += '
% /package/admin/nosh/command/exec foreground pause \; true &
[1] 30318
% hexdump -C /proc/30318/cmdline
00000000  66 6f 72 65 67 72 6f 75  6e 64 00 70 61 75 73 65  |foreground.pause|
00000010  00 3b 00 74 72 75 65 00                           |.;.true.|
00000018
% hexdump -C /proc/30319/cmdline
00000000  70 61 75 73 65 00                                 |pause.|
00000006
%
'; } const int oid[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, getpid() }; sysctl(oid, sizeof oid/sizeof *oid, 0, 0, s.data(), s.length()); #elif defined(__OpenBSD__) …

Como você pode ver, o próprio Chromium já possui o novo vetor argumento como uma série de strings terminadas em ␀. Ele está passando por uma camada de biblioteca intermediária que precisa de todos eles agrupados em uma cadeia, onde o nível de chamada real do sistema, no entanto, opera em termos de um vetor de argumento de sequências terminadas em.

Daí o comportamento que você está testemunhando, onde o Chromium está apresentando seus vetores de argumentos alterados para o sistema como um único argumento .

Talvez você possa persuadir os redatores do Chromium a adotar algo como setprocargv() . ☺

Leitura adicional

  • Peter Wemm (1995-12-16). setproctitle . Manual de Funções da Biblioteca do FreeBSD . FreeBSD.
por 21.03.2018 / 22:39