Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
Ferramentas/GitHubGitHub/robertdfrench/ifuncd-up
Análise de VulnerabilidadesAnálise Dinâmica de Código (DAST)ExploraçãoEngenharia ReversaAnálise de BináriosSegurança da Cadeia de SuprimentosPapers e PesquisaAprendizado e Educação
GitHubrobertdfrench/ifuncd-up

ifuncd-up

GNU IFUNC é o verdadeiro culpado por trás do CVE-2024-3094

Ver Repositório
601há 3 mesesRevisado pelo Kitploit

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar
Site

Em Resposta ao Hacker News

Vejo que vocês, brincalhões do [site laranja][hn], estão me enchendo o saco. Farei algumas respostas abaixo, mas primeiro ofereço um desafio: enviarei $500 do meu próprio dinheiro para a primeira pessoa que demonstrar este ataque sem ifunc. Estou genuinamente interessado e disposto a pagar pelo esclarecimento. Faça um fork deste repositório e envie um PR com sua PoC funcional. Solicitarei seu endereço de e-mail em particular se você vencer. Agora, as respostas:

Isso é caçar pelo galho errado.

Garoto, eu vivo no galho errado, posso latir para quem eu quiser.

Não era essencial para o exploit,

Você não é essencial para o exploit!

Sempre existe o selinux se quisermos adicionar proteção contra código arbitrário executando como root.

Uma vez carregado, este ataque não precisou cruzar mais nenhum limite de syscall. Então sim, poderíamos ter restringido uma sessão "extra" de root, mas ainda assim teríamos convidados indesejados na máquina!

O que é isso, o aniversário do Bilbo?? Ninguém entra a não ser a negócios da festa!!

  1. IFUNC não é de forma alguma a única maneira de executar código antes do main.

Mas é uma maneira desnecessária de executar código antes da proteção de memória ser configurada.

  1. A alternativa que apresentam é discutivelmente menos segura porque o ponteiro de função permanecerá gravável durante toda a vida do processo.

Podemos improvisar com mprotect! Veja a última frase acima da subseção Modificando LD_PRELOAD.

É, este blog está equivocado.

Desculpe, este blog estava desorientado. Eu fiz todas essas travessuras sozinho! Ninguém me enganou para ser tão idiota.

IFUNC deveria ser implementado pelo [próprio] software [cliente],

@CountWSS 💯 é isso aí

uma série de falhas flagrantes de processo do mantenedor do Github até ...

Este é o único ponto ao qual responderei seriamente:

Acho extremamente injusto com o mantenedor do xz-utils e bastante perigoso para a comunidade pensar nisso como começando com um erro da parte dele. Começou com ninguém se importando em ajudar a manter este projeto. O atacante dependeu do ifunc como uma vulnerabilidade técnica e de nossa negligência coletiva com o xz-utils como uma vulnerabilidade social. Acho vergonhoso ver as ações do Sr. Collin como algo diferente de uma heróica dedicação de anos ao serviço comunitário.

Além disso, Bruce Schneier concorda comigo então... lamento por você, seu argumento está queimado.

A linguagem pode ter sido mais dura do que o necessário

Você não vai acreditar o quanto meus amigos me fizeram suavizar isso primeiro.

As distribuições Linux não deveriam pensar tão bem de si mesmas a ponto de esperar que o OpenBSD se conforme e se adapte à bagunça delas

@debazel!!! Me gusta.

Que completo absurdo.

Ok, essa parte está correta.

IFUNC'd up

Por que você deve parar de culpar o xz-utils pelo [CVE-2024-3094][nvd]. Também confira minha Palestra no ETSA!

Acho que IFUNC'd up

O CVE-2024-3094, mais conhecido como "O backdoor do xz-utils", foi um quase acidente para a cibersegurança global. Se este ataque não tivesse sido descoberto no último minuto por [Andres Freund][freund], a maioria dos servidores SSH do nosso planeta teria começado a conceder acesso root à parte por trás deste ataque.

Infelizmente, muita análise focou em como o [código malicioso][JiaT75] entrou no repositório do xz-utils. Em vez disso, gostaria de argumentar que duas decisões de design antigas em software livre crítico são o que tornou este ataque possível: [vincular o OpenSSH ao SystemD][biebl], e a existência do [GNU IFUNC][sourceware].

Antes de começar: Grande parte desta discussão trata dos meandros da vinculação dinâmica no Linux. Se precisar de uma revisão, confira dynamic_linking.md.

Breve Resumo do CVE-2024-3094

Há dezenas de bons resumos detalhando os detalhes de alto nível do backdoor do xz-utils, como o artigo de Dan Goodin [O que sabemos sobre o backdoor do xz Utils que quase infectou o mundo][goodin1] e o FAQ de Sam James sobre o [backdoor do xz-utils (CVE-2024-3094)][thesamesam]. Não precisamos repetir tudo isso aqui, então para os propósitos deste artigo, eis um resumo muito grosseiro:

  • Algumas distros Linux modificam o OpenSSH para depender do SystemD
  • O SystemD depende do xz-utils, que utiliza GNU IFUNC
  • Logo, o xz-utils acaba no espaço de endereçamento do OpenSSH
  • Isso permite que o IFUNC modifique código no servidor SSH```mermaid flowchart TD G["GNU IFUNC"] A["OpenSSH (OpenBSD)"] B["Portable OpenSSH
    (Linux / macOS / etc)"] C[OpenSSH + IFUNC] D[xz-utils] E["SystemD (Linux)"] A -->|Remove OpenBSD specifics| B B -->|Add SystemD specifics| C D --> E E --> C C --> F["Mayhem"] G --> D
root@kitploit:~
## Por que as Distribuições Linux modificam o OpenSSH?
A resposta curta é que elas precisam. O OpenSSH é desenvolvido pela
comunidade OpenBSD, para a comunidade OpenBSD, e eles não se importam
nem um pouco com o Linux.  O projeto [Portable OpenSSH][mindrot] é uma
coleção de patches de melhor esforço que substituem componentes específicos
do OpenBSD por componentes POSIX genéricos e algum código específico de
plataforma, quando aplicável. A cadeia de suprimentos de software para SSH
acaba se parecendo com algo assim na prática:```mermaid
flowchart TD
  subgraph OpenBSD Folks
    A[OpenBSD]
    B[OpenSSH]
    H[improvements]
  end
  B-->A
  A-->H
  H-->B

  B-->C
  C[Portable OpenSSH]

  subgraph Debian Folks
    D[Debian SSH]
    G[improvements]
  end
  C-->D
  D-->G
  G-->C

  subgraph Fedora Folks
    J[Fedora SSH]
    K[improvements]
  end
  C-->J
  J-->K
  K-->C

A versão do OpenSSH do OpenBSD é upstream em relação a tudo mais, e a maioria das melhorias vem da própria comunidade OpenBSD. Essas mudanças fluem downstream para o projeto Portable OpenSSH, que tenta reimplementar novas funcionalidades de maneiras que não sejam específicas do OpenBSD. Isso é o que permite que o SSH funcione em plataformas como Linux, macOS, FreeBSD e até Windows.

Mas não para por aí. Alguns sistemas operacionais aplicam personalizações adicionais além do que o Portable OpenSSH oferece. Por exemplo, a Apple adiciona a flag [--apple-use-keychain][keith] ao ssh-add para ajudá-lo a integrar com o gerenciador de senhas do macOS.

No caso do CVE-2024-3094, o Fedora e o Debian mantiveram seus próprios [patches do SystemD][biebl] para seus forks do OpenSSH a fim de corrigir uma [condição de corrida em torno das reinicializações do sshd][schmidt]. Então a cadeia de suprimentos real do SSH começou a se parecer com isso:```mermaid flowchart TD A[OpenSSH] B[Portable OpenSSH] C[Debian SSH] D[Fedora SSH] A-->B B-->C B-->D C<-->|SystemD Patches|D

root@kitploit:~
Esses patches nunca entraram no Portable OpenSSH, porque o pessoal do Portable OpenSSH estava ["não interessado em assumir uma dependência do libsystemd"][djmdjm]. E eles nunca entraram no OpenSSH upstream, porque o OpenBSD não tem necessidade de suportar SystemD.

### Preocupações sobre "Separação de Preocupações"
Isso parece inofensivo, mas é um exemplo de um problema muito maior em Código Aberto, particularmente no Linux: componentes críticos do sistema operacional são desenvolvidos por pessoas que não se conhecem e não conversam entre si.

* As pessoas que fizeram patches no OpenSSH para SystemD sabiam (ou se importavam) que o libsystemd depende do xz-utils?
* As pessoas do SystemD sabiam (ou se importavam) que o xz-utils havia começado a usar ifunc?
* As pessoas do OpenSSH sabiam (ou se importavam) que ifunc era uma coisa? Certamente não é uma coisa no OpenBSD.

Em certo sentido, essa quebra de comunicação é uma característica do código aberto: posso adaptar seu trabalho às minhas necessidades sem precisar incomodá-lo. Mas também pode levar a um grau de indireção que impede que suposições críticas de design (como um processo tradicional de vinculação dinâmica) sejam mantidas.

O corolário óbvio da [Lei de Conway][conway] é que se você está enviando seu organograma, também está enviando os bugs que vivem nas rachaduras do seu organograma. Nenhuma pessoa ou equipe realmente cometeu um erro aqui, mas com o benefício da retrospectiva, fica claro que os atacantes perceberam que a mão esquerda do SSH do Debian/Fedora não sabia o que a mão direita do xz-utils estava fazendo.

## O que o GNU IFUNC *supostamente* faz?
Ele permite determinar, em tempo de execução, qual versão de alguma função você gostaria de usar. Ele faz isso dando a oportunidade de executar **código arbitrário** para influenciar como o vinculador resolve símbolos.

![](https://assets.kitploit.com/production/public/readmes/31477/ea52603b42c9b38ff0f8f693b09c5d5c0d107a4175f3be4e1e48b39c9ca3eb55.png)

### Detectando Recursos da CPU
Suponha que você tenha uma aplicação que deve rodar em uma ampla variedade de CPUs x86. Dependendo das características específicas da CPU atual, você pode preferir usar diferentes algoritmos para a mesma tarefa. A ideia original por trás do IFUNC era permitir que programas verificassem recursos da CPU na primeira vez que uma função é chamada e, em seguida, usassem uma implementação que seja mais apropriada para aquela CPU.

Veja [`cpu_demo.c`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/cpu_demo.c):```c
void print_cpu_info() __attribute__((ifunc ("resolve_cpu_info")));
void print_avx2() { printf("AVX2 is present.\n"); }
void print_nope() { printf("AVX2 is missing.\n"); }

static void* resolve_cpu_info(void) {
    __builtin_cpu_init();

	if (__builtin_cpu_supports("avx2")) {
		return print_avx2;
	} else {
		return print_nope;
	}
}

int main() {
	print_cpu_info();
	return 0;
}

Este programa mostra o uso mais comum do IFUNC: ele pergunta à CPU se ela suporta ou não certas características, e fornece uma implementação diferente de uma função dependendo de quais características são suportadas. Neste caso, nossa função print_cpu_info acabará imprimindo "AVX2 está presente" ou "AVX2 está ausente" dependendo de quão antiga é sua CPU.

Sondando o Ambiente do Processo

Embora o IFUNC seja destinado a sondar capacidades da CPU, nada impede você de executar código mais complicado em seus resolvedores. Por exemplo, tty_demo.c mostra como você pode carregar uma implementação de função diferente dependendo se STDOUT é um arquivo ou um terminal:```c // Print Green text to the Terminal void print_to_tty(const char *message) { const char *green_start = "\033[32m"; const char *color_reset = "\033[0m"; printf("%sTTY: %s%s\n", green_start, message, color_reset); }

// Print plain text to a file void print_to_file(const char *message) { printf("FILE: %s\n", message); }

void print_message(const char *message)
attribute((ifunc("resolve_print_function")));

void (*resolve_print_function(void))(const char *) { struct termios term;

root@kitploit:~
// Ask the kernel whether stdout is a file or a tty
int result = ioctl(STDOUT_FILENO, TCGETS, &term);
if (result == 0) {
    // stdout is a terminal
    return print_to_tty;
} else {
    // stdout is not a terminal
    return print_to_file;
}

}

int main() { print_message("Hello, World!"); return 0; }

root@kitploit:~
Este não é realmente o uso pretendido do IFUNC, mas mostra o que é possível: você pode executar código arbitrário antes do `main` em qualquer programa que use um IFUNC que você declarou.





## IFUNC é Provavelmente uma Má Ideia
![](https://assets.kitploit.com/production/public/readmes/31477/6d420d0d1b4f4c49a3ba8a4b2103d7f79d284c9d8fbda4449e6e6d0afa5b3cfa.png)

O IFUNC GNU é difícil de implementar, difícil de usar corretamente e (como uma suposta ferramenta de desempenho) não é muito mais rápido que alternativas. Como vimos com CVE-2024-3094, também é uma ferramenta muito poderosa para ataques à cadeia de suprimentos de software.

O IFUNC é usado extensivamente na GNU C Library, e isso provavelmente é aceitável. Essas são as pessoas para quem foi originalmente desenvolvido, e elas estão intimamente ligadas às equipes de compilador e linker que realmente implementam o IFUNC. Elas estão na melhor posição para entender os compromissos, e há muitas funções libc que se beneficiam de implementações específicas de CPU. Acredito que devemos considerar o IFUNC como uma interface interna para a glibc e evitar seu uso em outras aplicações.



### É Muito Confuso para Usar com Segurança
O ifunc é totalmente difícil de usar. Há muitos [casos extremos][nagy], e a [documentação oficial][gnu-cfa] é [escassa][sourceware]. Isso dá aos usuários a ideia enganosa de que adotar ifunc é simples.

Mesmo vários anos após o ifunc se tornar disponível, a interface anunciada [não funcionava][agner]. Desenvolvedores do GCC chamaram isso de [um erro][odonell] e consideraram adicionar avisos para compensar a fragilidade do IFUNC:

> As soluções da glibc necessárias para tornar o IFUNC robusto não estão em vigor, portanto devemos fazer o que pudermos para alertar os usuários de que ele pode quebrar.

Não é apenas o IFUNC. O Apple Mach-O tem um recurso semelhante chamado `.symbol_resolver` que eles ["se arrependem de ter adicionado"][rjmccall].



### Isso Compromete o RELRO
Ao permitir que código arbitrário execute enquanto a Tabela de Deslocamento Global ainda é gravável, as proteções fornecidas pelo [RELRO](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/dynamic_linking.md#relro) se tornam [irrelevantes][binarly-io].

Isso é importante notar, porque o RELRO se apresenta como uma forma de proteger a integridade de símbolos carregados dinamicamente. Do ponto de vista do usuário (você, como usuário do compilador e do linker), isso viola o [Princípio do Menor Espanto][pola]: nenhuma pessoa razoável esperaria que *carregar uma biblioteca dinâmica* comprometesse um recurso de segurança projetado para *proteger bibliotecas dinâmicas*.

![](https://assets.kitploit.com/production/public/readmes/31477/ad252f1cb2937e3f8b168ece1e3f15455dcb0d7647b8715dff7435f3babc0e1c.png)



### Nem Sempre é Necessário
Existem várias outras maneiras de lidar com essa situação. Cada uma tem compromissos diferentes, mas todas são muito mais simples que o IFUNC. Todas são mais portáveis que o IFUNC, mais fáceis de entender e mais difíceis de explorar.

> "Ifunc é apenas uma maneira totalmente estúpida de fazer seleção de código microarquitetônico específico em tempo de execução."
>
> -- [Rich Felker](https://hachyderm.io/@dalias/112952237145378821),
> mantenedor do [musl](https://musl.libc.org).


#### Ponteiros de Função Globais
O IFUNC é atraente porque permite que os desenvolvedores expressem a seleção de funções *declarativamente* em vez de *imperativamente*. Mas fazer isso de forma imperativa não é realmente tão difícil. Considere [`static_pointer.c`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/static_pointer.c), que resolve um ponteiro de função global em tempo de execução:```c
static int (*triple)(int) = 0;
int triple_sse42(int n) { return 3 * n; }
int triple_plain(int n) { return n + n + n; }

void print_fifteen() {
	int fifteen = triple(5);
	printf("%d\n", fifteen);
}

int main() {
	__builtin_cpu_init();
	if (__builtin_cpu_supports("sse4.2")) {
		triple = triple_sse42;
	} else {
		triple = triple_plain;
	}
	
	print_fifteen();
	return 0;
}

Isso é realmente tão ruim que precisamos de truques especiais no linker apenas para evitar?

Uma desvantagem desta abordagem é que o ponteiro de função triple é gravável em tempo de execução, enquanto IFUNC+RELRO garantiria que os endereços ifunc no GOT sejam imutáveis uma vez resolvidos.

No entanto, com um pouco mais de trabalho, poderíamos usar [mprotect(2)][mprotect] para marcar tais ponteiros como somente leitura.

Modificando LD_PRELOAD

Se você sabe quais recursos de CPU seu código precisa, e você tem uma cópia separada de sua biblioteca dinâmica para cada caso, então você poderia realizar a mesma coisa especificando a biblioteca correta com $LD_PRELOAD da seguinte forma:```bash #!/bin/bash if (cat /proc/cpuinfo | grep flags | grep avx2 > /dev/null); then LD_PRELOAD=./myfunc_avx2.so ./my_app else LD_PRELOAD=./myfunc_normal.so ./my_app fi

root@kitploit:~
(Se você não está familiarizado com `LD_PRELOAD`, confira o ["Um Tutorial Simples de `LD_PRELOAD`"][catonmat] do catonmat.)



#### Binários Separados por Combinação de Recursos
Quantas combinações únicas de recursos de CPU você realmente precisa suportar?
Quantas até mesmo existem?

À primeira vista, isso parece uma explosão combinatória. Existem
dezenas de diferentes extensões de aritmética vetorial, virtualização e segurança
para a ISA amd64. Mas esses recursos não ocorrem
independentemente no mundo real. Por exemplo, nenhuma CPU que possui AVX-512 não possui
SSE4.2 ou AES-NI.

Saber quais recursos de CPU sua aplicação precisa, e
quais deles ocorrem juntos em chips reais, pode ajudá-lo a determinar
quantos binários distintos você teria que distribuir. Pode não ser tantos quanto
você imagina. A maioria dos gerenciadores de pacotes permite que você execute scripts no momento da
instalação; você pode distribuir múltiplos binários em um único arquivo rpm ou deb e usar
lógica de instalação para escolher o melhor para a CPU do host.



### Não é Muito Mais Rápido que Alternativas

> O que tem sido óbvio para mim por muito tempo é que, mesmo que houvesse
> uma vantagem de desempenho do ifunc, isso só poderia acontecer quando toda a
> chamada de função é tão curta que a sobrecarga da chamada pode ser uma
> parte significativa do tempo total.
>
> -- [Rich Felker](https://hachyderm.io/@dalias/113074264762553873),
> mantenedor do [musl](https://musl.libc.org).

Considerando que a justificativa usual para ifunc é relacionada ao desempenho, eu
quis ver quanta sobrecarga *o próprio ifunc* causa. Afinal, qualquer
função que vale a pena otimizar provavelmente é chamada com frequência, então a sobrecarga
da invocação da função vale a pena ser reconhecida.

Para descobrir isso, projetei um experimento que chamaria uma
função *resolvida dinamicamente* repetidamente em um loop apertado.
Dê uma olhada em [`speed_demo/ifunc`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/speed_demo/ifunc/main.c) e
[`speed_demo/pointer`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/speed_demo/pointer/main.c). Esses programas
ambos fazem o mesmo trabalho (incrementar um contador estático), mas as
funções incrementadoras são resolvidas de maneiras diferentes: o primeiro
usa GNU IFUNC, e o segundo depende de simples ponteiros de função antigos.

Aqui está a lógica geral:

1. Chame uma função resolvedora para determinar qual incrementador usar.
1. Registre essa resposta em algum lugar (no GOT, ou como um ponteiro de função).
1. Chame esta função incrementadora alguns bilhões de vezes para obter uma estimativa
   do seu custo.

Como controle, também existe
[`speed_demo/fixed`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/speed_demo/fixed/main.c) que faz o mesmo
trabalho de incrementador, mas sem funções resolvidas dinamicamente. Isso
pode ser usado para ajudar a estimar que parte do tempo de execução é dedicada
à invocação da função versus que parte é apenas adição.

O alvo do Makefile `rigorous_speed_demo` faz várias execuções de cada um desses
programas e produz algumas estatísticas simples sobre seu desempenho. Esses números naturalmente mudarão com base no seu hardware,
mas o teste `fixed` deve servir como uma linha de base para comparação.

| *Resultados* | BAIXO | ALTO | MÉD   |
|-----------|------|------|-------|
| fixo      | 2.93 | 4.20 | 3.477 |
| ifunc     | 9.50 | 10.56| 9.986 |
| ponteiro  | 6.23 | 7.44 | 6.791 |

O que vemos aqui é que o ifunc tem uma sobrecarga não insignificante em comparação
com o uso de um simples ponteiro de função antigo. Em média, no meu hardware,
leva cerca de duas vezes mais tempo para chamar uma função ifunc 2 bilhões de vezes do que
para invocar um ponteiro de função 2 bilhões de vezes.

Isso importa na vida real? Absolutamente não. Funções que valem a pena otimizar
são muito mais caras do que as funções "incrementar em um" que estamos
analisando aqui. É interessante apenas porque o GNU IFUNC alega ser
um benefício para o desempenho, mas parece incorrer em mais custo do que
ponteiros de função.


#### Desempenho de Outras Técnicas
Existem outras técnicas que são mais lentas que o ifunc. Dê uma olhada no
`super_rigorous_speed_demo`, que traz dois outros experimentos para o jogo:
[`speed_demo/upfront`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/speed_demo/upfront/main.c) e
[`speed_demo/always`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/speed_demo/always/main.c).

`speed_demo/upfront` se comporta de forma semelhante a `speed_demo/pointer`,
exceto que armazena os resultados das verificações de recursos da CPU em variáveis
globais em vez de manter um ponteiro de função. Isso ainda
requer que uma função "resolvedora" seja executada primeiro para determinar qual
implementação será usada, com base no valor dessas variáveis globais.
Esta técnica acaba sendo mais lenta que o ifunc, mas também é mais segura
do que armazenar ponteiros de função: enquanto ponteiros de função podem ser definidos para
valores arbitrários, flags booleanas não podem. Portanto, um invasor capaz de modificar
essas variáveis pode tornar o programa *mais lento*, mas não pode fazer o programa se comportar
*de forma diferente*.

`speed_demo/always` é projetado para ser a técnica mais lenta -- ele verifica
todos os recursos de CPU necessários toda vez que uma implementação é
necessária e escolhe uma em tempo real. Curiosamente, esta técnica não é
significativamente mais lenta do que qualquer outra. É apenas marginalmente mais lenta
que o ifunc no caso em que temos apenas um único recurso de CPU para verificar. 

| TESTE   | BAIXO | ALTO  | MÉD      |
|---------|------|-------|----------|
| fixo    | 5.02 | 5.70  | 5.37     |
| ponteiro| 6.40 | 7.02  | 6.66     |
| ifunc   | 8.56 | 11.11 | 9.64     |
| antecipado | 9.24 | 9.41  | 9.33333  |
| sempre  | 10.07| 10.56 | 10.2333  |




## Conclusão
O GNU IFUNC é um recurso nicho do gcc/ld.so que poucas pessoas conheciam
antes de ser usado no CVE-2024-3094. Ele tem armadilhas não óbvias e
documentação insuficiente. Ao permitir que o vinculador execute código arbitrário
antes do `main`, antes que partes críticas da imagem do processo tenham sido
inicializadas e protegidas, ele prejudica uma das suposições mais básicas
da programação: que o mero ato de carregar uma biblioteca não irá
inerentemente *alterar* seu programa.

Os benefícios de desempenho do IFUNC são reais, mas não significativamente melhores
que alternativas. A simplicidade de implantar um único binário que é
otimizado para múltiplas CPUs é muito atraente, mas pode ser
alcançada com técnicas mais simples (como ponteiros de função).

Acredito que o IFUNC deveria ser desabilitado por padrão no gcc. Ativá-lo deveria
exigir uma flag assustadora, como `--enable-cve-2024-3094`. Qualquer um
usando-o fora da libc deveria ser obrigado a fornecer um argumento rigoroso e
bem pesquisado de que nenhuma solução alternativa é apropriada.

![Sim, todas as bibliotecas compartilhadas](https://assets.kitploit.com/production/public/readmes/31477/039631e9f0441a38341d4f2299c0666f63a731c02cb2239257afd7613455461c.png)

<!-- REFERENCES -->
[aes-ni]: https://en.wikipedia.org/wiki/AES_instruction_set
[agner]: https://www.agner.org/optimize/blog/read.php?i=167
[biebl]: https://salsa.debian.org/ssh-team/openssh/-/commit/818791ef8edf087481bd49eb32335c8d7e1953d6
[binarly-io]: https://github.com/binarly-io/binary-risk-intelligence/tree/master/xz-backdoor
[catonmat]: https://catonmat.net/simple-ld-preload-tutorial
[conway]: https://en.wikipedia.org/wiki/Conway%27s_law
[djmdjm]: https://github.com/openssh/openssh-portable/pull/251#issuecomment-2027935208
[fr0gger]: https://infosec.exchange/@fr0gger/112189232773640259
[freund]: https://www.openwall.com/lists/oss-security/2024/03/29/4
[gnu-cfa]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-ifunc-function-attribute
[goodin1]: https://arstechnica.com/security/2024/04/what-we-know-about-the-xz-utils-backdoor-that-almost-infected-the-world/
[hn]: https://news.ycombinator.com/item?id=48056749
[jasoncc]: https://jasoncc.github.io/gnu_gcc_glibc/gnu-ifunc.html#relocations-and-pic
[JiaT75]: https://github.com/tukaani-project/xz/commit/cf44e4b7f5dfdbf8c78aef377c10f71e274f63c0
[keith]: https://keith.github.io/xcode-man-pages/ssh-add.1.html#apple-use-keychain
[mindrot]: https://anongit.mindrot.org/openssh.git
[mprotect]: https://www.man7.org/linux/man-pages/man2/mprotect.2.html
[musl]: https://musl.libc.org
[nagy]: https://sourceware.org/legacy-ml/libc-alpha/2015-11/msg00108.html
[nvd]: https://nvd.nist.gov/vuln/detail/CVE-2024-3094
[odonell]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70082#c0
[OpenSSH9.8p1]: https://www.openssh.com/releasenotes.html#9.8p1
[openssh-unix-dev]: https://marc.info/?l=openssh-unix-dev&m=171288895109872&w=2
[pola]: https://en.wikipedia.org/wiki/Principle_of_least_astonishment
[rjmccall]: https://reviews.llvm.org/D139163#3993795
[schmidt]: https://bugzilla.redhat.com/show_bug.cgi?id=1381997#c4
[sourceware]: https://sourceware.org/glibc/wiki/GNU_IFUNC
[thesamesam]: https://gist.github.com/thesamesam/223949d5a074ebc3dce9ee78baad9e27#design
Baixar ferramenta