Fate attenzione alle vulnerabilità, workarounds pericolosi. Parte 1: FragmentSmack/SegmentSmack

Fate attenzione alle vulnerabilità, workarounds pericolosi. Parte 1: FragmentSmack/SegmentSmack

Ciao a tutti! Mi chiamo Dmitry Samsonov e lavoro come amministratore di sistema senior in «Odnoklassniki». Abbiamo oltre 7.000 server fisici, 11.000 container nel nostro cloud e 200 applicazioni che, in varie configurazioni, formano 700 diversi cluster. La grande maggioranza dei server opera con CentOS 7.
Il 14 agosto 2018 sono state pubblicate informazioni su una vulnerabilità chiamata FragmentSmack
(CVE-2018-5391) e SegmentSmack (CVE-2018-5390). Si tratta di vulnerabilità a livello di rete con un punteggio piuttosto elevato (7.5), che possono portare a un'interruzione del servizio (DoS) a causa dell'esaurimento delle risorse (CPU). La patch nel kernel per FragmentSmack non era ancora stata proposta in quel momento, inoltre, è stata rilasciata molto dopo la pubblicazione delle informazioni sulla vulnerabilità. Per risolvere SegmentSmack era consigliato aggiornare il kernel. Il pacchetto di aggiornamento è stato rilasciato lo stesso giorno, restava solo da installarlo.
No, non siamo affatto contrari all'aggiornamento del kernel! Tuttavia, ci sono delle peculiarità…

Come aggiorniamo il kernel in produzione

In realtà, non c'è niente di complicato:

  1. Scaricare i pacchetti;
  2. Installarli su un certo numero di server (inclusi i server che ospitano il nostro cloud);
  3. Assicurati che nulla si sia rotto;
  4. Verifica che tutte le impostazioni predefinite del kernel siano state applicate senza errori;
  5. Aspetta alcuni giorni;
  6. Controlla le metriche dei server;
  7. Cambia il deployment dei nuovi server al nuovo kernel;
  8. Aggiorna tutti i server nei data center (uno alla volta, per ridurre l'impatto sugli utenti in caso di problemi);
  9. Riavvia tutti i server.

Ripeti per tutti i rami dei kernel che abbiamo. Attualmente sono:

  • Stock CentOS 7 3.10 - per la maggior parte dei server standard;
  • Vanilla 4.19 - per il nostro cloud one-cloud, perché abbiamo bisogno di BFQ, BBR, ecc.;
  • Elrepo kernel-ml 5.2 - per distribuzioni ad alta intensità di carico, perché il 4.19 in precedenza si comportava in modo instabile, ma le funzionalità sono le stesse.

Come avrete intuito, la parte più lunga del processo è il riavvio di migliaia di server. Poiché non tutte le vulnerabilità sono critiche per ogni server, riavviamo solo quelli che sono direttamente accessibili da Internet. Nel cloud, per non limitare la flessibilità, non vincoliamo i container accessibili esternamente a singoli server con un nuovo kernel, ma riavviamo tutti gli host senza eccezioni. Fortunatamente, la procedura è più semplice rispetto ai server tradizionali. Ad esempio, i container stateless possono semplicemente trasferirsi su un altro server durante il reboot.

Tuttavia, il lavoro è comunque considerevole e potrebbe richiedere diverse settimane, e in caso di eventuali problemi con la nuova versione, anche diversi mesi. I malintenzionati lo comprendono perfettamente, quindi è necessario un piano "B".

FragmentSmack/SegmentSmack. Workaround

Fortunatamente, per alcune vulnerabilità esiste questo piano "B", che viene chiamato Workaround. Di solito si tratta di modifiche alle impostazioni del kernel/applicazioni che consentono di ridurre al minimo il possibile impatto o di escludere completamente l'exploit delle vulnerabilità.

Nel caso di FragmentSmack/SegmentSmack è stato proposto questo Workaround:

«È possibile modificare i valori predefiniti di 4MB e 3MB in net.ipv4.ipfrag_high_thresh e net.ipv4.ipfrag_low_thresh (e i loro equivalenti per ipv6 net.ipv6.ipfrag_high_thresh e net.ipv6.ipfrag_low_thresh) a 256 kB e 192 kB rispettivamente o anche più bassi. I test mostrano una diminuzione da lieve a significativa dell'utilizzo della CPU durante l'attacco, a seconda dell'hardware, delle impostazioni e delle condizioni. Tuttavia, potrebbe esserci un certo impatto sulle prestazioni a causa di ipfrag_high_thresh=262144 bytes, poiché solo due frammenti da 64K possono contemporaneamente essere presenti nella coda per il riassemblaggio. Ad esempio, c'è il rischio che le applicazioni che gestiscono grandi pacchetti UDP possano avere malfunzionamenti.».

I parametri stessi nella documentazione del kernel sono descritti come:

ipfrag_high_thresh - INTERO LUNGO
    Memoria massima utilizzata per riunire i frammenti IP.

ipfrag_low_thresh - INTERO LUNGO
    Memoria massima utilizzata per riassemblare i frammenti IP prima che il kernel
    inizia a rimuovere le code di frammenti incompleti per liberare risorse.
    Il kernel continua ad accettare nuovi frammenti per la deframmentazione.

Non abbiamo servizi di produzione di grandi UDP. In LAN il traffico frammentato è assente, in WAN è presente, ma non significativo. Nulla preannuncia — possiamo applicare una soluzione temporanea!

FragmentSmack/SegmentSmack. La prima vittima

Il primo problema che abbiamo incontrato è stato che i contenitori cloud a volte applicavano le nuove impostazioni solo parzialmente (solo ipfrag_low_thresh), e in altre occasioni non le applicavano affatto — semplicemente si bloccavano all'avvio. Non siamo riusciti a riprodurre il problema in modo consistente (tutte le impostazioni venivano applicate senza alcuna difficoltà manualmente). Comprendere perché il contenitore si blocchi all'avvio non è così semplice: non sono stati riscontrati errori. Una cosa è certa: ripristinare le impostazioni risolve il problema di arresto dei contenitori.

Perché non è sufficiente applicare Sysctl sull'host? Il contenitore vive nel proprio Namespace di rete dedicato, quindi almeno parte dei parametri Sysctl di rete nel contenitore può differire da quella dell'host.

Come vengono applicate le impostazioni Sysctl nel contenitore? Poiché i contenitori sono non privilegiati, non è possibile modificare alcuna impostazione Sysctl accedendo al contenitore stesso — non ci sono diritti sufficienti. All'epoca, per l'avvio dei contenitori, il nostro cloud utilizzava Docker (adesso già Podman). I parametri del nuovo contenitore, comprese le impostazioni Sysctl necessarie, venivano passati a Docker tramite API.
Durante il processo di esplorazione delle versioni, è emerso che l'API Docker non restituiva tutti gli errori (almeno, nella versione 1.10). Quando abbiamo provato a lanciare un container tramite “docker run”, alla fine abbiamo visto qualcosa:

write /proc/sys/net/ipv4/ipfrag_high_thresh: argomento non valido docker: Risposta di errore dal demone: Impossibile avviare il container : [9] Errore di sistema: impossibile sincronizzarsi con il processo del container.

Il valore del parametro non è valido. Ma perché? E perché non è valido solo a volte? È emerso che Docker non garantisce l'ordine di applicazione dei parametri Sysctl (l'ultima versione controllata è 1.13.1), quindi a volte ipfrag_high_thresh tentava di impostarsi a 256K, quando ipfrag_low_thresh era ancora 3M, cioè il limite superiore era inferiore a quello inferiore, il che portava all'errore.

A quel tempo stavamo già utilizzando un proprio meccanismo di riconfigurazione del container dopo l'avvio (congelamento del container tramite cgroup freezer e l'esecuzione di comandi nel namespace del container tramite ip netns), e abbiamo aggiunto anche l'impostazione dei parametri Sysctl in questa parte. Il problema è stato risolto.

FragmentSmack/SegmentSmack. Il primo colpo 2

Non appena ci siamo sistemati con l'applicazione del Workaround nel cloud, hanno cominciato ad arrivare le prime rare segnalazioni da parte degli utenti. Erano già passate alcune settimane dall'inizio dell'applicazione del Workaround sui primi server. Le indagini iniziali hanno rivelato che le segnalazioni riguardavano servizi specifici e non tutti i server di quei servizi. Il problema ha ripreso un carattere estremamente indefinito.

Innanzitutto, abbiamo provato a ripristinare le impostazioni di Sysctl, ma non ha avuto alcun effetto. Diverse manipolazioni delle impostazioni del server e dell'applicazione non hanno portato risultati. Ciò che ha aiutato è stato un riavvio. Il riavvio su Linux è tanto innaturale quanto era normale per Windows in passato. Tuttavia, ha funzionato e abbiamo attribuito tutto a un "bug nel kernel" causato dall'applicazione delle nuove impostazioni in Sysctl. Che leggerezza...

Tre settimane dopo, il problema si è ripresentato. La configurazione di questi server era piuttosto semplice: Nginx in modalità proxy/balancer. Il traffico era limitato. Nuovo dato: nei clienti, stava aumentando giorno dopo giorno il numero di errori 504 (Gateway Timeout). Nel grafico è mostrato il numero di errori 504 al giorno per questo servizio:

Fate attenzione alle vulnerabilità, workarounds pericolosi. Parte 1: FragmentSmack/SegmentSmack

Tutti gli errori riguardano lo stesso backend, quello situato nel cloud. Il grafico del consumo di memoria per i frammenti di pacchetti su questo backend era il seguente:

Fate attenzione alle vulnerabilità, workarounds pericolosi. Parte 1: FragmentSmack/SegmentSmack

Questa è una delle manifestazioni più evidenti del problema nei grafici del sistema operativo. Nel cloud, proprio in quel momento, è stata risolta un'altra problematica di rete relativa alle impostazioni QoS (Traffic Control). Nel grafico del consumo di memoria per i frammenti di pacchetti, appariva esattamente allo stesso modo:

Fate attenzione alle vulnerabilità, workarounds pericolosi. Parte 1: FragmentSmack/SegmentSmack

L'ipotesi era semplice: se nei grafici sono identici, allora anche la causa è la stessa. Soprattutto considerando che problemi di questo tipo di memoria si verificano molto raramente.

Il problema corretto consisteva nel fatto che utilizzavamo nel QoS lo scheduler di pacchetti fq con le impostazioni predefinite. Per impostazione predefinita, per una connessione consente di aggiungere in coda 100 pacchetti e alcune connessioni, in situazioni di scarsità di banda, iniziavano a riempire la coda fino al blocco. In questo caso, i pacchetti vengono scartati. Nelle statistiche tc (tc -s qdisc) ciò è visibile in questo modo:

qdisc fq 2c6c: padre 1:2c6c limite 10000p flow_limit 100p bucket 1024 orphan_mask 1023 quantum 3028 initial_quantum 15140 refill_delay 40.0ms
 Inviati 454701676345 byte 491683359 pkt (persi 464545, oltre limite 0 riordini 0)
 backlog 0b 0p riordini 0
  1024 flussi (1021 inattivi, 0 limitati)
  0 gc, 0 alta priorità, 0 limitati, 464545 flows_plimit

«464545 flows_plimit» rappresenta i pacchetti scartati a causa del superamento del limite della coda di una connessione, mentre «dropped 464545» indica il totale dei pacchetti scartati da questo scheduler. Dopo aver aumentato la lunghezza della coda a 1.000 e riavviato i container, il problema ha smesso di manifestarsi. È possibile rilassarsi in poltrona e gustare un frullato.

FragmentSmack/SegmentSmack. Ultima modifica

Innanzitutto, dopo alcuni mesi dall'annuncio delle vulnerabilità nel kernel, è finalmente arrivato un fix per FragmentSmack (ricordo che insieme all'annuncio di agosto era stato rilasciato solo un fix per SegmentSmack), il che ci ha dato la possibilità di mettere da parte il Workaround che ci ha causato diversi problemi. Nel frattempo abbiamo già migrato alcuni server al nuovo kernel e ora dovevamo ricominciare da capo. Perché abbiamo aggiornato il kernel senza attendere il fix per FragmentSmack? Il fatto è che il processo di protezione contro queste vulnerabilità si è sovrapposto (e si è fuso) con il processo di aggiornamento di CentOS stesso (che richiede ancora più tempo rispetto all'aggiornamento del solo kernel). Inoltre, SegmentSmack è una vulnerabilità più pericolosa, e il fix per essa è arrivato subito, quindi aveva comunque senso. Tuttavia, non potevamo semplicemente aggiornare il kernel su CentOS, perché la vulnerabilità FragmentSmack, che è emersa durante CentOS 7.5, è stata corretta solo nella versione 7.6, quindi abbiamo dovuto fermare l'aggiornamento a 7.5 e ricominciare tutto da capo con l'aggiornamento a 7.6. E anche questo succede.

In secondo luogo, ci sono tornate rare segnalazioni da parte degli utenti riguardo a problemi. Ora sappiamo con certezza che tutti erano legati al caricamento di file da parte dei clienti su alcuni dei nostri server. Inoltre, attraverso questi server sono passati davvero pochi caricamenti rispetto al totale.

Come ricordiamo dalla storia sopra, il rollback di Sysctl non ha aiutato. Ha funzionato il Riavvio, ma solo temporaneamente.
I sospetti su Sysctl non erano stati dissipati, ma questa volta era necessario raccogliere quante più informazioni possibili. Mancava anche la possibilità di riprodurre il problema del caricamento sul cliente, per poter studiare con maggiore precisione cosa stesse accadendo.

L'analisi di tutte le statistiche e dei log disponibili non ci ha avvicinati alla comprensione di quanto stava accadendo. Mangiava disperatamente la possibilità di riprodurre il problema per 'toccare con mano' una connessione specifica. Alla fine, agli sviluppatori su una versione speciale dell'applicazione è riuscita la riproduzione stabile del problema su un dispositivo di test connesso tramite Wi-Fi. Questo è stato un punto di svolta nell'indagine. Il cliente si connetteva a Nginx, che faceva da proxy al backend, rappresentato dalla nostra applicazione Java.

Fate attenzione alle vulnerabilità, workarounds pericolosi. Parte 1: FragmentSmack/SegmentSmack

Il dialogo durante i problemi era il seguente (registrato dal proxy Nginx):

  1. Cliente: richiesta di informazioni sul download del file.
  2. Server Java: risposta.
  3. Cliente: POST con file.
  4. Server Java: errore.

Il server Java scrive nel log che ha ricevuto 0 byte di dati dal client, mentre il proxy Nginx indica che la richiesta ha impiegato più di 30 secondi (30 secondi è il tempo di timeout dell'applicazione client). Perché si verifica il timeout e perché 0 byte? Dal punto di vista di HTTP, tutto funziona come dovrebbe, ma il POST con il file sembra scomparire dalla rete. Inoltre, sembra scomparire tra il client e Nginx. È arrivato il momento di armarsi di Tcpdump! Ma prima bisogna comprendere la configurazione della rete. Il proxy Nginx si trova dietro un bilanciatore L3. NFware. Si utilizza il tunneling per consegnare i pacchetti dal bilanciatore L3 al server, il quale aggiunge i propri header ai pacchetti:

Fate attenzione alle vulnerabilità, workarounds pericolosi. Parte 1: FragmentSmack/SegmentSmack

Inoltre, la rete su questo server arriva sotto forma di traffico taggato Vlan, che aggiunge anch'esso i propri campi ai pacchetti:

Fate attenzione alle vulnerabilità, workarounds pericolosi. Parte 1: FragmentSmack/SegmentSmack

E questo traffico può anche essere frammentato (quella piccola percentuale di traffico frammentato in ingresso di cui abbiamo parlato nella valutazione dei rischi da Workaround), il che cambia anche il contenuto degli header:

Fate attenzione alle vulnerabilità, workarounds pericolosi. Parte 1: FragmentSmack/SegmentSmack

Ancora una volta: i pacchetti sono incapsulati in un tag Vlan, incapsulati in un tunnel e frammentati. Per comprendere meglio come avviene questo processo, seguiamo il percorso di un pacchetto dal client al proxy Nginx.

  1. Il pacchetto raggiunge il bilanciatore di carico L3. Per una corretta instradamento all'interno del data center, il pacchetto è incapsulato in un tunnel e inviato alla scheda di rete.
  2. Poiché il pacchetto insieme agli header del tunnel supera l'MTU, il pacchetto viene suddiviso in frammenti e inviato nella rete.
  3. Lo switch dopo il bilanciatore L3, ricevendo il pacchetto, aggiunge un tag Vlan e lo invia oltre.
  4. Lo switch prima del proxy Nginx vede (in base alle impostazioni della porta) che il server si aspetta un pacchetto incapsulato in Vlan, quindi lo invia così com'è, senza rimuovere il tag Vlan.
  5. Linux riceve i frammenti dei singoli pacchetti e li unisce in un unico grande pacchetto.
  6. Successivamente, il pacchetto arriva all'interfaccia Vlan, dove viene rimossa la prima layer: l'incapsulamento Vlan.
  7. Poi, Linux lo invia all'interfaccia Tunnel, dove viene rimossa un'altra layer: l'incapsulamento del Tunnel.

La difficoltà sta nel trasmettere tutto questo come parametri a tcpdump.
Iniziamo dalla fine: ci sono pacchetti IP puliti (senza intestazioni extra) dai clienti, con incapsulamento vlan e tunnel rimosso?

tcpdump host

No, non ci sono stati pacchetti su questo server. Quindi, il problema deve trovarsi più a monte. Ci sono pacchetti con solo l'incapsulamento Vlan rimosso?

tcpdump ip[32:4]=0xx390x2xx

0xx390x2xx è l'indirizzo IP del cliente in formato esadecimale.
32:4 è l'indirizzo e la lunghezza del campo in cui è registrato l'IP SCR nel pacchetto Tunnel.

Ho dovuto trovare l'indirizzo del campo tramite tentativi, poiché su Internet si parla di 40, 44, 50, 54, ma non c'erano indirizzi IP. Puoi anche esaminare uno dei pacchetti in esadecimale (parametro -xx o -XX in tcpdump) e determinare a quale indirizzo corrisponde l'IP che conosci.

Ci sono frammenti di pacchetti senza l'incapsulamento Vlan e Tunnel rimosso?

tcpdump ((ip[6:2] > 0) and (not ip[6] = 64))

Questa magia ci mostrerà tutti i frammenti, incluso l'ultimo. Probabilmente è possibile filtrare anche per IP, ma non ci ho provato, dato che ci sono pochi di questi pacchetti e ho facilmente trovato ciò di cui avevo bisogno nel flusso generale. Ecco qui:

14:02:58.471063 In 00:de:ff:1a:94:11 ethertype IPv4 (0x0800), lunghezza 1516: (tos 0x0, ttl 63, id 53652, offset 0, flag [+], proto IPIP (4), lunghezza 1500)
    11.11.11.11 > 22.22.22.22: ip-troncato - 20 byte mancanti! (tos 0x0, ttl 50, id 57750, offset 0, flag [DF], proto TCP (6), lunghezza 1500)
    33.33.33.33.33333 > 44.44.44.44.80: Flag [.], seq 0:1448, ack 1, win 343, opzioni [nop,nop,TS val 11660691 ecr 2998165860], lunghezza 1448
        0x0000: 0000 0001 0006 00de fb1a 9441 0000 0800 ...........A....
        0x0010: 4500 05dc d194 2000 3f09 d5fb 0a66 387d E.......?....f8}
        0x0020: 1x67 7899 4500 06xx e198 4000 3206 6xx4 .faEE.....@.2.m.
        0x0030: b291 x9xx x345 2541 83b9 0050 9740 0x04 .......A...P.@..
        0x0040: 6444 4939 8010 0257 8c3c 0000 0101 080x dDI9...W.......
        0x0050: 00b1 ed93 b2b4 6964 xxd8 ffe1 006a 4578 ......ad.....jEx
        0x0060: 6966 0000 4x4d 002a 0500 0008 0004 0100 in etcdhelper, che non modificherà il servizio kube-dns...MM.*........

14:02:58.471103 In 00:de:ff:1a:94:11 ethertype IPv4 (0x0800), lunghezza 62: (tos 0x0, ttl 63, id 53652, offset 1480, flags [none], proto IPIP (4), lunghezza 40)
    11.11.11.11 > 22.22.22.22: ip-proto-4
        0x0000: 0000 0001 0006 00de fb1a 9441 0000 0800 ...........A....
        0x0010: 4500 0028 d194 00b9 3f04 faf6 2x76 385x E..(....?....f8}
        0x0020: 1x76 6545 xxxx 1x11 2d2c 0c21 8016 8e43 .faE...D-,.!...C
        0x0030: x978 e91d x9b0 d608 0000 0000 0000 7c31 .x............|Q
        0x0040: 881d c4b6 0000 0000 0000 0000 0000 ..............

Questi sono due frammenti di un pacchetto (ID 53652 identico) con una foto (la parola Exif è visibile nel primo pacchetto). Poiché a questo livello i pacchetti sono presenti, ma non nei dump uniti, il problema è chiaramente legato alla ricostruzione. Finalmente c'è una conferma documentale di ciò!

Il decoder dei pacchetti non ha rilevato problemi che impedissero la ricostruzione. L'ho provato qui: hpd.gasmi.net. All'inizio, quando cercavo di inviare qualcosa, il decoder non gradiva il formato del pacchetto. Si è scoperto che c'erano due ottetti extra tra Srcmac ed Ethertype (non relativi alle informazioni sui frammenti). Dopo averli rimossi, il decoder ha funzionato. Tuttavia, non ha segnalato alcun problema.
In ogni caso, oltre a quei Sysctl, non è stato trovato altro. Era necessario trovare un modo per identificare i server problematici, per capire l'entità del problema e prendere decisioni sulle azioni future. Ho trovato relativamente rapidamente il contatore necessario:

netstat -s | grep "packet reassembles failed"

È presente anche in snmpd con OID=1.3.6.1.2.1.4.31.1.1.16.1 (ipSystemStatsReasmFails).

«Il numero di fallimenti rilevati dall'algoritmo di ricostruzione IP (per qualsiasi motivo: scadenze, errori, ecc.)».

Tra il gruppo di server analizzati, due hanno mostrato un aumento più rapido di questo contatore, due un aumento più lento e altri due non hanno mostrato alcun incremento. Il confronto della dinamica di questo contatore con quella degli errori HTTP sul server Java ha rivelato una correlazione. Quindi, il contatore potrebbe essere impiegato per il monitoraggio.

Avere un indicatore affidabile dei problemi è molto importante per determinare con precisione se il rollback di Sysctl sia utile, poiché, come sappiamo dall'analisi precedente, non è possibile capirlo immediatamente dall'applicazione. Questo indicatore permetterebbe di identificare tutti i punti problematici in produzione prima che vengano notati dagli utenti.
Dopo il rollback di Sysctl, gli errori nel monitoraggio sono cessati, dimostrando così la causa dei problemi e confermando che il rollback è efficace.

Abbiamo ripristinato le impostazioni di frammentazione su altri server dove era stato attivato un nuovo monitoraggio, e in alcuni casi abbiamo allocato persino più memoria per i frammenti rispetto a quella che era impostata di default (si trattava di statistiche udp, la cui perdita parziale non era evidente nel contesto generale).

Le domande principali

Perché i pacchetti vengono frammentati sul nostro bilanciatore L3? La maggior parte dei pacchetti che arrivano dagli utenti ai bilanciatori è composta da SYN e ACK. Le dimensioni di questi pacchetti sono ridotte. Tuttavia, poiché la percentuale di tali pacchetti è molto alta, non abbiamo notato la presenza di pacchetti più grandi che hanno iniziato a essere frammentati.

La causa è stata uno script di configurazione danneggiato. advmss sui server con interfacce Vlan (c'erano molto pochi server con traffico taggato in produzione a quel tempo). Advmss consente di informare il cliente che i pacchetti verso di noi devono essere di dimensioni minori, in modo che, dopo l'aggiunta delle intestazioni del tunnel, non debbano essere frammentati.

Perché il rollback di Sysctl non aiutava, mentre il riavvio funzionava? Il rollback di Sysctl modificava la quantità di memoria disponibile per l'assemblaggio dei pacchetti. Tuttavia, sembra che il fatto stesso di avere memoria esaurita per i frammenti portasse a un rallentamento delle connessioni, causando così un prolungato ritardo dei frammenti in coda. Cioè, il processo si bloccava.
Il riavvio azzerava la memoria e tutto tornava a posto.

Si sarebbe potuti fare a meno del Workaround? Sì, ma c'è un grande rischio di lasciare gli utenti senza assistenza in caso di attacco. Certo, l'applicazione del Workaround ha portato alla nascita di vari problemi, tra cui il rallentamento di uno dei servizi per gli utenti, ma riteniamo che le azioni siano state giustificate.

Un grande grazie ad Andrej Timofeev (atimofeyev) per l'aiuto nell'indagine, così come ad Aleksej Krenëv (devicex) — per il lavoro titanico nell'aggiornamento di Centos e dei kernel sui server. Un processo che in questo caso è dovuto essere ripetuto diverse volte, facendo sì che si prolungasse per molti mesi.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS 🔥 Acquista hosting affidabile per siti web con protezione DDoS, server VPS VDS | ProHoster