cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

deprecated.rst (17380B)


      1.. SPDX-License-Identifier: GPL-2.0
      2
      3.. include:: ../disclaimer-ita.rst
      4
      5:Original: :ref:`Documentation/process/deprecated.rst <deprecated>`
      6:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
      7
      8.. _it_deprecated:
      9
     10==============================================================================
     11Interfacce deprecate, caratteristiche del linguaggio, attributi, e convenzioni
     12==============================================================================
     13
     14In un mondo perfetto, sarebbe possibile prendere tutti gli usi di
     15un'interfaccia deprecata e convertirli in quella nuova, e così sarebbe
     16possibile rimuovere la vecchia interfaccia in un singolo ciclo di sviluppo.
     17Tuttavia, per via delle dimensioni del kernel, la gerarchia dei manutentori e
     18le tempistiche, non è sempre possibile fare questo tipo di conversione tutta
     19in una volta. Questo significa che nuove istanze di una vecchia interfaccia
     20potrebbero aggiungersi al kernel proprio quando si sta cercando di rimuoverle,
     21aumentando così il carico di lavoro. Al fine di istruire gli sviluppatori su
     22cosa è considerato deprecato (e perché), è stata create la seguente lista a cui
     23fare riferimento quando qualcuno propone modifiche che usano cose deprecate.
     24
     25__deprecated
     26------------
     27Nonostante questo attributo marchi visibilmente un interfaccia come deprecata,
     28`non produce più alcun avviso durante la compilazione
     29<https://git.kernel.org/linus/771c035372a036f83353eef46dbb829780330234>`_
     30perché uno degli obiettivi del kernel è quello di compilare senza avvisi;
     31inoltre, nessuno stava agendo per rimuovere queste interfacce. Nonostante l'uso
     32di `__deprecated` in un file d'intestazione sia opportuno per segnare una
     33interfaccia come 'vecchia', questa non è una soluzione completa. L'interfaccia
     34deve essere rimossa dal kernel, o aggiunta a questo documento per scoraggiarne
     35l'uso.
     36
     37BUG() e BUG_ON()
     38----------------
     39Al loro posto usate WARN() e WARN_ON() per gestire le
     40condizioni "impossibili" e gestitele come se fosse possibile farlo.
     41Nonostante le funzioni della famiglia BUG() siano state progettate
     42per asserire "situazioni impossibili" e interrompere in sicurezza un
     43thread del kernel, queste si sono rivelate essere troppo rischiose
     44(per esempio, in quale ordine rilasciare i *lock*? Ci sono stati che
     45sono stati ripristinati?). Molto spesso l'uso di BUG()
     46destabilizza il sistema o lo corrompe del tutto, il che rende
     47impossibile un'attività di debug o anche solo leggere un rapporto
     48circa l'errore.  Linus ha un'opinione molto critica al riguardo:
     49`email 1
     50<https://lore.kernel.org/lkml/CA+55aFy6jNLsywVYdGp83AMrXBo_P-pkjkphPGrO=82SPKCpLQ@mail.gmail.com/>`_,
     51`email 2
     52<https://lore.kernel.org/lkml/CAHk-=whDHsbK3HTOpTF=ue_o04onRwTEaK_ZoJp_fjbqq4+=Jw@mail.gmail.com/>`_
     53
     54Tenete presente che la famiglia di funzioni WARN() dovrebbe essere
     55usato solo per situazioni che si suppone siano "impossibili".  Se
     56volete avvisare gli utenti riguardo a qualcosa di possibile anche se
     57indesiderato, usare le funzioni della famiglia pr_warn().  Chi
     58amministra il sistema potrebbe aver attivato l'opzione sysctl
     59*panic_on_warn* per essere sicuri che il sistema smetta di funzionare
     60in caso si verifichino delle condizioni "inaspettate". (per esempio,
     61date un'occhiata al questo `commit
     62<https://git.kernel.org/linus/d4689846881d160a4d12a514e991a740bcb5d65a>`_)
     63
     64Calcoli codificati negli argomenti di un allocatore
     65----------------------------------------------------
     66Il calcolo dinamico delle dimensioni (specialmente le moltiplicazioni) non
     67dovrebbero essere fatto negli argomenti di funzioni di allocazione di memoria
     68(o simili) per via del rischio di overflow. Questo può portare a valori più
     69piccoli di quelli che il chiamante si aspettava. L'uso di questo modo di
     70allocare può portare ad un overflow della memoria di heap e altri
     71malfunzionamenti. (Si fa eccezione per valori numerici per i quali il
     72compilatore può generare avvisi circa un potenziale overflow. Tuttavia usare
     73i valori numerici come suggerito di seguito è innocuo).
     74
     75Per esempio, non usate ``count * size`` come argomento::
     76
     77	foo = kmalloc(count * size, GFP_KERNEL);
     78
     79Al suo posto, si dovrebbe usare l'allocatore a due argomenti::
     80
     81	foo = kmalloc_array(count, size, GFP_KERNEL);
     82
     83Se questo tipo di allocatore non è disponibile, allora dovrebbero essere usate
     84le funzioni del tipo *saturate-on-overflow*::
     85
     86	bar = vmalloc(array_size(count, size));
     87
     88Un altro tipico caso da evitare è quello di calcolare la dimensione di una
     89struttura seguita da un vettore di altre strutture, come nel seguente caso::
     90
     91	header = kzalloc(sizeof(*header) + count * sizeof(*header->item),
     92			 GFP_KERNEL);
     93
     94Invece, usate la seguente funzione::
     95
     96	header = kzalloc(struct_size(header, item, count), GFP_KERNEL);
     97
     98.. note:: Se per caso state usando struct_size() su una struttura dati che
     99	  in coda contiene un array di lunghezza zero o uno, allora siete
    100	  invitati a riorganizzare il vostro codice usando il
    101	  `flexible array member <#zero-length-and-one-element-arrays>`_.
    102
    103Per maggiori dettagli fate riferimento a array_size(),
    104array3_size(), e struct_size(), così come la famiglia di
    105funzioni check_add_overflow() e check_mul_overflow().
    106
    107simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
    108----------------------------------------------------------------------
    109Le funzioni simple_strtol(), simple_strtoll(),
    110simple_strtoul(), e simple_strtoull() ignorano volutamente
    111i possibili overflow, e questo può portare il chiamante a generare risultati
    112inaspettati. Le rispettive funzioni kstrtol(), kstrtoll(),
    113kstrtoul(), e kstrtoull() sono da considerarsi le corrette
    114sostitute; tuttavia va notato che queste richiedono che la stringa sia
    115terminata con il carattere NUL o quello di nuova riga.
    116
    117strcpy()
    118--------
    119La funzione strcpy() non fa controlli agli estremi del buffer
    120di destinazione. Questo può portare ad un overflow oltre i limiti del
    121buffer e generare svariati tipi di malfunzionamenti. Nonostante l'opzione
    122`CONFIG_FORTIFY_SOURCE=y` e svariate opzioni del compilatore aiutano
    123a ridurne il rischio, non c'è alcuna buona ragione per continuare ad usare
    124questa funzione. La versione sicura da usare è strscpy(), tuttavia va
    125prestata attenzione a tutti quei casi dove viene usato il valore di
    126ritorno di strcpy().  La funzione strscpy() non ritorna un puntatore
    127alla destinazione, ma un contatore dei byte non NUL copiati (oppure
    128un errno negativo se la stringa è stata troncata).
    129
    130strncpy() su stringe terminate con NUL
    131--------------------------------------
    132L'utilizzo di strncpy() non fornisce alcuna garanzia sul fatto che
    133il buffer di destinazione verrà terminato con il carattere NUL. Questo
    134potrebbe portare a diversi overflow di lettura o altri malfunzionamenti
    135causati, appunto, dalla mancanza del terminatore. Questa estende la
    136terminazione nel buffer di destinazione quando la stringa d'origine è più
    137corta; questo potrebbe portare ad una penalizzazione delle prestazioni per
    138chi usa solo stringe terminate. La versione sicura da usare è
    139strscpy(), tuttavia va prestata attenzione a tutti quei casi dove
    140viene usato il valore di ritorno di strncpy().  La funzione strscpy()
    141non ritorna un puntatore alla destinazione, ma un contatore dei byte
    142non NUL copiati (oppure un errno negativo se la stringa è stata
    143troncata). Tutti i casi che necessitano di estendere la
    144terminazione con NUL dovrebbero usare strscpy_pad().
    145
    146Se il chiamate no usa stringhe terminate con NUL, allore strncpy()
    147può continuare ad essere usata, ma i buffer di destinazione devono essere
    148marchiati con l'attributo `__nonstring <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_
    149per evitare avvisi durante la compilazione.
    150
    151strlcpy()
    152---------
    153La funzione strlcpy(), per prima cosa, legge interamente il buffer di
    154origine, magari leggendo più di quanto verrà effettivamente copiato. Questo
    155è inefficiente e può portare a overflow di lettura quando la stringa non è
    156terminata con NUL. La versione sicura da usare è strscpy(), tuttavia
    157va prestata attenzione a tutti quei casi dove viene usato il valore di
    158ritorno di strlcpy(), dato che strscpy() ritorna un valore di errno
    159negativo quanto la stringa viene troncata.
    160
    161Segnaposto %p nella stringa di formato
    162--------------------------------------
    163
    164Tradizionalmente, l'uso del segnaposto "%p" nella stringa di formato
    165esponne un indirizzo di memoria in dmesg, proc, sysfs, eccetera.  Per
    166evitare che questi indirizzi vengano sfruttati da malintenzionati,
    167tutto gli usi di "%p" nel kernel rappresentano l'hash dell'indirizzo,
    168rendendolo di fatto inutilizzabile.  Nuovi usi di "%p" non dovrebbero
    169essere aggiunti al kernel.  Per una rappresentazione testuale di un
    170indirizzo usate "%pS", l'output è migliore perché mostrerà il nome del
    171simbolo.  Per tutto il resto, semplicemente non usate "%p".
    172
    173Parafrasando la `guida
    174<https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/>`_
    175di Linus:
    176
    177- Se il valore hash di "%p" è inutile, chiediti se il puntatore stesso
    178  è importante. Forse dovrebbe essere rimosso del tutto?
    179- Se credi davvero che il vero valore del puntatore sia importante,
    180  perché alcuni stati del sistema o i livelli di privilegi di un
    181  utente sono considerati "special"? Se pensi di poterlo giustificare
    182  (in un commento e nel messaggio del commit) abbastanza bene da
    183  affrontare il giudizio di Linus, allora forse potrai usare "%px",
    184  assicurandosi anche di averne il permesso.
    185
    186Potete disabilitare temporaneamente l'hashing di "%p" nel caso in cui questa
    187funzionalità vi sia d'ostacolo durante una sessione di debug. Per farlo
    188aggiungete l'opzione di debug "`no_hash_pointers
    189<https://git.kernel.org/linus/5ead723a20e0447bc7db33dc3070b420e5f80aa6>`_" alla
    190riga di comando del kernel.
    191
    192Vettori a dimensione variabile (VLA)
    193------------------------------------
    194
    195Usare VLA sullo stack produce codice molto peggiore rispetto a quando si usano
    196vettori a dimensione fissa. Questi `problemi di prestazioni <https://git.kernel.org/linus/02361bc77888>`_,
    197tutt'altro che banali, sono già un motivo valido per eliminare i VLA; in
    198aggiunta sono anche un problema per la sicurezza. La crescita dinamica di un
    199vettore nello stack potrebbe eccedere la memoria rimanente in tale segmento.
    200Questo può portare a dei malfunzionamenti, potrebbe sovrascrivere
    201dati importanti alla fine dello stack (quando il kernel è compilato senza
    202`CONFIG_THREAD_INFO_IN_TASK=y`), o sovrascrivere un pezzo di memoria adiacente
    203allo stack (quando il kernel è compilato senza `CONFIG_VMAP_STACK=y`).
    204
    205Salto implicito nell'istruzione switch-case
    206-------------------------------------------
    207
    208Il linguaggio C permette ai casi di un'istruzione `switch` di saltare al
    209prossimo caso quando l'istruzione "break" viene omessa alla fine del caso
    210corrente. Tuttavia questo rende il codice ambiguo perché non è sempre ovvio se
    211l'istruzione "break" viene omessa intenzionalmente o è un baco. Per esempio,
    212osservando il seguente pezzo di codice non è chiaro se lo stato
    213`STATE_ONE` è stato progettato apposta per eseguire anche `STATE_TWO`::
    214
    215  switch (value) {
    216  case STATE_ONE:
    217          do_something();
    218  case STATE_TWO:
    219          do_other();
    220          break;
    221  default:
    222          WARN("unknown state");
    223  }
    224
    225Dato che c'è stata una lunga lista di problemi `dovuti alla mancanza dell'istruzione
    226"break" <https://cwe.mitre.org/data/definitions/484.html>`_, oggigiorno non
    227permettiamo più che vi sia un "salto implicito" (*fall-through*). Per
    228identificare un salto implicito intenzionale abbiamo adottato la pseudo
    229parola chiave 'fallthrough' che viene espansa nell'estensione di gcc
    230`__attribute__((fallthrough))` `Statement Attributes
    231<https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_.
    232(Quando la sintassi C17/C18 `[[fallthrough]]` sarà più comunemente
    233supportata dai compilatori C, analizzatori statici, e dagli IDE,
    234allora potremo usare quella sintassi per la pseudo parola chiave)
    235
    236Quando la sintassi [[fallthrough]] sarà più comunemente supportata dai
    237compilatori, analizzatori statici, e ambienti di sviluppo IDE,
    238allora potremo usarla anche noi.
    239
    240Ne consegue che tutti i blocchi switch/case devono finire in uno dei seguenti
    241modi:
    242
    243* ``break;``
    244* `fallthrough;``
    245* ``continue;``
    246* ``goto <label>;``
    247* ``return [expression];``
    248
    249Array di lunghezza zero o con un solo elemento
    250----------------------------------------------
    251All'interno del kernel ricorre spesso la necessita di avere membri
    252di dimensione variabile all'interno di una struttura dati. In questi
    253casi il codice del kernel dovrebbe usare sempre i `"flexible array
    254member" <https://en.wikipedia.org/wiki/Flexible_array_member>`_. La
    255tecnica degli array a lunghezza nulla o di un solo elemento non
    256dovrebbe essere più usata.
    257
    258Nel codice C più vecchio, la dichiarazione di un membro di dimensione
    259variabile in coda ad una struttura dati veniva fatto dichiarando un
    260array di un solo elemento posizionato alla fine della struttura dati::
    261
    262        struct something {
    263                size_t count;
    264                struct foo items[1];
    265        };
    266
    267Questo ha portato ad un calcolo di sizeof() traballante (dovrebbe
    268rimuovere la dimensione del singolo elemento in coda per calcolare la
    269dimensione esatta dell' "intestazione"). Per evitare questi problemi è
    270stata introdotta un' `estensione a GNU C
    271<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_ che
    272permettesse la dichiarazione di array a lungezza zero::
    273
    274        struct something {
    275                size_t count;
    276                struct foo items[0];
    277        };
    278
    279Ma questo ha portato nuovi problemi, e non ha risolto alcuni dei
    280problemi che affliggono entrambe le tecniche: per esempio
    281l'impossibilità di riconoscere se un array di quel tipo viene usato
    282nel mezzo di una struttura dati e _non_ alla fine (potrebbe accadere
    283sia direttamente, sia indirettamente quando si usano le unioni o le
    284strutture di strutture).
    285
    286Lo standard C99 introduce i "flexible array members". Questi array non
    287hanno una dimensione nella loro dichiarazione::
    288
    289        struct something {
    290                size_t count;
    291                struct foo items[];
    292        };
    293
    294Questo è il modo con cui ci si aspetta che vengano dichiarati gli
    295elementi di lunghezza variabile in coda alle strutture dati.  Permette
    296al compilatore di produrre errori quando gli array flessibili non si
    297trovano alla fine della struttura dati, il che permette di prevenire
    298alcuni tipi di bachi dovuti a `comportamenti inaspettati
    299<https://git.kernel.org/linus/76497732932f15e7323dc805e8ea8dc11bb587cf>`_.
    300Inoltre, permette al compilatore di analizzare correttamente le
    301dimensioni degli array (attraverso sizeof(), `CONFIG_FORTIFY_SOURCE`,
    302e `CONFIG_UBSAN_BOUNDS`). Per esempio, non esiste alcun meccanismo in
    303grado di avvisarci che il seguente uso di sizeof() dia sempre come
    304zero come risultato::
    305
    306        struct something {
    307                size_t count;
    308                struct foo items[0];
    309        };
    310
    311        struct something *instance;
    312
    313        instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
    314        instance->count = count;
    315
    316        size = sizeof(instance->items) * instance->count;
    317        memcpy(instance->items, source, size);
    318
    319Il valore di ``size`` nell'ultima riga sarà ``zero``, quando uno
    320invece si aspetterebbe che il suo valore sia la dimensione totale in
    321byte dell'allocazione dynamica che abbiamo appena fatto per l'array
    322``items``. Qui un paio di esempi reali del problema: `collegamento 1
    323<https://git.kernel.org/linus/f2cd32a443da694ac4e28fbf4ac6f9d5cc63a539>`_,
    324`collegamento 2
    325<https://git.kernel.org/linus/ab91c2a89f86be2898cee208d492816ec238b2cf>`_.
    326Invece, `i flexible array members hanno un tipo incompleto, e quindi
    327sizeof() non può essere applicato
    328<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_; dunque ogni
    329uso scorretto di questo operatore verrà identificato immediatamente
    330durante la compilazione.
    331
    332Per quanto riguarda gli array di un solo elemento, bisogna essere
    333consapevoli che `questi array occupano almeno quanto lo spazio di un
    334singolo oggetti dello stesso tipo
    335<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_, e quindi
    336contribuiscono al calcolo della dimensione della struttura che li
    337contiene. In questo caso è facile commettere errori quando si vuole
    338calcolare la dimensione totale della memoria totale da allocare per
    339una struttura dati::
    340
    341        struct something {
    342                size_t count;
    343                struct foo items[1];
    344        };
    345
    346        struct something *instance;
    347
    348        instance = kmalloc(struct_size(instance, items, count - 1), GFP_KERNEL);
    349        instance->count = count;
    350
    351        size = sizeof(instance->items) * instance->count;
    352        memcpy(instance->items, source, size);
    353
    354In questo esempio ci siamo dovuti ricordare di usare ``count - 1`` in
    355struct_size(), altrimenti avremmo --inavvertitamente-- allocato
    356memoria per un oggetti ``items`` in più. Il modo più pulito e meno
    357propenso agli errori è quello di usare i `flexible array member`, in
    358combinazione con struct_size() e flex_array_size()::
    359
    360        struct something {
    361                size_t count;
    362                struct foo items[];
    363        };
    364
    365        struct something *instance;
    366
    367        instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
    368        instance->count = count;
    369
    370	memcpy(instance->items, source, flex_array_size(instance, items, instance->count));