Percio Castelo.
EN Currículo
Quando um redirecionamento de shell revela um conflito de arquitetura ELF
← Voltar para blog

Quando um redirecionamento de shell revela um conflito de arquitetura ELF

01/11/2026 · 4 min · Linux · 150 visualizações

Quando um redirecionamento de shell revela um conflito de arquitetura ELF#

Às vezes, uma tarefa simples no desktop esconde um problema de arquitetura muito mais profundo. Recentemente passei por uma situação curiosa que começou com uma edição rápida em um atalho de aplicativo no Linux Mint e terminou em uma investigação envolvendo descritores de arquivo, chamadas de sistema e cabeçalhos de binários ELF.

A meta inicial era direta: adicionar uma porta de depuração remota do Chromium através da flag --remote-debugging-port em um aplicativo baseado em Electron chamado antigravity, silenciando a saída padrão e os erros em segundo plano:

--remote-debugging-port=31905 > /dev/null 2>&1 &

O comando parecia inofensivo, mas o comportamento resultante desafiou a lógica do shell.


O lançador desktop e o problema das abas fantasmas#

A primeira tentativa foi editar o arquivo .desktop do lançador do sistema em ~/.local/share/applications/.

A linha Exec original era:

/usr/share/antigravity/antigravity %F

De acordo com o padrão FreeDesktop XDG, o ambiente gráfico despacha comandos utilizando chamadas diretas da família execvp(). Isso significa que operadores de redirecionamento (>, &, |) não são interpretados pelo shell nativamente. Quando passados diretamente na linha Exec, o lançador os entrega como argumentos literais no vetor argv[].

Para contornar essa regra, tentei encapsular a chamada dentro de um subshell:

sh -c "/usr/share/antigravity/antigravity --remote-debugging-port=31905 %F > /dev/null 2>&1"

O programa abriu na tela, mas com um sintoma estranho: ele criou abas vazias com os nomes %F, >, null e 2>&1.

Testei passar o terminador de opções padrão POSIX (--), que orienta o parser de argumentos a encerrar a leitura de parâmetros:

/usr/share/antigravity/antigravity --remote-debugging-port=31905 -- %F > /dev/null 2>&1

O problema continuou. Tentei forçar a substituição de processo com exec:

sh -c 'exec /usr/share/antigravity/antigravity --remote-debugging-port=31905 > /dev/null 2>&1'

As abas persistiam. O aplicativo parecia ignorar os operadores de redirecionamento e interpretá-los como caminhos de arquivo para carregar na interface.


Isolando descritores de arquivo com Bash e C#

Para verificar se o problema era vazamento de argumentos pelo ambiente gráfico, criei um script limpo redirecionando os descritores de arquivo 1 (stdout) e 2 (stderr) diretamente no shell antes de invocar o programa:

#!/bin/bash
exec > /dev/null
exec 2>&1

/usr/share/antigravity/antigravity --remote-debugging-port=31905 "$@"

Mesmo assim, o aplicativo continuava abrindo as abas com os nomes literais dos operadores.

Para eliminar completamente o interpretador de comandos da equação, escrevi um wrapper em C usando chamadas de sistema diretas (open, dup2 e execv), garantindo que o vetor argv estivesse estritamente sanitizado:

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
    int devnull = open("/dev/null", O_WRONLY);
    if (devnull != -1) {
        dup2(devnull, 1);
        dup2(devnull, 2);
        close(devnull);
    }

    char *new_argv[argc + 2];
    new_argv[0] = "/usr/share/antigravity/antigravity";
    new_argv[1] = "--remote-debugging-port=31905";

    for (int i = 1; i < argc; i++) {
        new_argv[i+1] = argv[i];
    }
    new_argv[argc + 1] = NULL;

    execv(new_argv[0], new_argv);
    perror("Erro ao executar execv");
    return 1;
}

Compilei o código e executei. O programa continuou abrindo as mesmas abas fantasmas. Um programa compilado chamando execv sem passar caracteres de redirecionamento não deveria ter como transferir essas strings para o processo final. Algo no binário de destino estava quebrado.


O teste no terminal e o erro de formato de execução#

Decidi rodar o executável diretamente pelo terminal a partir do script wrapper configurado no sistema (ragy):

user@host:~$ ragy
🚀 Launching Antigravity with CDP on port 31905...
Warning: 'remote-debugging-port' is not in the list of known options, but still passed to Electron/Chromium.

Logo após essa mensagem, o terminal devolveu uma linha reveladora:

/usr/bin/antigravity: 62: /usr/share/antigravity/bin/../antigravity: Exec format error

A mensagem Exec format error corresponde ao código de erro ENOEXEC, emitido pelo kernel do Linux quando a rotina load_elf_binary() em fs/binfmt_elf.c recusa o arquivo executável. Isso acontece quando o número mágico não coincide, o arquivo não tem permissão de execução ou o cabeçalho de arquitetura não corresponde à CPU da máquina.

Isso explicava por que o binário original falhava. Mas por que a janela gráfica ainda abria com as abas fantasmas?

O script wrapper distribuído com o pacote possuía uma rotina interna de fallback mal construída: ao capturar o erro ENOEXEC no executável principal, ele despachava a linha de comando original para um processo secundário (language_server), que tratava cada token de redirecionamento (>, &, null) como caminhos de arquivos para abrir no editor.


Inspecionando os cabeçalhos ELF com readelf e file#

Com o erro de formato identificado, chequei os cabeçalhos do binário principal em uma máquina com processador x86-64:

readelf -h /usr/share/antigravity/antigravity

A saída apontou a causa raiz do problema:

  Classe: ELF64
  Tipo: DYN (Position-Independent Executable file)
  Maquina: AArch64
  Versao: 0x1

A máquina host rodava uma CPU Intel/AMD de 64 bits (x86-64), mas o executável instalado era compilado para ARM de 64 bits (AArch64).

Para conferir todos os binários da pasta:

find /usr/share/antigravity/ -executable -type f -exec file {} + | grep ELF

O resultado confirmou a discrepância:

/usr/share/antigravity/antigravity: ELF 64-bit LSB pie executable, ARM aarch64...
/usr/share/antigravity/libvulkan.so.1: ELF 64-bit LSB shared object, ARM aarch64...
/usr/share/antigravity/chrome-sandbox: setuid ELF 64-bit LSB pie executable, ARM aarch64...
/usr/share/antigravity/resources/app/extensions/antigravity/bin/language_server_linux_x64: ELF 64-bit LSB pie executable, x86-64...

Quase todos os arquivos eram binários ARM. O único binário compilado para x86-64 era o executável auxiliar do servidor de linguagem. Quando o binário principal falhava com ENOEXEC, o wrapper ativava o processo secundário em modo de contingência, gerando a confusão de abas.

A solução foi remover o pacote incompatível (sudo apt purge antigravity) e instalar a versão correta construída para a arquitetura amd64/x86_64. Após instalar o pacote adequado, o atalho original funcionou de primeira sem abrir abas extras.


Da linha de comando aos cabeçalhos ELF: lições práticas#

Esse diagnóstico deixou três aprendizados úteis para o dia a dia com ambientes Linux:

  1. Desconfie de comportamentos visuais anômalos em wrappers: quando um aplicativo ignora redirecionamentos básicos do shell ou chamadas limpas de dup2, o binário principal pode estar caindo em rotinas de contingência mal documentadas.
  2. Execute no terminal antes de criar soluções complexas: rodar o comando diretamente no console teria exposto a mensagem Exec format error muito antes de escrever wrappers em C ou scripts adicionais.
  3. Valide a arquitetura do binário com readelf ou file: quando um programa instalado manualmente apresentar falhas inexplicáveis, conferir o cabeçalho ELF ajuda a descartar pacotes baixados com a arquitetura errada em segundos.

Este artigo foi útil?

Deixe uma reação rápida para apoiar o conteúdo:

150 leituras
Creative Commons Atribuição-NãoComercial

Este post está licenciado sob CC BY-NC.

Comentários

Participe da discussão abaixo.

0 comentários