Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
ifuncd-up — GNU IFUNC è il vero colpevole dietro CVE-2024-3094 | Kitploit
Strumenti/GitHubGitHub/robertdfrench/ifuncd-up
Analisi delle VulnerabilitàAnalisi Dinamica del Codice (DAST)ExploitReverse EngineeringAnalisi di BinariSicurezza della Supply ChainPaper e RicercaApprendimento e Formazione
GitHubrobertdfrench/ifuncd-up

ifuncd-up

GNU IFUNC è il vero colpevole dietro CVE-2024-3094

Vedi Repository
6013 mesi faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi
Sito web

In Response to Hacker News

Vedo che voi burloni su [il sito arancione][hn] mi state rendendo la vita difficile. Farò alcune risposte scelte qui sotto, ma prima offro una sfida: manderò $500 di tasca mia mia alla prima persona che dimostrerà questo attacco senza ifunc. Sono genuinamente interessato e disposto a pagare per l'illuminazione. Forkate questo repo e inviate una PR con il vostro PoC funzionante; vi chiederò privatamente il vostro indirizzo postale se vincete. Ora le risposte:

Stai abbaiando all'albero sbagliato.

Ragazzo, io vivo nell'albero sbagliato, posso abbaiare a chi mi pare.

Non era essenziale per l'exploit,

Tu non sei essenziale per l'exploit!

C'è sempre selinux se vogliamo aggiungere protezione contro l'esecuzione di codice arbitrario come root.

Una volta caricato, questo attacco non aveva bisogno di attraversare ulteriori limiti di syscall. Quindi sì, avremmo potuto limitare una sessione root "bonus", ma avremmo comunque avuto ospiti non invitati sulla macchina!

Che cos'è, il compleanno di Bilbo?? Nessun ingresso se non per affari di festa!!

  1. IFUNC non è certo l'unico modo per eseguire codice prima di main.

Ma è un modo inutile per eseguire codice prima che la protezione della memoria sia configurata

  1. L'alternativa che presentano è probabilmente meno sicura perché il puntatore a funzione rimarrà scrivibile per tutta la vita del processo,

Possiamo improvvisare con mprotect! Vedi l'ultima frase sopra la sottosezione Modifica di LD_PRELOAD.

Sì, questo blog è fuorviante.

Scusate, questo blog era senza guida. Ho fatto tutte queste marachelle da solo! Nessuno mi ha ingannato facendomi diventare così stupido.

IFUNC dovrebbe essere implementato dal software [del cliente] stesso,

@CountWSS 💯 assolutamente sì

una serie di palesi fallimenti di processo dal maintainer di Github fino a ...

Questo è l'unico punto a cui risponderò seriamente:

Penso che sia straordinariamente ingiusto nei confronti del maintainer di xz-utils e piuttosto pericoloso per la comunità pensare a questo come iniziato con un suo errore. È iniziato con il fatto che a nessuno importava nulla di aiutare a mantenere questo progetto. L'attaccante dipendeva da ifunc come vulnerabilità tecnica e dalla nostra negligenza collettiva verso xz-utils come vulnerabilità sociale. Penso che sia vergognoso vedere le azioni del signor Collin come qualcosa di diverso da una dedizione eroica, durata anni, al servizio della comunità.

Inoltre Bruce Schneier è d'accordo con me quindi... mi dispiace per te, la tua argomentazione è spacciata.

Il linguaggio potrebbe essere stato più duro del necessario

Non crederete a quanto i miei amici mi abbiano fatto annacquare tutto questo prima.

Le distribuzioni Linux non dovrebbero avere un'opinione così alta di sé da aspettarsi che OpenBSD si conformi e si adatti al loro caos

@debazel!!! Mi piace.

Che enorme stronzata.

Okay, quella parte è accurata.

IFUNC'd up

Perché dovreste smettere di incolpare xz-utils per [CVE-2024-3094][nvd]. Inoltre guardate il mio Talk ETSA!

Penso che IFUNC'd up

CVE-2024-3094, più comunemente nota come "La backdoor di xz-utils", è stata una sfiorata catastrofe per la cybersecurity globale. Se questo attacco non fosse stato scoperto all'ultimo momento da [Andres Freund][freund], la maggior parte dei server SSH del pianeta avrebbe iniziato a concedere accesso root ai responsabili di questo attacco.

Sfortunatamente, troppe analisi si sono concentrate su come il [codice malevolo][JiaT75] sia entrato nel repo di xz-utils. Invece, vorrei sostenere che due decisioni progettuali di lunga data in software open source critico siano ciò che ha reso possibile questo attacco: il [collegamento di OpenSSH a SystemD][biebl] e l'esistenza di [GNU IFUNC][sourceware].

Prima di iniziare: Gran parte di questa discussione riguarda le complessità del linking dinamico su Linux. Se avete bisogno di un ripasso, consultate dynamic_linking.md.

Rapido riepilogo di CVE-2024-3094

Ci sono tantissimi buoni articoli che delineano i dettagli di alto livello della backdoor di xz-utils, come [Cosa sappiamo della backdoor in xz Utils che ha quasi infettato il mondo][goodin1] di Dan Goodin e il gist [FAQ sulla backdoor di xz-utils (CVE-2024-3094)][thesamesam] di Sam James. Non abbiamo bisogno di rispolverare tutto qui, quindi ai fini di questo articolo, ecco un riepilogo molto approssimativo:

  • Alcune distro Linux modificano OpenSSH per renderlo dipendente da SystemD
  • SystemD dipende da xz-utils, che usa GNU IFUNC
  • Ergo, xz-utils finisce nello spazio degli indirizzi di OpenSSH
  • Questo permette a ifunc di modificare il codice nel server 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:~
## Perché le distribuzioni Linux modificano OpenSSH?
La risposta breve è che devono farlo. OpenSSH è sviluppato dalla
comunità OpenBSD, per la comunità OpenBSD, e non gliene importa un
fico secco di Linux.  Il progetto [Portable OpenSSH][mindrot] è una
raccolta di patch best-effort che sostituiscono i componenti
specifici di OpenBSD con componenti POSIX generici, e codice
specifico della piattaforma dove applicabile. La filiera software per SSH finisce per avere un aspetto
simile a questo in pratica:```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

La versione di OpenSSH di OpenBSD è a monte rispetto a tutto il resto, e la maggior parte dei miglioramenti provengono dalla community di OpenBSD. Queste modifiche fluiscono a valle verso il progetto Portable OpenSSH, che cerca di reimplementare le nuove funzionalità in modi che non siano specifici di OpenBSD. È questo che consente a SSH di funzionare su piattaforme come Linux, macOS, FreeBSD e persino Windows.

Ma non finisce qui. Alcuni sistemi operativi applicano ulteriori personalizzazioni oltre a quelle fornite da Portable OpenSSH. Ad esempio, Apple aggiunge il flag [--apple-use-keychain][keith] a ssh-add per favorirne l'integrazione con il gestore di password di macOS.

Nel caso di CVE-2024-3094, Fedora e Debian hanno mantenuto le proprie [patch SystemD][biebl] per i loro fork di OpenSSH, al fine di correggere una [race condition relativa ai riavvii di sshd][schmidt]. Quindi la reale supply chain di SSH ha iniziato ad avere questo aspetto:```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:~
Queste patch non sono mai state integrate in Portable OpenSSH, perché i
manutentori di Portable OpenSSH erano ["non interessati ad aggiungere una
dipendenza da libsystemd"][djmdjm]. E non sono mai entrate nell'OpenSSH upstream, perché
OpenBSD non ha alcuna necessità di supportare SystemD.

### Preoccupazioni sulla "Separation of Concerns"
Questo sembra abbastanza innocuo, ma è un esempio di un problema molto più ampio
nell'open source, in particolare in Linux: componenti critici del
sistema operativo sono sviluppati da persone che non si conoscono tra loro e
non si parlano. 

* I manutentori che hanno patchato OpenSSH per SystemD sapevano (o gli importava) che
  libsystemd dipende da xz-utils?
* I manutentori di SystemD sapevano (o gli importava) che xz-utils aveva iniziato a usare
  ifunc?
* I manutentori di OpenSSH sapevano (o gli importava) che ifunc esistesse? Di certo
  non esiste su OpenBSD.

In un certo senso, questa rottura della comunicazione è una caratteristica dell'open
source: posso adattare il tuo lavoro alle mie esigenze senza doverti disturbare
per questo. Ma può anche portare a un grado di indirezione che impedisce
che i presupposti progettuali critici (come un tradizionale processo
di collegamento dinamico) vengano rispettati.

Il corollario ovvio della [legge di Conway][conway] è che se stai
distribuendo il tuo organigramma, stai anche distribuendo i bug che vivono nelle
fessure del tuo organigramma. Nessuna singola persona o team ha davvero commesso un errore
qui, ma col senno di poi è chiaro che gli attaccanti
percepivano che la mano sinistra di Debian/Fedora SSH non sapesse cosa
stava facendo la mano destra di xz-utils.



## Cosa *dovrebbe* fare GNU IFUNC?
Ti permette di determinare, a runtime, quale versione di una funzione
vuoi usare. Lo fa dandoti l'opportunità di eseguire
**codice arbitrario** per influenzare il modo in cui il linker risolve i simboli.

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



### Rilevamento delle funzionalità della CPU
Supponiamo di avere un'applicazione che deve essere eseguita su un'ampia varietà di x86
CPU.  A seconda delle caratteristiche specifiche della CPU corrente, potresti
preferire usare algoritmi diversi per lo stesso compito. L'idea originale
dietro IFUNC era di consentire ai programmi di verificare le funzionalità della CPU la prima
volta che una funzione viene chiamata, e successivamente usare un'implementazione che
sarà la più adatta per quella CPU.

Dai un'occhiata a [`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;
}

Questo programma mostra l'uso più comune di IFUNC: chiede alla CPU se supporta o meno determinate funzionalità e fornisce una diversa implementazione di una funzione a seconda delle funzionalità supportate. In questo caso, la nostra funzione print_cpu_info stamperà "AVX2 is present" o "AVX2 is missing" a seconda di quanto sia antiquata la tua CPU.

Sondare l'ambiente di processo

Sebbene IFUNC sia pensato per sondare le capacità della CPU, nulla ti impedisce di eseguire codice più complicato nei tuoi resolver. Ad esempio, tty_demo.c mostra come caricare una diversa implementazione di una funzione a seconda che STDOUT sia un file o un terminale:```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:~
This is not really the intended use of IFUNC, but it shows what's
possible: you can run arbitrary code before `main` in any program that
uses an IFUNC that you've declared.





## IFUNC è probabilmente una pessima idea
![](https://assets.kitploit.com/production/public/readmes/31477/6d420d0d1b4f4c49a3ba8a4b2103d7f79d284c9d8fbda4449e6e6d0afa5b3cfa.png)

GNU IFUNC è difficile da implementare, difficile da usare correttamente e (come
presunto strumento di performance) non è molto più veloce delle alternative. Come
abbiamo visto con CVE-2024-3094, è anche uno strumento molto potente per gli
attacchi alla supply chain del software.

IFUNC è ampiamente utilizzato all'interno della GNU C Library, e questo
probabilmente va bene. Quelle sono le persone per cui è stato originariamente
sviluppato e sono strettamente collegate ai team del compilatore e del linker
che implementano realmente IFUNC. Sono nella posizione migliore per comprendere i
compromessi e ci sono moltissime funzioni libc che traggono vantaggio da
implementazioni specifiche per CPU. Credo che dovremmo considerare IFUNC come
un'interfaccia interna per glibc ed evitarne l'uso in altre applicazioni.



### È troppo confuso da usare in sicurezza
ifunc è assolutamente troppo difficile da usare. Ci sono troppi [casi
limite][nagy] e la [documentazione ufficiale][gnu-cfa] è
[scarsa][sourceware]. Questo dà agli utenti l'idea fuorviante che adottare
ifunc sia semplice.

Anche diversi anni dopo che ifunc è diventato disponibile, l'interfaccia
pubblicizzata [non funzionava][agner]. Gli sviluppatori di GCC l'hanno definito
[un errore][odonell] e hanno preso in considerazione l'aggiunta di avvisi per
compensare la fragilità di IFUNC:

> Le soluzioni glibc necessarie per rendere robusto IFUNC non sono in atto,
> quindi dovremmo fare il possibile per avvisare gli utenti che potrebbe rompersi.

E non è neanche solo IFUNC. Apple Mach-O ha una funzionalità simile chiamata
`.symbol_resolver` che ["rimpiangono di aver aggiunto"][rjmccall].



### Compromette RELRO
Permettendo l'esecuzione di codice arbitrario mentre la Global Offset Table è
ancora scrivibile, le protezioni offerte da [RELRO](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/dynamic_linking.md#relro)
sono [rese irrilevanti][binarly-io]. 

Questo è importante da notare, perché RELRO si presenta come un modo per
proteggere l'integrità dei simboli caricati dinamicamente. Dal punto di vista
dell'utente (tu, come utente del compilatore e del linker), questo viola il
[Principio del minimo stupore][pola]: nessuna persona ragionevole si
aspetterebbe che *il caricamento di una libreria dinamica* comprometta una
funzionalità di sicurezza progettata per *proteggere le librerie dinamiche*.

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



### Non è sempre necessario
Ci sono molti altri modi per gestire questa situazione. Ognuno di essi ha
diversi compromessi, ma sono tutti molto più semplici di IFUNC. Tutti questi
sono più portabili di IFUNC, più facili da capire e più difficili da sfruttare.

> "Ifunc è semplicemente un modo assolutamente stupido di fare la selezione runtime di codice
> specifico per microarchitettura."
>
> -- [Rich Felker](https://hachyderm.io/@dalias/112952237145378821),
> manutentore di [musl](https://musl.libc.org).


#### Puntatori a funzioni globali
IFUNC è interessante perché consente agli sviluppatori di esprimere la selezione
di funzioni *dichiarativamente* piuttosto che *imperativamente*. Ma farlo in
modo imperativo in realtà non è così difficile. Considera
[`static_pointer.c`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/static_pointer.c), che risolve un puntatore a funzione
globale a runtime:```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;
}

È davvero così grave che abbiamo bisogno di espedienti speciali nel linker solo per evitarlo?

Uno svantaggio di questo approccio è che il puntatore a funzione triple è scrivibile in fase di esecuzione, mentre IFUNC+RELRO garantirebbe che gli indirizzi ifunc nella GOT siano immutabili una volta risolti. Tuttavia, con un po' di lavoro extra, potremmo usare [mprotect(2)][mprotect] per marcare tali puntatori come di sola lettura.

Modifica di LD_PRELOAD

Se sai quali funzionalità della CPU richiede il tuo codice e disponi di una copia separata della tua libreria dinamica per ogni caso, potresti ottenere lo stesso risultato specificando la libreria giusta con $LD_PRELOAD in questo modo:```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 non hai familiarità con `LD_PRELOAD`, dai un'occhiata a ["A Simple
`LD_PRELOAD` Tutorial"][catonmat] di catonmat.)



#### Binari separati per combinazione di funzionalità
Quante combinazioni uniche di funzionalità della CPU devi davvero supportare?
Quante ne esistono?

In apparenza, sembra un'esplosione combinatoria. Esistono
dozzine di estensioni diverse all'ISA amd64 per l'aritmetica vettoriale,
la virtualizzazione e la sicurezza. Ma queste funzionalità non si
presentano indipendentemente nel mondo reale. Per esempio, nessuna CPU
che ha AVX-512 è priva di SSE4.2 o AES-NI.

Sapere quali funzionalità della CPU richiede la tua applicazione e
quali di esse si presentano insieme nei chip reali può aiutarti a
determinare quanti binari distinti dovresti distribuire. Potrebbero
non essere tanti quanto ti aspetteresti. La maggior parte dei gestori
di pacchetti consente di eseguire script al momento dell'installazione;
potresti distribuire più binari in un singolo file rpm o deb e usare una logica di installazione per scegliere il migliore per la CPU host.



### Non è molto più veloce delle alternative

> Quello che per me è ovvio da molto tempo è che, anche se ci fosse
> un vantaggio prestazionale per ifunc, potrebbe esserci solo quando
> l'intera chiamata di funzione è così breve che l'overhead della chiamata
> può essere una porzione significativa del tempo complessivo.
>
> -- [Rich Felker](https://hachyderm.io/@dalias/113074264762553873),
> manutentore di [musl](https://musl.libc.org).

Dato che la solita giustificazione per ifunc è legata alle prestazioni,
volevo vedere quanto overhead causi *ifunc stesso*. Dopotutto, qualsiasi
funzione degna di essere ottimizzata è probabilmente chiamata spesso,
quindi l'overhead dell'invocazione della funzione merita di essere riconosciuto.

Per capirlo, ho progettato un esperimento che chiama una
funzione *risolta dinamicamente* ripetutamente in un ciclo stretto.
Dai un'occhiata a [`speed_demo/ifunc`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/speed_demo/ifunc/main.c) e a
[`speed_demo/pointer`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/speed_demo/pointer/main.c).  Questi programmi
fanno entrambi lo stesso lavoro (incrementare un contatore statico), ma le
funzioni di incremento sono risolte in modi diversi: il primo
sfrutta GNU IFUNC, mentre il secondo si affida ai semplici puntatori a
funzione.

Ecco la logica generale:

1. Chiamare una funzione resolver per determinare quale incrementatore usare.
1. Registrare questa risposta da qualche parte (nel GOT, o come puntatore a funzione).
1. Chiamare questa funzione di incremento qualche miliardo di volte per ottenere una stima
   del suo costo.

Come controllo, c'è anche
[`speed_demo/fixed`](https://github.com/robertdfrench/ifuncd-up/blob/HEAD/code/speed_demo/fixed/main.c) che fa lo stesso
lavoro di incremento ma senza funzioni risolte dinamicamente. Questo
può essere usato per ottenere una stima utile di quale parte del tempo
di esecuzione è dedicata all'invocazione della funzione e quale parte è solo addizione.

Il target del Makefile `rigorous_speed_demo` esegue diverse prove di
ciascuno di questi programmi e produce alcune semplici statistiche sulle
loro prestazioni. Questi numeri cambieranno ovviamente in base
all'hardware, ma il test `fixed` dovrebbe servire come base di confronto.

| *Risultati* | LOW | HIGH | AVG   |
|-----------|------|------|-------|
| fixed     | 2.93 | 4.20 | 3.477 |
| ifunc     | 9.50 | 10.56| 9.986 |
| pointer   | 6.23 | 7.44 | 6.791 |

Quello che vediamo qui è che ifunc ha un overhead non trascurabile
rispetto all'uso di un semplice puntatore a funzione. In media, sul mio
hardware, chiamare una funzione ifunc 2 miliardi di volte richiede circa
il doppio del tempo rispetto a invocare un puntatore a funzione 2 miliardi di volte.

Ha importanza nella vita reale? Assolutamente no. Le funzioni che
meritano di essere ottimizzate sono molto più costose delle funzioni
"incrementa di uno" che stiamo analizzando qui. È interessante solo
perché GNU IFUNC sostiene di essere un vantaggio per le prestazioni,
eppure sembra comportare più costi dei puntatori a funzione.


#### Prestazioni di altre tecniche
Esistono altre tecniche più lente di ifunc. Dai un'occhiata a
`super_rigorous_speed_demo`, che mette in gioco altri due esperimenti:
[`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` si comporta in modo simile a `speed_demo/pointer`,
tranne per il fatto che memorizza i risultati dei controlli delle
funzionalità della CPU in variabili globali invece di tenere traccia di
un puntatore a funzione. Questo richiede comunque che una funzione
"resolver" venga eseguita per prima per determinare quale implementazione
usare, in base al valore di queste variabili globali. Questa tecnica
risulta essere più lenta di ifunc, ma è anche più sicura della
memorizzazione di puntatori a funzione: mentre i puntatori a funzione possono
essere impostati su valori arbitrari, i flag booleani non possono. Quindi un attaccante
in grado di modificare queste variabili può rendere il programma *più lento*, ma non può far sì che il programma si comporti *diversamente*.

`speed_demo/always` è progettato per essere la tecnica più lenta --
controlla tutte le funzionalità della CPU necessarie ogni volta che
serve un'implementazione e ne sceglie una al volo. Curiosamente, questa
tecnica non è significativamente più lenta delle altre. È solo marginalmente più lenta
di ifunc nel caso in cui si debba controllare una sola funzionalità della CPU. 

| TEST    | LOW  | HIGH  | AVG     |
|---------|------|-------|---------|
| fixed   | 5.02 | 5.70  | 5.37    |
| pointer | 6.40 | 7.02  | 6.66    |
| ifunc   | 8.56 | 11.11 | 9.64    |
| upfront | 9.24 | 9.41  | 9.33333 |
| always  | 10.07| 10.56 | 10.2333 |




## Conclusione
GNU IFUNC è una funzionalità di nicchia di gcc/ld.so di cui poche persone
erano a conoscenza prima che venisse usata in CVE-2024-3094. Ha insidie
non ovvie e documentazione insufficiente. Lasciando che il linker esegua
codice arbitrario prima di `main`, prima che parti critiche dell'immagine di
processo siano state inizializzate e protette, mina uno dei presupposti
più basilari della programmazione: che il semplice atto di caricare una
libreria non *cambierà* intrinsecamente il tuo programma.

I benefici prestazionali di IFUNC sono reali, ma non significativamente
migliori delle alternative. La semplicità di distribuire un singolo binario
ottimizzato per più CPU è molto allettante, ma può essere ottenuta
con tecniche più semplici (come i puntatori a funzione).

Credo che IFUNC dovrebbe essere disabilitato per impostazione predefinita in gcc.
Abilitarlo dovrebbe richiedere un flag dall'aspetto spaventoso, come `--enable-cve-2024-3094`.
Chiunque lo usi al di fuori di libc dovrebbe essere tenuto a fornire un argomento rigoroso
e ben studiato sul perché nessuna soluzione alternativa sia appropriata.

![Sì, tutte le librerie condivise](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
Scarica lo strumento