{"id":26550153,"url":"https://github.com/mikyll/sistemi-operativi-m","last_synced_at":"2025-03-22T07:32:29.005Z","repository":{"id":73339098,"uuid":"411182856","full_name":"mikyll/Sistemi-Operativi-M","owner":"mikyll","description":"Appunti (incompleti), prove esame svolte e flashcard per studiare la teoria del corso Sistemi Operativi M della prof.ssa Anna Ciampolini @Unibo.","archived":false,"fork":false,"pushed_at":"2025-03-08T19:18:10.000Z","size":4256,"stargazers_count":22,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-08T19:25:28.303Z","etag":null,"topics":["alma-mater-studiorum","appunti","bologna","magistrale","notes","operating-system","operativi","sistemi","sistemi-operativi","unibo"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mikyll.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-28T07:39:01.000Z","updated_at":"2025-03-08T19:18:14.000Z","dependencies_parsed_at":null,"dependency_job_id":"8daebd83-af62-4610-9299-38c32a41c6a1","html_url":"https://github.com/mikyll/Sistemi-Operativi-M","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikyll%2FSistemi-Operativi-M","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikyll%2FSistemi-Operativi-M/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikyll%2FSistemi-Operativi-M/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikyll%2FSistemi-Operativi-M/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mikyll","download_url":"https://codeload.github.com/mikyll/Sistemi-Operativi-M/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244924723,"owners_count":20532872,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alma-mater-studiorum","appunti","bologna","magistrale","notes","operating-system","operativi","sistemi","sistemi-operativi","unibo"],"created_at":"2025-03-22T07:30:35.257Z","updated_at":"2025-03-22T07:32:28.995Z","avatar_url":"https://github.com/mikyll.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eSistemi Operativi M\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  Appunti del corso \u003ca href=\"https://www.unibo.it/it/didattica/insegnamenti/insegnamento/2021/468009\"\u003e\u003cb\u003eSistemi Operativi M\u003c/b\u003e (72947)\u003c/a\u003e, anno 2021-2022, tenuto dalla prof.ssa \u003ca href=\"https://www.unibo.it/sitoweb/anna.ciampolini\"\u003e\u003cb\u003eAnna Ciampolini\u003c/b\u003e\u003c/a\u003e. A cura di \u003ca href=\"https://github.com/mikyll\"\u003eMichele Righi\u003c/a\u003e, \u003ca href=\"https://github.com/TryKatChup\"\u003eKarina Chichifoi\u003c/a\u003e e \u003ca href=\"https://github.com/lnwor\"\u003eLorenzo Guerra\u003c/a\u003e.\n\t\u003cbr/\u003e\n\t\u003cb\u003eSPOILER: gli appunti sono incompleti, ma \u003cins\u003eprove esame\u003c/ins\u003e e \u003cins\u003eflashcard\u003c/ins\u003e sono molto utili.\u003c/b\u003e\n  \u003cbr/\u003e\n\t\u003cbr/\u003e\n\t\u003ca href=\"capitoli\"\u003eCapitoli\u003c/a\u003e\n\t·\n\t\u003ca href=\"prove esame\"\u003eProve Esame\u003c/a\u003e\n\t·\n\t\u003ca href=\"flashcard\"\u003eFlashcard\u003c/a\u003e\n\t·\n\t\u003ca href=\"https://github.com/mikyll/Sistemi-Operativi-M/issues\"\u003eReport a bug\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cdetails open=\"open\"\u003e\n  \u003csummary\u003e\u003ch2 style=\"display: inline-block\"\u003eIndice\u003c/h2\u003e\u003c/summary\u003e\n  \u003col\u003e\n\u003c!-- CAPITOLO 1 --\u003e\n    \u003cli\u003e\u003ca href=\"#01---virtualizzazione-\"\u003eVirtualizzazione\u003c/a\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#virtualizzazione-di-un-sistema-di-elaborazione\"\u003eVirtualizzazione di un sistema di elaborazione\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#emulazione\"\u003eEmulazione\u003c/a\u003e\n          \u003cul\u003e\n            \u003cli\u003e\u003ca href=\"#interpretazione\"\u003eInterpretazione\u003c/a\u003e\n            \u003cli\u003e\u003ca href=\"#compilazione-dinamica\"\u003eCompilazione Dinamica\u003c/a\u003e\n          \u003c/ul\u003e\n        \u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#tipi-livelli-di-virtualizzazione\"\u003eTipi (Livelli) di Virtualizzazione\u003c/a\u003e\u003c/li\u003e\n        \u003c!--\u003cli\u003e\u003ca href=\"#cenni-storici\"\u003eCenni Storici\u003c/a\u003e\u003c/li\u003e--\u003e\n        \u003cli\u003e\u003ca href=\"#vantaggi-della-virtualizzazione\"\u003eVantaggi della Virtualizzazione\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#realizzazione-del-vmm\"\u003eRealizzazione del VMM\u003c/a\u003e\n          \u003cul\u003e\n            \u003c!--\u003cli\u003e\u003ca href=\"#vmm-di-sistema\"\u003eVMM di Sistema\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#vmm-ospitato\"\u003eVMM Ospitato\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#ring-di-protezione\"\u003eRing di Protezione\u003c/a\u003e\n              \u003cul\u003e\n                \u003cli\u003e\u003ca href=\"#ring-deprivileging\"\u003eRing Deprivileging\u003c/a\u003e\u003c/li\u003e\n                \u003cli\u003e\u003ca href=\"#ring-compression\"\u003eRing Compression\u003c/a\u003e\u003c/li\u003e\n                \u003cli\u003e\u003ca href=\"#ring-aliasing\"\u003eRing Aliasing\u003c/a\u003e\u003c/li\u003e\n              \u003c/ul\u003e\n            \u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#supporto-hardware-alla-virtualizzazione\"\u003eSupporto Hardware alla Virtualizzazione\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#realizzazione-del-vmm-in-architetture-non-virtualizzabili\"\u003eRealizzazione del VMM in Architetture Non Virtualizzabili\u003c/a\u003e\u003c/li\u003e--\u003e\n            \u003cli\u003e\u003ca href=\"#fast-binary-translation-ftb\"\u003eFast Binary Translation (FTB)\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#paravirtualizzazione\"\u003eParavirtualizzazione\u003c/a\u003e\u003c/li\u003e\n          \u003c/ul\u003e\n        \u003c/li\u003e\n        \u003c!--\u003cli\u003e\u003ca href=\"#architetture-virtualizzabili\"\u003eArchitetture Virtualizzabili\u003c/a\u003e\n          \u003cul\u003e\n            \u003cli\u003e\u003ca href=\"#protezione-nellarchitettura-x86\"\u003eProtezione nell'architettura x86\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#funzionamento-dei-vmm-nellarchitettura-x86-classica\"\u003eFunzionamento dei VMM nell'architettura x86 classica\u003c/a\u003e\u003c/li\u003e\n          \u003c/ul\u003e\n        \u003c/li\u003e--\u003e\n        \u003cli\u003e\u003ca href=\"#gestione-di-vm\"\u003eGestione di VM\u003c/a\u003e\n          \u003cul\u003e\n            \u003cli\u003e\u003ca href=\"#stati-di-una-vm\"\u003eStati di una VM\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#migrazione-di-una-vm\"\u003eMigrazione di una VM\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#soluzione-precopy\"\u003eSoluzione: precopy\u003c/a\u003e\u003c/li\u003e\n          \u003c/ul\u003e\n\t\t\t\t\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#xen\"\u003eXEN\u003c/a\u003e\n          \u003cul\u003e\n            \u003cli\u003e\u003ca href=\"#architettura\"\u003eArchitettura\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#realizzazione\"\u003eRealizzazione\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#gestione-della-memoria-e-paginazione\"\u003eGestione della Memoria e Paginazione\u003c/a\u003e\n\t\t\t\t\t\t\t\u003cul\u003e\n                \u003cli\u003e\u003ca href=\"#protezione-memory-split\"\u003eProtezione: Memory Split\u003c/a\u003e\u003c/li\u003e\n                \u003cli\u003e\u003ca href=\"#protezione-balloon-process\"\u003eProtezione: Balloon Process\u003c/a\u003e\u003c/li\u003e\n              \u003c/ul\u003e\n\t\t\t\t\t\t\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#cenni-su-virtualizzazione-della-cpu\"\u003eCenni su Virtualizzazione della CPU\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#virtualizzazione-dei-dispositivi-io\"\u003eVirtualizzazione dei Dispositivi (I/O)\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#gestione-delle-interruzioni\"\u003eGestione delle Interruzioni\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#migrazione-live\"\u003eMigrazione Live\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\u003c/ul\u003e\n\t\t\t\t\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/li\u003e\n\u003c!-- CAPITOLO 2 --\u003e\n    \u003cli\u003e\u003ca href=\"#02---protezione-\"\u003eProtezione\u003c/a\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#protezione-modelli-politiche-e-meccanismi\"\u003eProtezione: Modelli, Politiche e Meccanismi\u003c/a\u003e\n\t\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#modelli\"\u003eModelli\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#politiche\"\u003ePolitiche\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#meccanismi\"\u003eMeccanismi\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\u003c/ul\u003e\n\t\t\t\t\u003c/li\u003e\n\t\t\t\t\u003cli\u003e\u003ca href=\"#dominio-di-protezione\"\u003eDominio di Protezione\u003c/a\u003e\n\t\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#associazione-tra-processo-e-dominio\"\u003eAssociazione tra Processo e Dominio\u003c/a\u003e\n\t\t\t\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#esempio-di-cambio-di-dominio\"\u003eEsempio di cambio di dominio\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\u003c/ul\u003e\n\t\t\t\t\t\u003c/ul\u003e\n\t\t\t\t\u003c/li\u003e\n\t\t\t\t\u003cli\u003e\u003ca href=\"#matrice-degli-accessi\"\u003eMatrice degli Accessi\u003c/a\u003e\n\t\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\t\u003c!--\u003cli\u003e\u003ca href=\"#verifica-del-rispetto-dei-vincoli-di-accesso\"\u003eVerifica del Rispetto dei Vincoli di Accesso\u003c/a\u003e\u003c/li\u003e--\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#modifica-dello-stato-di-protezione\"\u003eModifica dello Stato di Protezione\u003c/a\u003e\n\t\t\t\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\t\t\t\u003c!--\u003cli\u003e\u003ca href=\"#modello-graham-denning\"\u003eModello Graham-Denning\u003c/a\u003e\u003c/li\u003e--\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#propagazione-dei-diritti-di-accesso-copy-flag\"\u003ePropagazione dei Diritti di Accesso (Copy Flag)\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\t\u003c!--\u003cli\u003e\u003ca href=\"#diritto-owner\"\u003eDiritto Owner\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#diritto-control\"\u003eDiritto Control\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#diritto-switch\"\u003eDiritto Switch\u003c/a\u003e\u003c/li\u003e--\u003e\n\t\t\t\t\t\t\t\u003c/ul\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#realizzazione-della-matrice-degli-accessi\"\u003eRealizzazione della Matrice degli Accessi\u003c/a\u003e\n\t\t\t\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#acl-lista-degli-accessi\"\u003eACL: Lista degli Accessi\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#cl-capability-list\"\u003eCL: Capability List\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\u003c/ul\u003e\n\t\t\t\t\t\t\u003c/li\u003e\n\t\t\t\t\t\t\u003c!--\u003cli\u003e\u003ca href=\"#revoca-dei-diritti-di-accesso\"\u003eRevoca dei Diritti di Accesso\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#acl-vs-cl\"\u003eACL vs CL\u003c/a\u003e\u003c/li\u003e--\u003e\n\t\t\t\t\t\u003c/ul\u003e\n\t\t\t\t\u003c/li\u003e\n\t\t\t\t\u003cli\u003e\u003ca href=\"#protezione-multilivello\"\u003eProtezione Multilivello\u003c/a\u003e\n\t\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#modelli-di-sicurezza-multilivello\"\u003eModelli di Sicurezza Multilivello\u003c/a\u003e\n\t\t\t\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#modello-bell-la-padula\"\u003eModello Bell-La Padula\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#modello-biba\"\u003eModello Biba\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\u003c/ul\u003e\n\t\t\t\t\t\t\u003c/li\u003e\n\t\t\t\t\t\u003c/ul\u003e\n\t\t\t\t\u003c/li\u003e\n\t\t\t\t\u003c!--\u003cli\u003e\u003ca href=\"#architetture-dei-sistemi-ad-elevata-sicurezza\"\u003eArchitetture dei Sistemi ad Elevata Sicurezza\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\u003cli\u003e\u003ca href=\"#classificazione-della-sicurezza-dei-sistemi-di-calcolo\"\u003eClassificazione della Sicurezza dei Sistemi di Calcolo\u003c/a\u003e\u003c/li\u003e--\u003e\n\t\t\t\u003c/ul\u003e\n\t\t\u003c/li\u003e\n\u003c!-- CAPITOLO 3 --\u003e\n\t\t\u003cli\u003e\u003ca href=\"#03---programmazione-concorrente-\"\u003eProgrammazione Concorrente\u003c/a\u003e\n\t\t\t\u003cul\u003e\n\t\t\t\t\u003c!--\u003cli\u003e\u003ca href=\"#cenni-storici\"\u003eCenni Storici\u003c/a\u003e\u003c/li\u003e--\u003e\n\t\t\t\t\u003cli\u003e\u003ca href=\"#tipi-di-architettura\"\u003eTipi di architettura\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\u003cli\u003e\u003ca href=\"#classificazione-delle-architetture\"\u003eClassificazione delle Architetture\u003c/a\u003e\n\t\t\t\t\t\u003c!--\u003cul\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#single-processor\"\u003eSingle Processor\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#shared-memory-multiprocessors\"\u003eShared-Memory Multiprocessors\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#distributed-memory\"\u003eDistributed-Memory\u003c/a\u003e\n\t\t\t\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#multicomputers\"\u003eMulticomputers\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#network-systems\"\u003eNetwork Systems\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\u003c/ul\u003e\n\t\t\t\t\t\t\u003c/li\u003e\n\t\t\t\t\t\u003c/ul\u003e--\u003e\n\t\t\t\t\u003c/li\u003e\n\t\t\t\t\u003cli\u003e\u003ca href=\"#tipi-di-applicazioni\"\u003eTipi di Applicazioni\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\u003cli\u003e\u003ca href=\"#processi-non-sequenziali-e-tipi-di-iterazione\"\u003eProcessi Non Sequenziali e Tipi di Iterazione\u003c/a\u003e\n\t\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#processo-sequenziale\"\u003eProcesso Sequenziale\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#processo-non-sequenziale\"\u003eProcesso Non Sequenziale\u003c/a\u003e\n\t\t\t\t\t\t\t\u003c!--\u003cul\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#elaboratore-non-sequenziale\"\u003eElaboratore Non Sequenziale\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#linguaggi-concorrenti\"\u003eLinguaggi Concorrenti\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\u003c/ul\u003e--\u003e\n\t\t\t\t\t\t\u003c/li\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#scomposizione-di-un-processo-non-sequenziale\"\u003eScomposizione di un Processo Non Sequenziale\u003c/a\u003e\n\t\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#interazione-tra-processi\"\u003eInterazione tra Processi\u003c/a\u003e\n\t\t\t\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#cooperazione\"\u003eCooperazione\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#competizione\"\u003eCompetizione\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#interferenza\"\u003eInterferenza\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\u003c/ul\u003e\n\t\t\t\t\t\t\u003c/li\u003e\n\t\t\t\t\t\u003c/ul\u003e\n\t\t\t\t\u003c/li\u003e\n\t\t\t\u003c/ul\u003e\n\t\t\u003c/li\u003e\n\t\t\u003cli\u003e\u003ca href=\"#architetture-e-linguaggi-per-la-programmazione-concorrente\"\u003eArchitetture e Linguaggi per la Programmazione Concorrente\u003c/a\u003e\u003c/li\u003e\n\t\t\u003cli\u003e\u003ca href=\"#architettura-di-una-macchina-concorrente\"\u003eArchitettura di una Macchina Concorrente\u003c/a\u003e\n\t\t\t\u003cul\u003e\n\t\t\t\t\u003cli\u003e\u003ca href=\"#architettura-della-macchina-m\"\u003eArchitettura della Macchina M\u003c/a\u003e\u003c/li\u003e\n\t\t\t\u003c/ul\u003e\n\t\t\u003c/li\u003e\n\t\t\u003cli\u003e\u003ca href=\"#costrutti-linguistici-per-la-specifica-della-concorrenza\"\u003eCostrutti Linguistici per la Specifica della Concorrenza\u003c/a\u003e\n\t\t\t\u003cul\u003e\n\t\t\t\t\u003cli\u003e\u003ca href=\"#forkjoin\"\u003eFork/Join\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\u003cli\u003e\u003ca href=\"#cobegincoend\"\u003eCobegin/Coend\u003c/a\u003e\u003c/li\u003e\n\t\t\t\u003c/ul\u003e\n\t\t\u003c/li\u003e\n\t\t\u003cli\u003e\u003ca href=\"#proprietà-dei-programmi\"\u003eProprietà dei Programmi\u003c/a\u003e\n\t\t\t\u003cul\u003e\n\t\t\t\t\u003cli\u003e\u003ca href=\"#verifica-della-correttezza-di-un-programma\"\u003eVerifica della Correttezza di un Programma\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\u003cli\u003e\u003ca href=\"#proprietà-di-safety-e-liveness\"\u003eProprietà di Safety e Liveness\u003c/a\u003e\n\t\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#proprietà-dei-programmi-sequenziali\"\u003eProprietà dei Programmi Sequenziali\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#proprietà-dei-programmi-concorrenti\"\u003eProprietà dei Programmi Concorrenti\u003c/a\u003e\n\t\t\t\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\t\t\t\u003cli\u003e\u003ca href=\"#verifica-di-proprietà-nei-programmi-concorrenti\"\u003eVerifica di Proprietà nei Programmi Concorrenti\u003c/a\u003e\u003c/li\u003e\n\t\t\t\t\t\t\t\u003c/ul\u003e\n\t\t\t\t\t\t\u003c/li\u003e\n\t\t\t\t\t\u003c/ul\u003e\n\t\t\t\t\u003c/li\u003e\n\t\t\t\u003c/ul\u003e\n\t\t\u003c/li\u003e\n  \u003c/ol\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2 style=\"display: inline-block\"\u003eIndice per lezioni\u003c/h2\u003e\u003c/summary\u003e\n  \u003cul\u003e\n    \u003cli\u003e\u003ca href=\"#01---virtualizzazione-\"\u003e2021/09/21\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#soluzione-precopy\"\u003e2021/09/28\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#diritto-owner\"\u003e2021/09/29\u003c/a\u003e\u003c/li\u003e\n\t\t\u003cli\u003e\u003ca href=\"#03---programmazione-concorrente-\"\u003e2021/10/05\u003c/a\u003e\u003c/li\u003e\n\t\t\u003cli\u003e\u003ca href=\"#interazione-tra-processi\"\u003e2021/10/06\u003c/a\u003e\u003c/li\u003e\n\t\t\u003cli\u003e\u003ca href=\"#proprietà-dei-programmi-concorrenti\"\u003e2021/10/12\u003c/a\u003e\u003c/li\u003e\n\t\t\u003cli\u003e\u003ca href=\"#\"\u003e2021/10/13\u003c/a\u003e\u003c/li\u003e\n  \u003c/ul\u003e\n\u003c/details\u003e\n\n\u003c!-- Lezione 2021/09/21--\u003e\n## 01 - Virtualizzazione [![Vai al Capitolo Singolo](gfx/icons/file-moved_dark.svg#gh-light-mode-only)](capitoli/01%20-%20Virtualizzazione.md#gh-light-mode-only \"Vai al Capitolo Singolo\") [![Vai al Capitolo Singolo](gfx/icons/file-moved_light.svg#gh-dark-mode-only)](capitoli/01%20-%20Virtualizzazione.md#gh-dark-mode-only \"Vai al Capitolo Singolo\")\n\nLa virtualizzazione è una tecnologia oggi usatissima. Virtualizzare un sistema di elaborazione (costituito da un insieme di risorse hardware e software) significa presentare all'utilizzatore una visione delle risorse diversa da quella attuale (ad esempio duplicazione della memoria). Questo obbiettivo viene raggiunto mediante un livello intermedio, un layer che svolge appunto il ruolo di intermediario tra utilizzatore (vista logica) e sistema (vista fisica). Solitamente l'intermediario è software, ma talvolta può avere un supporto hardware specifico. Esso permette di eseguire più macchine virtuali su una stessa architettura e ognuna di queste vede le proprie risorse, indipendentemente dalle altre, e da quelle effettive (\"reali\").\\\nPoiché le Macchine Virtuali (VM) devono funzionare in modo indipendente senza causare problemi al sistema, la gestione delle risorse dev'essere realizzata in modo appropriato: questo compito è affidato al Virtual Machine Monitor (VMM, detto anche Hypervisor), cha ha compiti molto simili a quelli di un Sistema Operativo (SO), motivo per cui viene trattato in questo corso).\n\nEsempi di virtualizzazione:\n- **virtualizzazione a livello di processo** - i SO multitasking consentono l'esecuzione parallela di più processi, ognuno dei quali dispone di una VM (CPU, memoria, dispositivi) dedicata. Questo tipo è realizzato dal kernel;\n- **virtualizzazione della memoria** - con memoria virtuale ogni processo vede uno spazio di indirizzamento di dimensioni indipendenti dalle reali dimensioni e dallo spazio effettivamente a disposizione. Anche questo è realizzato dal kernel del SO;\n- **astrazione** - un oggetto astratto (risorsa virtuale) come rappresentazione semplificata di un oggetto (risorsa fisica). Solitamente, l'astrazione serve per fornire una vista delle sole proprietà significative, nascondendo i dettagli realizzativi non necessari, ad esempio i tipi di dato ad alto livello (numeri intero, numeri in virgola mobile, ecc.) rispetto alla loro rappresentazione binaria nella cella di memoria. Un altro esempio sono i linguaggi di programmazione, in cui un'istruzione di alto livello è un'astrazione di ciò che avviene a più basso livello, in linguaggio macchina. Il disaccoppiamento è realizzato dalle operazioni (interfaccia) con le quali è possibile utilizzare l'oggetto;\n- **linguaggi di programmazione** - la capacità di portare lo stesso programma (scritto in un linguaggio di alto livello) su architetture diverse è possibile grazie alla definizione di una VM in grado di interpretare ed eseguire ogni istruzione del linguaggio, indipendentemente dall'architettura del sistema (SO e hardware). Possibili esempi sono gli interpreti (ad esempio Java Virtual Machine, cacpace di eseguire il bytecode Java), ed i compilatori.\n\n### Virtualizzazione di un sistema di elaborazione\nUna singola piattaforma hardware viene condivisa da più elaboratori virtuali, ognuno gestito da un proprio sistema operativo. Il disaccoppiamento viene realizzato dal VMM, che è il mediatore unico tra le VM e l'hardware. I suoi compiti sono *consentire la condivisione da parte di più macchine virtuali di una singola piattaforma hardware*, garantendo *isolamento* tra di esse e *stabilità* del sistema. Il VMM deve realizzare una specie di sandbox per ciascuna VM (se ad esempio una va in crash, le altre non devono risentirne).\n\n### Emulazione\nConsiste nell'esecuzione di programmi compilati per una particolare architettura (e quindi con un certo set di istruzioni) su un sistema di elaborazione dotato di un diverso insieme di istruzioni. Vengono emulate interamente le singole istruzioni dell'architettura ospitata, consentendo completa interoperabilità tra ambienti eterogenei. Tramite l'emulazione, sistemi operativi o applicazioni pensati per determinate architetture, possono eseguire senza essere modificati, su architetture completamente differenti.\\\n**Vantaggi**: interoperabilità tra ambienti eterogenei.\\\n**Svantaggi**: problemi di efficienza (basse performance).\\\nNel tempo questo approccio si è ramificato seguendo due strade: interpretazione e ricompilazione dinamica.\n\n#### Interpretazione\nConsiste nella lettura di ogni singola istruzione del codice macchina che dev'essere eseguito e nell'esecuzione di più istruzioni sull'host virtualizzante per ottenere semanticamente lo stesso risultato.\\\n**Vantaggi**: è un metodo generale e potente che presenta una grande flessibilità nell'esecuzione perché consente di emulare e riorganizzare i meccanismi propri delle varie architetture.\\\n**Svantaggi**: produce un sovraccarico generalmente elevato poiché possono essere necessarie molte istruzioni dell'host per interpretare una singola istruzione sorgente.\n\n#### Compilazione Dinamica\nInvece una singola istruzione del sistema ospitato, vengono letti interi blocchi di istruzioni, che vengono tradotti (per la nuova architettura), ottimizzati e messi in esecuzione.\\\n**Vantaggi**: migliori prestazioni rispetto al metodo precedente, in quanto si leggono interi blocchi di codice, che vengono tradotti ed ottimizzati, consentendo di sfruttare tutte le possibilità offerte dalla nuova architettura; inoltre, le parti di codice usate frequentemente possono essere bufferizzate per evitare di doverle ricompilare in seguito.\nTutti i più noti emulatori utilizzano questa tecnica per implementare l'emulazione.\n\n### Tipi (Livelli) di Virtualizzazione\n- Livello applicativo - applicazioni virtuali / supporto a tempo di esecuzione (es: JVM, .NET CLR)\n- Livello di librerie (API a livello utente) - librerie virtuali (es: WINE, WABI, vCUDA)\n- Livello di Sistema Operativo - container (Jail, Virtual Environment, Docker)\n- Livello di **Astrazione Hardware** (HAL) - **macchine virtuali** (VMware, Virtual PC, Xen, User mode Linux). Questo è il tipo di virtualizzazione che astrae l'hardware ed è quello che ci interessa maggiormente in questo corso. Al contrario dei container, le VM non condividono lo stesso SO.\n- Livello di Instruction Set Architecture(ISA) - ISA Virtuale (Bochs, QEMU)\n\n### Cenni Storici\nLa virtualizzazione non è un concetto nuovo, bensì nasce negli anni '60 coi sistemi CP/CMS di IBM, dove il Control Program (CP) esegue direttamente sull'hardware svolgendo il ruolo di VMM ed il Conversational Monitor System (CMS) è il sistema operativo, replicato per ogni VM. Con la diffusione del consolidamento dell'hardware, si è passati dal paradigma \"one application, one server\" (tipico degli anni '80/'90, dovuto al crollo dei costi dell'hardware), ad avere, dagli anni 2000, un unico server bello grosso e potente, su cui installare 20/30 VM, ciascuna delle quali svolge un certo servizio: una soluzione molto più razionale, in quanto avere un numero di macchine fisiche ristrette permette di semplificare la configurazione, la gestione e la manutenzione. Per poi arrivare negli anni 2010 al Cloud Computing.\n\n### Vantaggi della Virtualizzazione\nLa virtualizzazione comporta numerosi vantaggi:\n- possibilità di avere più SO, anche differenti, sulla stessa architettura fisica;\n- isolamento degli ambienti d'esecuzione, utile specialmente per eseguire e testare software dalla sicurazza e affidabilità non certa (nel caso peggiore la singola VM va in crash);\n- abbattimento dei costi hardware, in quantosi possono concentrare più macchine (es. server) su un'unica architettura hardware, ed abbattimento dei costi di amministrazione;\n- gestione facilitata delle macchine (creazione, installazione -esistono template già preimpostati-, amministrazione, migrazione \"a caldo\", possibilità di adottare politiche di bilanciamento del carico e robustezza -disaster recovery-)\n\n### Realizzazione del VMM\nIl VMM generalmente deve fornire ad ogni VM le risorse che gli servono per funzionare (CPU, memoria, dispositivi I/O).\nI requisiti fondamentali sono i tre seguenti:\n- l'ambiente d'esecuzione fornito dev'essere identico a quello della macchina reale (come se non fosse un sistema virtualizzato, ma girasse direttamente sull'architettura hardware);\n- dev'essere garantita un'elevata efficienza (che sia accettabile) nell'esecuzione dei programmi;\n- dev'essere garantita la stabilità e la sicurezza dell'intero sistema.\nDue concetti molto importanti (che fungono anche da parametri per classificarlo) nella realizzazione del VMM sono: il **livello**, ovvero dove è collocato il VMM (può essere un *VMM di sistema* o un *VMM ospitato*); la **modalità di dialogo**, ovvero il modo in cui il VMM accede alle risorse (*virtualizzazione pura* o *paravirtualizzazione*)\n\nIn un sistema di virtualizzazione esistono due tipi di \"componenti\": l'**host** è la piattaforma sulla quale si realizzano le VM, ovvero il livello sottostante che comprende la macchina fisica ed il VMM; il **guest** è la VM vera e propria che comprende il Sistema Operativo e le applicazioni.\n\n#### VMM di Sistema\nSi trova direttamente sopra l'hardware e consiste in un Sistema Operativo molto leggero che realizza le funzionalità di virtualizzazione (es: kvm, xen). A meno che non ci sia abbastanza spazio libero sul disco e vi sia la possibilità di impostare un multiboot, per installare un VMM di sistema è necessario eliminare il Sistema Operativo preesistente.\n\n\u003cimg width=\"60%\" src=\"gfx/01%20-%20Virtualizzazione/VMM%20di%20Sistema.png\" alt=\"VMM di Sistema\"/\u003e\n\n#### VMM Ospitato\nViene installato come una normale applicazione sul Sistema Operativo preesistente, opera nello spazio utente ed accede all'hardware tramite le system call del SO (es. VirtualBox). È più semplice da installare e per la gestione delle periferiche può fare riferimento al Sistema Operativo sottostante, ma ha performance peggiori.\n\n\u003cimg width=\"50%\" src=\"gfx/01%20-%20Virtualizzazione/VMM%20Ospitato.png\" alt=\"VMM Ospitato\"/\u003e\n\n```\nNB: d'ora in poi faremo sempre riferimento a VMM di sistema.\n```\n\n#### Ring di Protezione\nL'architettura delle CPU prevede almeno due livelli di protezione (0 \"modi di esecuzione\"): supervisore/kernel (livello 0) e utente (livello \u003e0). Ogni ring corrisponde ad una diversa modalità di funzionamento del processore:\n- a livello 0 è possibile eseguire istruzioni privilegiate della CPU;\n- a livello superiore a 0 non possono essere eseguite.\n\nAlcuni programmi, come il kernel del SO, sono progettati per eseguire nel ring 0 (in cui si ha il pieno controllo dell'hardware).\nIn un sistema virtualizzato, il VMM dev'essere l'unica componente in grado di mantenere il pieno controllo dell'hardware (di conseguenza si troverà a ring 0, mentre le VM a ring \u003e0).\nMa nella VM c'è il Sistema Operativo, il cui kernel non può eseguire a livello 0 come dovrebbe. Di conseguenza sorgono due principali problemi: *ring deprivileging* e *ring compression*.\n\n##### Ring Deprivileging\nIl SO della VM si trova ad eseguire in un ring che non gli è proprio e le istruzioni privilegiate richieste dal sistema operativo nell'ambiente guest non possono essere eseguite.\nPossibile soluzione **trap \u0026 emulate**: se il guest tenta di eseguire un'istruzione prvilegiata (ad esempio 'popf', ovvero la disabilitazione delle interruzioni), la CPU lancia un'eccezione, che viene rilevata dal VMM (trap), al quale trasferisce il controllo; dopodiché il VMM controlla la correttezza dell'operazione e ne emula (emulate) il comportamento.\n```\nNB: se la popf potesse essere eseguita direttamente sul processore (a ring 0), verrebbero\ndisabilitati gli interrupt per tutto il sistema ed il VMM non potrebbe riguadagnare il \ncontrollo della CPU, mentre il comportamento desiderato sarebbe che gli interrupt venisse-\nro sospesi solo per la VM in questione.\n```\n\n##### Ring Compression\nSe ad esempio l'architettura ha solo 2 ring, poiché il primo (0) è assegnato al kernel del Sistema Operativo, applicazioni e SO della macchina virtuale eseguono allo stesso livello, con conseguente mancanza di isolamento e protezione.\n\n##### Ring Aliasing\nAlcune istruzioni non privilegiate, eseguite a livello user, permettono di accedere in lettura ad alcuni registri la cui gestione dovrebbe essere riservata al VMM, con conseguenti possibili inconsistenze. Ad esempio, il registro CS contiene il livello di privilegio corrente (se la VM pensa di essere in un certo ring, ma leggendo lo stato del registro vede che è sbagliato, potrebbero esserci dei problemi).\n\n#### Supporto Hardware alla Virtualizzazione\nL'architettura della CPU si dice **naturalmente virtualizzabile** (o con supporto nativo alla virtualizzazione) se prevede l'invio di trap allo stato supervisore (0) per ogni istruzione privilegiata invocata da un ring \u003e0. In questi casi è possibile realizzare un approccio \"trap \u0026 emulate\" e si ha supporto nativo all'esecuzione diretta.\nTuttavia, non tutte le architetture sono naturalmente virtualizzabili (es. Intel IA32) e alcune istruzioni privilegiate non provocano una trap, anzi, in alcuni casi causano il crash del sistema.\n\n#### Realizzazione del VMM in Architetture Non Virtualizzabili\nNel caso in cui un processore non fornisca supporto nativo alla virtualizzazione, per la realizzazione del VMM è necessario ricorrere a soluzioni software. Alcune possibili sono: *fast binary translation*, *paravirtualizzazione*.\n\n##### Fast Binary Translation (FTB)\nSfrutta un'idea simile alla compilazione dinamica: il VMM scansiona il codice dei SO guest prima dell'esecuzione, per sostituire a runtime i blocchi contenenti istruzioni privilegiate con blocchi equivalenti dal punto di vista funzionale, ma che contengano invece chiamate al VMM. I blocchi tradotti vengono salvati in cache per eventuali riutilizzi futuri.\\\n**Vantaggi**: ogni VM è una esatta replica della macchina fisica, dunque è possibile installare gli stessi SO di architetture senza virtualizzazione nativa.\\\n**Svantaggi**: la traduzione dinamica è costosa.\n\n\u003cimg width=\"40%\" src=\"gfx/01%20-%20Virtualizzazione/Fast%20Binary%20Translation.png\" alt=\"Fast Binary Translation\"/\u003e\n\n##### Paravirtualizzazione\nÈ l'approccio più diffuso al giorno d'oggi, oltre a FBT. Il VMM (hypervisor) offre ai SO guest un'interfaccia virtuale (hypercall API) alla quale i SO guest devono fare riferimento per avere accesso alle risorse. Le istruzioni non privilegiate vengono eseguite direttamente dai SO guest, mentre per le istruzioni privilegiate, eseguono delle hypercall. ```NB: così come il *Sistema* Operativo fornisce delle *system* call, l'*Hyper*visor fornisce delle *hyper* call.``` Ciò consente  di eseguire istruzioni privilegiate chiamando direttamente la relativa hyper call, senza dover generare interrupt al VMM. Xen utilizza questa tecnica.\\\n**Vantaggi**: la struttura del VMM è semplificata e si ottengono prestazioni migliori, in quanto non si ha il ritardo dovuto alla compilazione di FTB.\\\n**Svantaggi**: vi è la necessità di porting dei SO guest (i kernel devono essere resi compatibili, soluzione che è preclusa a molti sistemi operativi proprietari, fra cui Windows).\n\n\u003cimg width=\"34%\" src=\"gfx/01%20-%20Virtualizzazione/Paravirtualizzazione.png\" alt=\"Paravirtualizzazione\"/\u003e\n\n### Architetture virtualizzabili\nCon **virtualizzazione pura**, si intende un'architettura che non costringe l'amministratore (o l'utente) a installare nella macchina virtuale un kernel modificato (che non sia l'originale del Sistema Operativo), dunque è il caso di architetture con supporto nativo alla virtualizzazione, ma anche FTB, in quanto anche lì non c'è bisogno di modificare il kernel.\\\n**Vantaggi**: non c'è ring compression né ring aliasing (il guest esegue in un ring separato -intermedio- diverso da quello delle applicazioni; il ring deprivileging è risolto tramite trap \u0026 emualte (gestione tramite VMM); trasparenza (l'API presentata dall'hypervistor è la stessa offerta dal processore).\nProdotti virtualizzabili: xen, vmware, kvm.\n\n#### Protezione nell'architettura x86\n**Prima generazione**: non avevano nessuna capacità di protezione e non facevano distinzione tra SO e applicazioni, facendo girare entrambe con i medesimi privilegi. Il problema principale era dato dal fatto che, in questo modo, le applicazioni potevano accedere direttamente ai sottosistemi di I/O, allocare memoria senza alcun intervento del SO, con conseguenti problemi di sicurezza e stabilità (es. MS-DOS).\n\n**Seconda generazione**: viene introdotto il concetto di protezione, con la distinzione tra SO, che possiede controllo assoluto sulla macchina fisica sottostante, e le applicazioni, che possono interagire con le risorse fisiche solo facendone richiesta al SO (concetto di ring di protezione).\n\n**Registro CS**: i due bit meno significativi vengono riservati per rappresentare il Livello Corrente di Privilegio (CPL) =\u003e 4 possibili ring, a priorità crescente (0 maggiori privilegi, destinato al kernel del SO, ... , 3 minori privilegi, destinato alle applicazioni utente).\nIn questo modo si ottiene **protezione della CPU**: non è permesso a ring diversi dallo 0 di eseguire le istruzioni privilegiate, che son destinate solo al kernel del SO, in quanto considerate critiche e potenzialmente pericolose. Una qualsiasi violazione può provocare un'eccezione, gestita immediatamente dal SO, che può reagire, ad esempio, terminando l'applicazione in esecuzione.\n\n**Segmentazione**: ogni segmento è rappresentato da un descrittore (in una tabella) in cui sono indicati il Livello di Protezione richiesto (PL) ed i permessi di accesso (r, w, x).\nIn questo modo si ottiene **protezione della memoria**: una violazione dei vincoli di protezione provoca un'eccezione. Ciò accade, ad esempio, se il valore di CLP è maggiore del PL del segmento di codice contenente l'istruzione invocata.\n\n\n#### Funzionamento dei VMM nell'architettura x86 classica\nAnche in questo caso è presente il problema del ring deprivileging, in quanto viene dedicato il ring 0 alla VMM e conseguentemente i SO guest vengono collocati in ring a privilegi ridotti. Vengono comunemente utilizzate 2 tecniche:\n- **0/1/3**: VMM (0), SO (1), applicazioni (3). Il SO viene spostato dal ring 0 (dove nativamente dovrebbe trovarsi) al ring 1, lasciando le applicazioni al ring 3, mentre al ring 0 viene installato il VMM;\n- **0/3/3**: VMM (0), SO (3), applicazioni (3). Il SO viene spostato direttamente al ring 3, dove si trovano anche le applicazioni, mentre sul ring 0 viene installato il VMM. In questa modalità non è possibile generare eccezioni, quindi devono essere intrapresi meccanismi molto sofisticati con un controllo continuo da parte del VMM.\n\n### Gestione di VM\nIl compito fondamentale del VMM è quello di gestire le VM (creazione, accensione/spegnimento, eliminazione, migrazione live).\n\n#### Stati di una VM\nUna macchina virtuale può trovarsi nei seguenti stati:\n- **running** (o attiva): la macchina ha superato la fase di bootstrap ed è stata caricata nella *RAM* del server su cui è allocata;\n- **inactive** (powered off): la macchina è spenta ed è rappresentata nel *file system* tramite un file immagine;\n- **paused**: la macchina è in *attesa* di un evento (es: I/O richiesto da un processo nell'ambiente guest);\n- **suspended**: lo stato correnteviene salvato nel file system dal VMM. L'uscita da tale stato avviene tramite un'operazione di *resume*.\n\nsuspend: il VMM salva lo stato della VM in memoria secondaria, mettendola in stand by;\nresume: il VMM ripristina lo stato della VM in memoria centrale (lo stato è quello in cui si trovava quando è stata sospesa). Questa operazione può avvenire su un nodo diverso da quello della suspend.\n\n\u003cimg width=\"50%\" src=\"gfx/01%20-%20Virtualizzazione/Stati%20di%20una%20VM.png\" alt=\"Stati di una VM\"/\u003e\n\n#### Migrazione di una VM\nÈ una funzionalità necessaria soprattutto nei datacenter, per una gestione agile delle VM, a fronte di:\n- variazioni dinamiche del carico (**load balancing**, consolidamento);\n- **manutenzione \"online\"** dei server, senza dover interrompere i servizi forniti;\n- gestione finalizzata al **risparmio energetico**;\n- **tolleranza ai guasti** e disaster recovery.\n\nStrumento fondamentale per queste procedure è la migrazione, ovvero la possibilità di muovere VM tra server.\n**Migrazione live**: possibilità di spostare una VM da un server fisico ad un altro, senza doverla spegnere. È desiderabile minimizzare il downtime, il tempo di migrazione ed il consumo di banda.\n\n\u003c!-- Lezione 2021/09/28 --\u003e\n\u003c!--\nRIPASSINO\nAvevamo introdotto il tema della migrazione live, meccanismo che consente lo spostamento della VM da un nodo fisico ad un altro. Questo spostamento, se fatto in modo \"live\", significa che può essere eseguito senza neanche spegnere la macchina in questione.\nIn questo modo si ha un downtime davvero trascurabile (poco più di 100ms)\n\nLa capacità/caratteristica di indipendenza e isolamento dall'ambiente fisico è il vantaggio principale che ci consente di realizzare in modo molto semplice dal punto di vista tecnico, la migrazione live, ovvero suspend su un nodo e resume su un altro nodo.\n\nFra gli obbiettivi, sicuramente uno prioritario è minimizzare il downtime, in quanto se la macchina fornisce un servizio, vogliamo che questo rimanga disponibile per il maggior tempo possibile e dunque, appunto, che il downtime venga minimizzato.\nAltri aspetti da tenere in considerazione:\n- ridurre al minimo il tempo di migrazione, come tempo complessivo che richiede la migrazione;\n- occupare meno banda possibile.\n\nNaturalmente ci sono dei vantaggi nella realizzazione della migrazione se le architetture alle quali stiamo facendo riferimento hanno file system in comune (es. cluster), ovvero condividono gli stessi dischi.\n--\u003e\n#### Soluzione: precopy\nLa soluzione più diffusa al giorno d'oggi si basa su un meccanismo di precopia, che viene attuata in una serie di passi:\n1. **Pre-migrazione**: fase iniziale in cui si capisce quali sono i nodi interessati, ovvero si individua la VM da migrare (nodo A) e l'host di destinazione (nodo B);\n2. **Reservation**: viene riservato un contenitore vuoto nel server di destinazione (reservation del posto per la macchina da migrare);\n3. **Pre-copia iterativa delle pagine**: la VM da migrare chiaramente avrà un file immagine (tipicamente un file di stato mappato sui registri CPU). In questa fase viene eseguita una copia nell'host B di tutte le pagine allocate in memoria sull'host A. Poiché le pagine in memoria, soprattutto se la VM è in esecuzione, possono variare, ovviamente non è detto che vengano copiate una volta sola. Alla successiva iterazione, vengono copiate solo le pagine modificate (*dirty pages*), fino a quando il numero di queste è inferiore ad una certa soglia data;\n4. **Sospensione della VM**: raggiunta la soglia (quando rimangono poche pagine), si applica la suspend sulla macchina d'origine (in seguito avverrà una resume sulla macchina di destinazione);\n5. **Commit**: la copia della VM sul nodo di destinazione è completa, dunque si può procedere con una commit (ovvero ci si affranca completamente dal nodo di origine, dal quale la VM viene eliminata);\n6. **Resume**: viene eseguita la resume sul nodo B, in cui si trova una macchina pronta a ripartire, completa sia come immagine sul file system, sia come stato presente nei registri.\n\nCon questa modalità, si ha downtime solo durante la copia delle ultime dirty pages, ovvero quando si è raggiunta la soglia preimpostata.\n```\nNB: chiaramente la prima iterazione della precopia è quella che richiede più tempo,\nquelle successive ne richiedono meno perché salvano solo le pagine modificate.\n```\nSebbene la precopia sia la modalità oggi più diffusa, ne esistono anche altre, ad esempio *post-copy*, in cui la macchina viene sospesa e vengono copiate (non iterativamente) pagine e stato. Così facendo si ottiene un tempo totale di migrazione più basso, ma un downtime dei servizi forniti dalla VM molto più elevato.\n\n### XEN\nXEN è un progetto che nasce in ambito accademico a Cambridge. Nasce come hypervisor (VMM) paravirtualizzato, richiede che le VM che girano sopra xen abbiano un kernel adattato all'interfaccia che xen offre ai propri utilizzatori. Per quanto riguarda il porting di Linux ha coinvolto circa 3000 linee di codice del kernel, per adattarlo in modo che potesse dialogare con le API di XEN.\nDal punto di vista commerciale ha limitato la gamma di kernel installabili, per quanto riguarda i SO proprietari, nonostante un tentativo di porting dei Sistemi Operativi (ad esempio Windows XP, che non è stato portato a termine).\n\n#### Architettura\nXEN è costituito da un VMM *hypervisor*, che si appoggia direttamente sull'hardware (virtualizzazione di sistema - quindi è necessario avere spazio e in caso togliere il SO preesistente) e si occupa della virtualizzazione della CPU, della memoria e dei dispositivi per ogni VM. In XEN le macchine virtuali vengono chiamate *domain* e su ogni sistema XEN c'è una VM speciale chiamata *domain 0* che è privilegiata: a livello architetturale è come tutte le altre ma, tramite un'interfaccia di controllo fornita da XEN, può amministrare tutto il sistema. Questa interfaccia è accessibile solo dal domain 0, ed è separata dall'hypervisor stesso, scelta che permette di ottenere una separazione dei meccanismi dalle politiche: all'interno delle applicazioni che consento la configurazione ed il controllo del sistema abbiamo le politiche (espresse dall'utente), che vengono poi implementate e messe in pratica dall'hypervisor. Infatti, tipicamente nel domain 0 girano applicazioni che consentono all'amministratore di configurare il sistema virtualizzato e operando sulla console di questa VM è possibile creare una VM guest (di domain U - utente), eliminarla, migrarla, ecc.\n\n#### Realizzazione\nUn VMM assomiglia per certi versi al kernel di un SO: deve gestire in modo appropriato l'hardware e fornire un accesso particolare agli utilizzatori (che nel caso di un sistema virtualizzato non sono gli utenti ma le VM.\nOgni VM vede una *CPU* come se fosse a lei esclusivamente dedicata, quando in realtà non è così: le risorse vengono condivise grazie all'attività dell'hypervisor tra tutti gli utilizzatori secondo politiche particolari (ad esempio per quanto riguarda la CPU l'hypervisor dovrà mettere in atto politiche di scheduling particolari).\nStessa cosa vale per la *memoria*, anch'essa dev'essere in qualche modo messa a disposizione per gli utilizzatori dal VMM, che deve garantire i criteri di sicurezza opportuni.\nAltro compito importantissimo del VMM è quello della gestione dei *dispositivi* (quindi I/O).\n\nQualche cenno sulle caratteristiche di XEN: noi facciamo riferimento a XEN \"paravirtualizzato\": in questi sistemi necessario separare il kernel dalla macchina virtuale e dalle applicazioni, in quanto XEN adotta una configurazione dei ring 0/1/3 (VMM esegue a ring 0, Sistemi Operativi a ring 1, le applicazioni a ring 3, così non si ha ring compression).\nLe app possono utilizzare le system call per comunicare col sistema operativo, i sistemi operativi possono comunicare col VMM tramite delle hyper calls (sono come system call fornite dal nucleo dell'hypervisor per permettere agli SO di eseguire istruzioni particolari).\n\n#### Gestione della Memoria e Paginazione\nI SO guest gestiscono la memoria virtuale mediante la paginazione tradizionale: le page table delle VM vengono mappate in memoria fisica da XEN, il quale è l'unico a potervi accedere in *scrittura*, su richiesta delle VM. L'accesso in *lettura*, invece, è permesso anche ai sistemi operativi ospitati.\n\n##### Protezione: Memory Split\nCom'è strutturato lo spazio di indirizzamento delle singole VM guest? Si adotta un principio di **memory split**.\n```\nNB: Consideriamo sempre il parallelo con sistema non virtualizzato/sistema virtualizzato:\nin un sistema virtualizzato, ogni utilizzatore è una VM, quindi ogni entità che si inter-\nfaccia col VMM (equivalente del kernel) è una VM. Così come accade nei sistemi non virtua-\nlizzati, in cui ogni processo ha un utilizzatore e un suo spazio di indirizzamento, anche\nnei sistemi virtualizzati ogni VM ha un suo spazio di indirizzamento virtuale (perché sia-\nmo in presenza di memoria virtuale).\n```\nPer motivi di efficienza, poiché chiaramente nella commutazione tra una VM e l'altra c'è problema di reperire il codice di XEN, lo spazio di indirizzamento di ogni VM è strutturato a \"segmenti\": nei primi 64MiB viene allocato XEN (ring 0), poi c'è una parte relativa al Kernel del SO guest (ring 1), poi c'è lo spazio utente, che verrà utilizzato dalle applicazioni (ring 3).\\\nI VM guest si occupano delle politiche di gestione della paginazione, mentre i meccanismi, ovvero l'effettiva implementazione della paginazione, sono compito del VMM, in quanto il kernel del SO guest, non può occuparsene, non essendo nel ring privilegiato 0. Ciò garantisce maggiore protezione in quanto si ha separazione tra politiche (a carico dei guest - alto livello) e meccanismi (a carico del VMM - basso livello).\nCon questa soluzione, quando viene creato un nuovo processo nello spazio del guest, fra le altre cose dev'essere creata una Tabella delle Pagine (PT) associata a tale processo. Ovviamente, poiché come detto tale operazione non può essere fatta dal kernel del sistema operativo che ospita quel processo (in quanto si trova a ring 1), dev'essere fatta da qualcun'altro. Quindi ciò che succede è che il guest richiede una nuova PT all'hypervisor, il quale la crea e vi aggiunge anche lo spazio riservato a XEN; così facendo XEN registra la tabella e acquisisce il diritto di scrittura esclusivo (i guest potranno solo leggerle), e ogni volta che il guest di tale TP dovrà aggiornarla, proverà a scriverci generando un trap *protection fault*, che verrà catturata e gestita da XEN, permettendogli di verificare la correttezza della richiesta ed aggiornare effettivamente, in seguito, la Tabella delle Pagine.\n\n##### Protezione: Balloon Process\nPer com'è gestita la protezione in XEN, l'unica componente capace di allocare memoria è il VMM (ring 0), ma può farlo solo in seguito a richeiste delle VM guest, in quanto come detto, le politiche si trovano in alto livello (ring 3), mentre i meccanismi a basso livello (ring 0). Però, in alcuni casi (es: attivazione nuova VM, operazione per la quale serve acquisire memoria necessaria per allocare lo spazio di indirizzamento di quella macchina virtuale), può essere necessario al VMM dover ottenere nuove pagine. Questa possibilità, ovvero di richiedere pagine, il VMM non ce l'ha. Può farlo solo in seguito a richieste da parte dei guest. Per risolvere questo problema, su XEN è stato adottata una soluzione (peculiare per la paravirtualizzazione) chiamata **balloon process**: in ogni guest c'è un processo in costante esecuzione, che è in grado di dialogare direttamente con l'hypervisor. In caso di necessità di pagine, il VMM può chiedere a tali processi di \"gonfiarsi\", ovvero richiedere al proprio SO ulteriori pagine. Tale richiesta provoca l'allocazione di nuove pagine al balloon process che, una volta ottenute, le cede al VMM.\n\n#### Cenni su Virtualizzazione della CPU\nIl VMM definisce un'architettura virtuale simile a quella del processore, nella quale però, le istruzioni privilegiate sono sostituite da opportune hypercalls:\n\nIl VMM si occupa dello scheduling delle VM, seguendo un algoritmo molto generale (in grado di soddisfare dei vincoli temporali molto stringenti) chiamato *Borrowed Virtual Time*, che si basa sulla nozione di virtual-time: è un tempo che va avanti solo fintanto che la VM è attiva, ovvero se si trova in uno stato di sospensione il tempo si ferma e riprende quando viene attivato. Xen adotta due clock, uno relativo al real-time, l'altro al virtual-time.\n\n#### Virtualizzazione dei dispositivi (I/O)\nLe VM devono poter accedere ai dispositivi che sono disponibili a livello hardware. La scelta di XEN è quella, ovviamente, di virtualizzare l'interfaccia di ogni dispositivo, ma farlo tramite due tipi di driver: *back-end driver* e *front-end driver*.\\\n**Back-end driver** è il driver vero e proprio, che permette, tramite un'interfaccia del VMM chiamata *Safe Hardware Interface*, di comunicare ed utilizzare il dispostivo collegato a livello hardware. Tipicamente viene installato all'interno di una VM particolare che è sempre ancorata al nodo fisico (dominio 0 - solitamente qui vengono installati tutti i driver di ogni dispositivo presente connesso a livello fisico in quel nodo).\\\n**Front-end driver** è un driver \"astratto\", generico, non riferito adun dispositivo particolare, che viene installato tipicamente nel kernel del SO di una VM guest. Questo driver, all'occorrenza si collega al back-end driver specifico.\n```\nNB: non c'è niente che vieti di installare un back-end direttamente su una VM di domain U,\nma può convenire concentrarli tutti nel domain 0, sia perché siamo certi che quella macchi-\nna non si sposterà mai da lì, essendo ancorata all'hardware, sia per motivi di portabilità.\n```\n\n\u003cimg width=\"50%\" src=\"gfx/01%20-%20Virtualizzazione/Driver.png\" alt=\"Front-end and Back-end Drivers\"/\u003e\n\nOvviamente, per consentire la comunicazione tra back-end driver e front-end driver, serve un meccanismo che gestica le richieste. Questo viene realizzato tramite delle strutture chiamate asynchronous I/O rings (buffer FIFO circolari) in cui ogni elemento è una specie di descrittore che rappresenta una particolare richiesta. Le richieste di accesso ad un particolare device vengono fatte dal guest tramite il front-end che deposita la richiesta nel ring relativo, mentre dall'altra parte c'è il back-end che le preleva e le gestisce.\n\n\u003cimg width=\"50%\" src=\"gfx/01%20-%20Virtualizzazione/Asynchronous%20IO%20Ring.png\" alt=\"Structure of Asynchronous I/O Rings\"/\u003e\n\n**Vantaggi**: il driver viene scorporato in due parti, svingolando la VM dal particolare server fisico in cui risiede (il front-end driver della VM rimane lo stesso anche se questa viene spostata su un altro nodo), garantendo *portabilità*; inoltre, mantenendo i driver fuori dall'hypervisor, si ha che esso è più semplificato e leggero.\\\n**Svantaggi**: il meccanismo di comunicazione fra i due tipi di driver appesantisce l'accesso ai dispositivi.\n\n#### Gestione delle Interruzioni\nLa gestione delle interruzioni viene virtualizzata in modo molto semplice: ogni interruzione viene gestita direttamente dal SO guest, eccezione fatta per la *page fault*, che richiede accesso al registro CR2, il quale contiene l'indirizzo che ha provocato il page fault. Poiché tale registro è accessibile solo a ring 0, la gestione del page fault deve coinvolgere il VMM: la routine di gestione eseguita da XEN legge CR2, lo copia in una variabile nello spazio del SO ospitato, al quale viene restituito il controllo per poter gestire il page fault.\n\n#### Migrazione Live\nIl comando di migrazione viene eseguito da un demone di migrazione che si trova nel domain 0 del server di origine della macchina da migrare. La soluzione è basata sulla precopy e le pagine da migrare vengono compresse per ridurre l'occupazione di banda.\n\n## 02 - Protezione [![Vai al Capitolo Singolo](gfx/icons/file-moved_dark.svg#gh-light-mode-only)](capitoli/02%20-%20Protezione.md#gh-light-mode-only \"Vai al Capitolo Singolo\") [![Vai al Capitolo Singolo](gfx/icons/file-moved_light.svg#gh-dark-mode-only)](capitoli/02%20-%20Protezione.md#gh-dark-mode-only \"Vai al Capitolo Singolo\")\n\n**Sicurezza**: riguarda l'insieme delle *tecniche per regolamentare l'accesso* degli utenti al sistema di elaborazione. La sicurezza impedisce accessi non autorizzati al sistema e i conseguenti tentativi dolosi di alterazione e distruzione dei dati. La sicurezza riguarda l'interfaccia del sistema verso il mondo esterno. Le tecnologie di sicurezza di un sistema informatico realizzano meccanismi per l'identificazione, l'autenticazione e l'autorizzazione di utenti \"fidati\".\\\n**Protezione**: *insieme di attività volte a garantire il controllo dell'accesso* alle risorse logiche e fisiche da parte degli utenti autorizzati all'uso di un sistema di calcolo. Rispetto alla sicurezza ha un campo d'azione più interno al sistema. Per rendere un sistema \"sicuro\" è necessario stabilire per ogni utente autorizzato quali siano le risorse a cui può accedere e con quali operazioni può farlo. Ciò viene stabilito dal sistema di protezione tramite le tecniche di controllo degli accessi.\n\n### Protezione: Modelli, Politiche e Meccanismi\nIn un sistema il controllo degli accessi si esprime tramite la definizione di tre livelli concettuali:\nmodelli, politiche e meccanismi.\n\n#### Modelli\nUn modello di protezione definisce i *soggetti*, gli *oggetti* ai quali i soggetti hanno accesso ed i *diritti* di accesso:\n- **soggetti** - rappresentano la parte attiva di un sistema, ovvero le entità che possono richiedere l'accesso alle risorse. Ad esempio: gli utenti o i processi che eseguono per conto degli utenti;\n- **oggetti** - costituiscono la parte passiva di un sistema, ovvero le risorse fisiche e logiche alle quali si può accedere e su cui si può operare. Ad esempio i file, o i processi intesi come risorsa (solitamente in un sistema di protezione i soggetti sono gli utenti, e i processo sono oggetti);\n- **diritti di accesso** - sono le operazioni con le quali è possibile operare sugli oggetti. Ad esempio, in Linux i diritti di accesso sono lettura, scrittura, esecuzione.\n```\nNB: un soggetto può avere diritti di accesso anche per altri soggetti (es: processo che\ncontrolla un altro processo.\n```\nAd ogni soggetto è associato un dominio, che rappresenta l'*ambiente di protezione* nel quale il soggetto esegue e specifica i diritti di accesso posseduti da tale soggetto nei confronti di ogni risorsa.\nUn dominio di protezione è unico per ogni soggetto, mentre un soggetto (ad esempio un processo) può cambiere dominio durante la sua esecuzione.\n\n#### Politiche\nLe politiche di protezione definiscono le regole con le quali i soggetti possono accedere agli oggetti. Mentre il modello è qualcosa di insito nel sistema, le politiche generalmente vengono scelte da chi opera su quel sistema. Si classificano in 3 diverse tipologie:\n- **DAC** (Discretional Access Control) - il creatore di un oggetto controlla i diritti di accesso per quell'oggetto (tipologia adottata da UNIX, che fornisce un meccanismo per definire e interpretare per ciascun file i 3 bit di read, write ed execute, per il proprietario, il gruppo e gli altri). La definizione delle politiche è decentralizzata.\n- **MAC** (Mandatory Access Control) - i diritti d'accesso vengono definiti in modo centralizzato. Questa soluzione viene utilizzata in sistemi di alta sicurezza per garantire assoluta confidenzialità e i diritti vengono gestiti da un'entità centrale.\n- **RBAC** (Role Based Access Control) - ad un ruolo vengono assegnati specifici diritti di accesso sulle risorse. Gli utenti possono appartenere a diversi ruoli. I diritti attribuiti ad ogni ruolo vengono assegnati in modo centralizzato.\n**Principio del Privilegio Minimo** (o POLA - Principle Of Least Authority): ad ogni soggetto sono garantiti i diritti di accesso solo agli oggetti strettamente necessari per la sua esecuzione. Questa è una caratteristica desiderabile per tutte le politiche di protezione.\n\n#### Meccanismi\nI meccanismi di protezione sono gli strumenti messi a disposizione dal sistema di protezione per imporre una determinata politica.\nPrincipi di realizzazione:\n- **flessibilità del sistema di protezione**: i meccanismi di protezione devono essere sufficientemente generali per consentire per consentire l'applicazione di diverse politiche di protezione;\n- **separazione tra meccanismi e politiche**: la politica definisce *cosa va fatto* ed il meccanismo *come va fatto*. È desiderabile la massima indipendenza tra le due componenti.\n\n### Dominio di Protezione\nUn dominio definisce un insieme di coppie, ognuna contenente l'identificatore di un oggetto e l'insieme delle operazioni che il soggetto associato a tale dominio può eseguire su ciascun oggetto (diritti di accesso).\n\nEs: D(S) = {\\\u003co, diritti\\\u003e | o è un oggetto, diritti è un insieme di operazioni}\n\nOgni dominio è associato univocamente ad un soggetto, mentre un soggetto (ad esempio un processo) può eventualmente cambiare dominio durante la sua esecuzione; il soggetto può accedere solo agli oggetti definiti nel suo dominio, utilizzando i diritti specificati dal dominio.\n\nDomini disgiunti o con diritti di accesso in comune: esiste la possibilità per due o più soggetti di effettuare alcune operazioni comuni su un oggetto condiviso. Le operazioni vengono svolte dai processi che operano per conto di soggetti (a cui sono associati i domini).\n```\nNB: in ogni istante della sua esecuzione, il processo esegue in uno ed un solo dominio.\n```\n\n#### Associazione tra Processo e Dominio\nL'associazione tra processo e dominio può essere statica o dinamica.\\\n**Statica**: l'insieme delle risorse disponibili ad un processo rimane fisso durante il suo tempo di vita. Osservazioni: questo tipo di associazione non è adatta al Principio del Privilegio Minimo, in quanto l'insieme globale delle risorse che un processo potrà usare può non essere un'informazione disponibile prima della sua esecuzione; inoltre, l'insieme minimo di risorse necessarie ad un processo per garantire tale Principio, può cambiare in modo dinamico durante l'esecuzione.\\\n**Dinamica**: l'associazione tra processo e dominio varia durante l'esecuzione del processo. In questo modo si può mettere in pratica il *Principio del Privilegio Minimo*, in quanto in ogni sua fase di esecuzione il processo può acquisire diritti diversi (ovvero solo quelli strettamente necessari). Tuttavia in questo caso *occorre un meccanismo per consentire il passaggio da un dominio all'altro* del processo.\n\n##### Esempio di cambio di dominio\n**Standard dual mode** (kernel/user mode): ci sono due domini (ring) di protezione, quello dell'utente (user mode) e quello del kernel (monitor o kernel mode). Quando un processo deve eseguire un'istruzione privilegiata, chiama una system call ed avviene il cambio di dominio. Questo non realizza la protezione tra utenti, ma solo tra kernel e utente.\n\n**UNIX**: il dominio è associato all'utente. Ogni *processo* è caratterizzato dall'attributo UserID (UID). Il cambio di dominio corrisponde al cambio temporaneo di identità (UID) del processo.\nAd ogni *file* invece sono associati il proprietario (user-id) ed un bit di dominio (set-uid). Se il un file ha il bit set-uid settato, quando un utente B, diverso dal proprietario A di tale file, ne lancia l'esecuzione, al processo che esegue viene assegnato lo user-id dell'utente B. Così facendo il file entra nel dominio di B.\n\n### Matrice degli Accessi\nUn sistema di protezione può essere rappresentato a livello astratto utilizzando il modello della matrice degli accessi: tale matrice consente di rappresentare il modello e le politiche valide nel sistema considerato.\n- ogni riga rappresenta un soggetto (utente);\n- ogni colonna rappresenta un oggetto (risorsa, file)\n- ogni elemento rappresenta i diritti accordati ai soggetti sugli oggetti.\nLe informazioni contenute nella matrice possono variare nel tempo: le informazioni contenute nella matrice all'istante t rappresentano lo stato di protezione del sistema in t. La matrice degli accessi offre ai meccanismi di protezione le informazioni che consentono di verificare il rispetto dei vincoli di accesso. Il meccanismo associato al modello:\n- ha il compito di verificare se ogni richiesta di accesso che proviene da un processo (che opera in un determinato dominio) è consentita oppure no;\n- autorizza l'esecuzione delle richieste consentite e impedisce quelle vietate;\n- consente di modificare dinamicamente e in modo controllato il cambiamento dello stato di protezione.\n\n#### Verifica del Rispetto dei Vincoli di Accesso\nIl meccanismo consente di assicurare che un processo che opera nel dominio *Di* possa accedere solo agli oggetti specificati nella riga *i* e solo con i diritti di accesso indicati. Quando un'operazione M dev'essere eseguita nel dominio *Di* sull'oggetto *Oj*, il meccanismo consente di controllare che M sia contenuta nella casella *access(i,j)*. In caso affermativo l'operazione può essere eseguita, altrimenti viene restituito un errore.\n\n#### Modifica dello Stato di Protezione\nIn base alla politica di protezione adottata, lo stato di protezione può essere modificato da entità differenti:\n- nella politica DAC (es: sistemi UNIX-based) può essere modificato dai soggetti, ovvero gli utenti;\n- nella politica MAC può essere fatto solo dall'entità centrale.\n\n##### Modello Graham-Denning\nQuesto modello stabilisce quali sono i comandi che consentono una modifica dello stato di protezione, identificando 8 primitive:\n- create object, aggiunge una colonna;\n- delete object, rimuove una colonna;\n- create subject, aggiunge una riga;\n- delete subject, rimuove una riga;\n- read access right, legge il diritto d'accesso;\n- grant access right, assegna il diritto d'accesso;\n- delete access right, rimuove il diritto d'accesso;\n- transfer access right, propaga il diritto d'accesso.\n\n##### Propagazione dei Diritti di Accesso (Copy Flag)\nLa possibilità di copiare un diritto di accesso per un oggetto da un dominio ad un altro nella matrice di accesso è indicata con un asterisco * (*copy flag*).\nUn soggetto *Sa* può trasferire un diritto di accesso *a* (ad esempio 'read') per un oggetto *Ox* ad un altro soggetto *Sb* solo se *Sa* ha accesso a *Ox* con il diritto *a* e tale diritto ha il copy flag (ovvero solo se nella tabella delle matrici, l'elemento *Sa*\\\\*Ox* contiene *a*\\*, ad esempio read*)\n\n\u003cimg width=\"50%\" src=\"gfx/02%20-%20Protezione/Matrice%20degli%20Accessi%20Copy%20Flag.png\" alt=\"Matrice degli Accessi e Copy Flag\"/\u003e\n\nL'operazione di propagazione può essere realizzata in due modi:\n- **trasferimento** del diritto, il soggetto iniziale perde il diritto di accesso, che viene spostato al nuovo soggetto;\n- **copia** del diritto, il soggetto iniziale mantiene il diritto di accesso, \"duplicandolo\" al nuovo soggetto.\n\n\u003c!-- lezione 2021/09/29 --\u003e\n##### Diritto Owner\nIl diritto *owner* realizza il concetto di \"proprietario di una risorsa\" (oggetto). Il soggetto che possiede tale diritto di accesso, nei sistemi che lo prevedono, ha la possibilità di concedere/revocare un qualunque diritto di accesso sull'oggetto che gli appartiene (ovvero possiede il diritto owner su tale oggetto) ad un qualunque altro soggetto.\\\nIn una matrice degli accessi, ciò si traduce nella presenza, in ciascuna colonna, di una ed una sola cella nella quale è presente un diritto owner. Per ogni risorsa (dunque per ogni colonna) ci dev'essere un solo soggetto che ne è il proprietario. Ciò significa che tale soggetto ha un ruolo privilegiato nei confronti di quella risorsa ed è l'unico soggetto capace di revocare o concedere diritti di accesso su quella risorsa ad altri soggetti.\nAd esempio, se *S2* ha il diritto 'owner' su *O2* allora può revocare il diritto 'execute' su *O2* al soggetto *S1*, oppure anche a se stesso.\n\n\u003cimg width=\"50%\" src=\"gfx/02%20-%20Protezione/Matrice%20degli%20Accessi%20Owner.png\" alt=\"Matrice degli Accessi e Diritto Owner\"/\u003e\n\n##### Diritto Control\nIl diritto *control* permette di revocare un qualunque diritto di accesso, riferendosi non ad un oggetto ma ad un altro soggetto.\nSe la cella della colonna di un soggetto ha il diritto control, autorizza l'owner a modificare la riga associata a tale soggetto.\\\nAd esempio, se *S1* ha il diritto di 'control' su *S2* e *S2* ha il diritto di 'write' su *O3*, allora *S1* può revocare il diritto di write di *S2* su *O3*.\n\n\u003cimg width=\"50%\" src=\"gfx/02%20-%20Protezione/Matrice%20degli%20Accessi%20Control.png\" alt=\"Matrice degli Accessi e Diritto Control\"/\u003e\n\n```\nNB: In un sistema MAC, avremmo l'entità centrale che è l'unica autorizzata a stabilire\nche cosa si può o non si può fare sulle risorse del sistema. Questa autorità è un sog-\ngetto che ha il diritto di control su tutti gli altri soggetti (ha il potere assoluto,\nnel senso che può modificare il contenuto della riga associata ad ogni altro soggetto).\n```\n\nCopy flag, owner e control sono strumenti con cui possiamo *modificare* il contenuto della matrice degli accessi (possiamo aggiungere o togliere diritti nelle varie caselle). Se ci pensiamo bene, una riga della matrice altro non è che il dominio di protezione associato ad un soggetto.\n\n##### Diritto Switch\nUno dei modi possibili per garantire il rispetto del Principio del Privilegio Minimo è prevedere la possibilità di un cambio di dominio a runtime. Un processo che esegue nel dominio di un soggetto, se ha bisogno di diritti differenti, può spostarsi nel dominio specifico che gli garantisce questi diritti nuovi di cui ha bisogno.\\\nA tal proposito, esiste un diritto speciale chiamato *switch*: esercitando questo diritto, il processo che esegue nel dominio di un certo soggetto, può passare ad un nuovo dominio.\nAd esempio, se il soggetto *S2* ha bisogno del diritto 'write' sull'oggetto O3, ma possiede solo 'read', se possiede il diritto di 'switch' *S1* può passare nel dominio di *S1* per acquistare il diritto di 'write' e accedere a tale risorsa in scrittura.\n\n\u003cimg width=\"50%\" src=\"gfx/02%20-%20Protezione/Matrice%20degli%20Accessi%20Switch.png\" alt=\"Matrice degli Accessi e Diritto Switch\"/\u003e\n\nNel mondo UNIX il diritto di switch è implementato tramite il bit set-uid: se tale bit è settato, il processo che esegue il file può ottenere il dominio del soggetto proprietario.\n\n\n#### Realizzazione della Matrice degli Accessi\nLa matrice degli accessi è una notazione astratta che rappresenta lo *stato* di protezione. Parliamo di stato in quanto sia la forma della matrice che il suo contenuto cambiano dinamicamente nel tempo: ogni colonna rappresenta una risorsa (es: un file), e le risorse vengono create, distrutte e modificate continuamente nel corso dell'esecuzione del sistema operativo.\n\nNella rappresentazione concreta è necessario considerare:\n- la **dimensione** della matrice, ovvero quale può essere la sua dimensione massima (poiché ogni colonna è un file, ed il numero di file in un file system può raggiungere un ordine di centinaia di migliaia di oggetti, ovviamente il numero delle colonne sarà molto elevato);\n- il fatto che sia una matrice **sparsa**, ovvero non è detto che in tutte le celle vi siano delle informazioni. Anzi, al contrario, specialmente se si hanno molti file, possiamo trovare diverse celle vuote, in quanto non è detto che tutti i soggetti abilitati al sistema abbiano qualche diritto su ciascun file, dunque tipicamente vi sarà una prevalenza di celle vuote.\n\nLa rappresentazione più intuitiva sarebbe riservare dello spazio in memoria pari al numero totale di soggetti per il numero totale di oggetti, ma questa soluzione non è ottimale (fa schifo).\nLa rappresentazione concreta dello stato di protezione dev'essere ottimizzata sia per quanto riguarda l'occupazione della memoria, sia rispetto all'efficienza nell'accesso e nella gestione delle informazioni di protezione. Per questo motivo esistono 2 approcci:\n- **Access Control List (ACL)**, si basa su una *rappresentazione per colonne*. Per ogni oggetto (risorsa) si mantiene una struttura dati che concettualmente rappresenta una colonna della matrice, ma tenendo conto che la colonna, come la matrice, è sparsa, in questa linea si mantengono solo gli elementi significativi, ovvero quello non vuoti. La struttura associata ad un oggetto è dunque una *lista in cui ogni elemento è un soggetto che ha un qualche diritto su quell'oggetto*.\n- **Capability List (CL)**, si basa su una *rappresentazione per righe*. Ad ogni soggetto è associta una lista che indica quali sono gli oggetti al quale il soggetto può accedere.\n\n##### ACL: Lista degli Accessi\nNe viene assegnata una a ciascun oggetto ed ha una struttura composta da un insieme di elementi, ognuno dei quali contiene la coppia \u003csoggetto, insieme dei diritti\u003e limitatamente ai soggetti con un insieme non vuoto di diritti per l'oggetto.\nQuando un qualunque soggetto *S* tenta un'operazione *M* su un oggetto *O*, il sistema di protezione va a verificare nella ACL associata ad *O* se è presente un elemento riferito al soggetto che sta tentando l'accesso e, se esiste, controlla che contenga il diritto per eseguire *M* (ovvero sia presenta la coppia \u003c*S*, *Rk*\u003e con *M* appartenente a *Rk*).\\\nIn certi casi, per velocizzare l'accesso, viene prevista una lista di default: se è prevista, esistono dei diritti comuni a tutti i soggetti, dunque si va a vedere prima nella lsita di default e, se la ricerca non va a buon fine, si va a vedere nello specifico, elemento per elemento. Chiaramente, se la ricerca non ha successo, l'accesso viene negato.\n\n**Utenti e Gruppi**: molti sistemi, per identificare un soggetto, prevedono non solo il nome utente (UID - User IDentifier), ma anche il gruppo (GID - Group IDentifier) a cui appartiene. Un gruppo aggrega un insieme di utenti, ha un nome, e può essere incluso nelle ACL. È importante sapere che un utente può appartenere anche a più gruppi, ma in un certo istante può appartenere ad un solo gruppo alla volta. Nel caso siano presenti i gruppi, una entry della ACL ha la forma UID, GID: \\\u003cinsieme di diritti\\\u003e.\nQuando un soggetto \u003cutente, gruppo\u003e prova ad accedere ad una risorsa in un certo modo, il tentativo di accesso comporta una ricerca nell'ACL dell'oggetto: se compare il modo con il quale l'utente sta cercando di accedere alla risorsa, allora l'operazione viene consentita.\n\nTipicamente i gruppi esistono per una questione di differenziazione dei ruoli, ciascuno dei quali ha diritti diversi. In generale, nei sistemi che prevedono i gruppi, è comunque possibile svincolare i soggetti dai gruppi, ovvero senza assegnargli alcun gruppo (UID, * \\\u003cinsieme diritti\\\u003e).\n\n##### CL: Capability List\nNe viene associata una a ciascun soggetto ed ha una struttura composta da un insieme di elementi, ognuno dei quali contiene l'indicazione dell'oggetto ed i diritti di accesso che quel soggetto, al quale la CL è associata, può esercitare su quell'oggetto. Chiaramente non avrà tanti elementi quanti sono le colonne della matrice degli accessi, in quanto come detto è una matrice sparsa.\nNella pratica, spesso l'oggetto viene identificato tramite un descrittore ed ovviamente i diritti, che spesso vengono rappresentati in modo compatto tramite una sequenza di bit.\n\n\u003cimg width=\"60%\" src=\"gfx/02%20-%20Protezione/Struttura%20Capability%20List.png\" alt=\"Struttura Tipica di una Capability List\"/\u003e\n\nIn generale è importante (anche per le ACL), che le informazioni relative alla protezione vengano protette a loro volta da manomissioni. Ci sono vari modi:\n- limitazione degli accessi in scrittura al solo kernel del Sistema Operativo (si sfrutta la protezione a livello hardware, oppure i modi di esecuzione del processore: kernel mode / user mode). In questo modo l'utente fa riferimento ad un puntatore (capability) che identifica la sua posizione nella lista appartenente allo spazio del kernel (soluzione simile all'uso di file descriptor in UNIX);\n- se l'hardware lo supporta si può utilizzare un'architettura etichettata: a livello hardware ogni singola parola ha bit extra (tag) che esprimono la protezione su quella cella di memoria. In questo modo si può proteggere la protezione proprio a livello basso, a livello di memoria. In architetture di questo tipo il processore sa che, durante lo svolgimento delle sue operazioni di aritmetica, i bit di etichetta devono essere ignorati (non vengono proprio considerati).\n\n#### Revoca dei Diritti di Accesso\nIn un sistema di protezione dinamica può essere necessario *revocare* i diritti di accesso per un oggetto. Revocare significa negare dei diritti precedentemente concessi. Ne esistono diversi tipi:\n- revoca **generale** o **selettiva**, ovvero rispettivamente da un certo momento in poi nessuno potrà accedere ad un determinato oggetto, oppure solo alcuni soggetti non potranno più accedervi (ad esempio quelli appartenenti ad un gruppo);\n- revoca **totale** o **parziale**, ovvero rispettivamente riguardante tutti i diritti per l'oggetto, oppure solo un particolare sottoinsieme di diritti;\n- revoca **permanente** o **temporanea**, ovvero rispettivamente il diritto di accesso revocato non sarà più disponibile, oppure potrà essere successivamente riacquistato.\n\n**Revoca per un oggetto con ACL**: la revoca in questo caso risulta semplice, in quanto si fa riferimento alla ACL associata all'oggetto in questione e si cancellano i diritti di accesso che si vogliono revocare.\n\n**Revoca per un oggetto con CL**: l'operazione risulta più complessa, in quanto è necessario verificare, per ogni dominio, se contiene la capability con riferimento all'oggetto considerato.\n```\nNB: cancellare un file significa togliere i diritti su quel file a tutti gli utenti che\nli possiedono. In ACL cancello semplicecmente l'ACL del sistema, mentre con CL bisogna\nfare ricerca in tutte le CL per vedere se esiste un elemento riferito a quel file e in\ncaso cancellarlo.\nSicuramente queste operazioni che riguardano un solo oggetto risultano più costose in\nsistemi con CL.\n```\n\n#### ACL vs CL\nUn sistema realizzato esclusivamente con CL può soffrire di un appesantimento dovuto a operazioni che riguardano revoche che interessano più soggetti e quindi causano overhead (costo computazione maggiore).\nNaturalmente si può fare anche il discorso duale: se si ha la necessità di fare una modifica allo stato di protezione che interessa un particolare soggetto. Il caso più banale è eliminare il soggetto dal sistema. Ciò questo comporta una modifica allo stato di protezione, in CL si cancella semplicemente la lista associata al soggetto; in ACL bisogna fare ricerca in ogni ACL.\\\nDunque non c'è soluzione assoluta, o generalmente migliore dell'altra: nella realtà, nella maggior parte dei sistemi solitamente si usa una soluzione ibrida che combina i due metodi.\n\nAd esempio, in UNIX, per ogni risorsa (file, in quanto UNIX è file-centrico, ovvero tutte le risorse sono presenti nel filesystem come file) per ogni oggetto viene mantenuta una struttura contenente 12 bit \"di protezione\". Sono memorizzati sul disco e fanno parte dell'i-node, che è rappresentato sulla memoria di massa all'interno dell'i-list.\nSe ci pensiamo bene sono una forma semplificata di ACL: i 12 bit (di cui 9 per i diritti di utente, gruppo e altri) sono una forma semplificata di ACL, in quanto esprimono cosa gli utenti possono o non possono fare. È semplificata in quanto non si ha il dettaglio di un particolare utente, a differenza di Sistemi Operativi come Windows, ma solo dell'utente proprietario (oltre che del gruppo e degli altri utenti).\n\n**Soluzione ibrida**: ACL memorizzate in memoria secondaria (persistente), mentre le CL in memoria centrale (volatile). Ogni volta che un soggetto (es: processo) tenta di accedere ad un oggetto per la prima volta, si analizza la ACL relativa a quell'oggetto. Se esiste una entry contenente il soggetto, e se fra i diritti di accesso c'è l'operazione richiesta dal soggetto, viene fornita la capability relativa a quell'oggetto, la quale viene salvata in memoria volatile. Così facendo, il soggetto può accedere all'oggetto più volte, senza che sia necessario analizzare di nuovo la ACL. Dopo l'ultimo accesso, la capability viene distrutta (rimossa dalla memoria volatile).\n\nEsempio: quando cerco di aprire un file in scrittura, viene fatta una verifica sulla ACL (che controlla se posso effettuare quell'operazione); se la verifica va a buon fine, il file viene aperto e nella tabella dei file aperti viene caricato un elemento che concettualmente rappresenta il diritto di quel processo (capability) ad accedere in scrittura sul file; quindi viene aggiunta la capability dell'oggetto per il soggetto in questione, alla tabella dei file aperti. Di fatto la tabella dei file aperti è una CL.\n\n**Differenze**: la ACL si trova in memoria secondaria in modo persistente, la CL è in memoria volatile (e solitamente ha vita più breve): quando il processo finisce di operare sul file, l'elemento viene rimosso e quando il processo termina la tabella dei file aperti viene distrutta.\n\n**Vantaggio**: una volta verificato preliminarmente che sia presente il diritto d'accesso, non c'è più bisogno di consultare la ACL, ma si va a guardare la CL.\n\n### Protezione Multilivello\nCome detto, la protezione riguarda il controllo degli accessi alle risorse interne al sistema; la sicurezza riguarda il controllo degli accessi al sistema. Poiché la protezione di un sistema può essere inefficace, se un utente non autorizzato riesce a far eseguire programmi che agiscono sulle risorse del sistema (es: Trojan, o Cavalli di Troia \u003c!-- indotti, con intenzioni malevole, in qualche modo nel filesystem, una volta qui inducono un utente autorrizzato ad eseguire quel programma e provocano dei danni --\u003e), è necessario affiancarvi un sistema di sicurezza, che normalmente ha una *struttura multilivello*.\n\nIl sistema di sicurezza stabilisce delle regole più generali rispetto al sistema di protezione, in cui prima di tutto si classificano gli utenti (ad esempio in funzione del loro ruolo), dopodiché gli oggetti (le risorse). In funzione della confidenzialità dell'oggetto, vengono collocate ad un livello diverso del sistema. In un sistema di questo tipo l'approccio è quello di tipo MAC.\n\n#### Modelli di Sicurezza Multilivello\nI modelli di sicurezza multilivello più usati sono due:\n- **Bell-La Padula** - obbiettivo di garantire la confidenzialità delle informazioni;\n- **Biba** - è antitetico al precedente, e ha l'obbiettivo di garantire l'integrità delle informazioni.\nEntrambi aderiscono allo stesso modello multilivello.\n\nIn un modello di sicurezza multilivello:\ni soggetti (utenti) e gli oggetti (risorse) sono classificati in livelli (classi di accesso):\n- livelli per i soggetti (**clearance levels**);\n- livelli per gli oggetti (**sensitivity levels**).\n```\nNB: le regole di sicurezza fissano le regole di interazione tra livelli diversi.\n```\n\n##### Modello Bell-La Padula\nNato in ambito militare, ha come obbiettivo primario garantire la **confidenzialità** delle informazioni.\nAbbiamo un sistema di protezione (matrice accessi) a cui viene affiancato un modello multilivello che viene gestito con approccio di tipo MAC.\nVi sono 4 diversi livelli di sensibilità degli oggetti:\n1. non classificato (+ basso);\n2. confidenziale\n3. segreto\n4. top secret (+ alto)\n\nQuesti sono i livelli in cui verranno classificati i documenti.\nSe voglio che un documento sia disponibile solo a chi si trova ai vertifici della gerarchia (es. Generale) lo metterò top secret.\n\nVi sono 2 regole di sicurezza, che caratterizzano il modello, che stabiliscono il verso di propagazione delle informazioni nel sistema:\n1. **proprietà di semplice sicurezza**: un processo in esecuzione ad un livello di sicurezza k può **leggere** oggetti a suo livello o a livelli inferiori;\n2. **proprità \\* (star)**: un processo in esecuzione a livello di sicurezza k può **scrivere** solo oggetti al suo livello o superiori.\nIl flusso delle informazioni è dunque dal basso verso l'alto.\n\n\u003cimg width=\"60%\" src=\"gfx/02%20-%20Protezione/Flusso%20Modello%20Bell-La%20Padula.png\" alt=\"Flusso delle Informazioni nel Modello Bell-La Padula\"/\u003e\n\n**Esempio di difesa contro Trojan per modello Bell-La Padula**: Bell-La Padula serve a impedire attacchi come questo. Supponiamo che i livelli di sicurezza siano 2: riservato e pubblico.\nSe facciamo in modo che gli utenti siano classificati, nonostante l'ACL consenta l'accesso in scrittura, la politica di sicurezza lo impedisce (NB: la politica di sicurezza ha precedenza sui meccanismi di protezione).\nTuttavia, il modello Bell-La Padula è stato concepito per mantenere i segreti, non per garantire l'integrità dei dati.\n\n##### Modello Biba\nHa come obbiettivo l'**integrità** dei dati. Serve per garantire che l'integrità delle informazioni di livello superiore venga in qualche modo preservata.\nAnche in questo caso prevede 2 regole:\n- **proprietà di semplice sicurezza**: è l'opposto di Bell-La Padula, in quanto stabilisce che un processo in esecuzione al livello di sicurezza k può scrivere solo oggetti al suo livello o a quelli inferiori (nessuna scrittura verso l'alto).\n- **proprietà di integrità \\* **: un processo in esecuzione a livello k può leggere solo oggetti al suo livello o a quelli superiori (nessuna lettura verso il basso).\nIl flusso delle informazioni è dunque l'opposto del precedente: dall'alto verso il basso.\n```\nNB: chiaramente i modelli B-LP e BIBA sono in conflitto tra loro, quindi non pos-\nsono essere combinati.\n```\n\n### Architetture dei Sistemi ad Elevata Sicurezza\n**Sistemi Operativi Fidati**: sistemi per cui è possibile definire (e in certi casi dimostrare formalmente) determinati requisiti o regole di sicurezza.\n\n**Reference Monitor (RM)**: elemento di controllo realizzato nell'hardware e dal sistema operativo, che regola l'accesso dei soggetti agli oggetti sulla base di parametri di sicurezza del soggetto e dell'oggetto (in pratica ha il compito di imporre il rispetto delle regole di sicurezza). Poiché ad ogni singola iterazione deve fare delle verifiche e ciò ha un costo, spesso si tende ad implementarlo, almeno in parte, a livello hardware.\n\n**Trusted Computing Base (TCB)**: il RM ha accesso ad una base di calcolo fidata, chiamata *TCB*. Questa contiene delle informazioni che tracciano la classificazione dei soggetti e degli oggetti all'interno del sistema.\n\nIl reference monitor deve imporre le regole di sicurezza (che sono ad esempio, nel caso del modello Bell-La Padula, \"no read-up\" e \"no write-down\") ed ha le seguenti proprietà:\n- **mediazione completa**, ovvero le regole di sicurezza vengono applicate ad ogni singolo accesso da parte di un soggetto ad un particolare oggetto;\n```\nNB: non è così intuitiva, nei SO comuni, es. derivati da UNIX, le regole di prote-\nzione vengono verificate solo a lato apertura del file. Se abbiamo un sistema fi-\ndato invece, ad ogni singola operazione (ad esempio di scrittura) viene fatta una\nverifica da parte del RM.\n```\n- **isolamento**, ovvero il RM e la TCB devono essere a loro volta protette da parte di eventuali accessi non autorizzati. Deve essere possibile accederli solo se ci si trova in modalità privilegiata;\n- **verificabilità**, ovvero la correttezza del RM dev'essere dimostrata. Dev'essere possibile verificare/dimostrare formalmente che il monitor fa quello per cui è stato progettato. Questa proprietà non è semplicissima da applicare.\n\n### Classificazione della Sicurezza dei Sistemi di Calcolo\n*Orange Book* è un documento pubblicato dal Dipartimento della Difesa americano, in cui sono specificate 4 categorie di sicurezza (A, B, C, D, in ordine decrescente), e che consente quindi di etichettare i sistemi di calcolo sulla base delle caratteristiche di sicurezza.\n(- sicuro) D \u003c C \u003c B \u003c A (+ sicuro)\n\n- **D - Protezione Minima**, non sono presenti meccanismi che consentono di esercitare sicurezza né protezione. Al giorno d'oggi non ne esistono. Esempio: MS-DOS, all'epoca i sistemi erano concepiti per essere mono-utente;\n- **C - Protezione Discreta**, si suddivide in *C1* e *C2*:\n    - *C1*, i sistemi prevedono dei meccanismi di:\n        - autenticazione degli utenti (i dati di autenticazione sono protetti e non accessibili ad utenti non autorizzati);\n        - protezione dei dati e programmi propri di ogni utente;\n        - controllo degli accessi a oggetti comuni per gruppi di utenti definiti.\n    Esempio: UNIX e sistemi derivati\n    - *C2*, il controllo degli accessi è fatto su base individuale, non collettiva, al contrario di UNIX.\n    Esempio: Windows.\n- **B - Protezione Obbligatoria**, si suddivide in *B1*, *B2* e *B3*:\n    - *B1*, come C2 ma con introduzione dei livelli di sicurezza (modello Bell-La Padula), almeno 2.\n    - *B2*, si estende l'uso di etichette di riservatezza ad ogni risorsa del sistema, anche canali di comunicazione;\n    - *B3*, la TCB consente la creazione di liste di controllo degli accessi in cui sono identificati utenti o gruppi cui non è consentito l'accesso ad un oggetto specifico.\n- **A - Protezione Verificata (Massima Sicurezza)**, si suddivide in *A1* e classi superiori ad A1. È equivalente a B3, ma con il vincolo di essere progettato e realizzato utilizzando metodi formali di definizione e verifica (il RM è verificabile). Un sistema appartiene ad una categoria superiore ad A1 se è stato progettato in impianti di produzione affidabili, da persone affidabili.\n\n\n\u003c!-- lezione 2021/10/05 --\u003e\n## 03 - Programmazione Concorrente [![Vai al Capitolo Singolo](gfx/icons/file-moved_dark.svg#gh-light-mode-only)](capitoli/03%20-%20Programmazione%20Concorrente.md#gh-light-mode-only \"Vai al Capitolo Singolo\") [![Vai al Capitolo Singolo](gfx/icons/file-moved_light.svg#gh-dark-mode-only)](capitoli/03%20-%20Programmazione%20Concorrente.md#gh-dark-mode-only \"Vai al Capitolo Singolo\")\n\nLa *programmazione concorrente* è l'insieme delle tecniche, metodologie e strumenti per il support all'esecuzione di sistemi software composti da *insiemi di attività svolte simultaneamente*.\n\n### Cenni Storici\nLa programmazione concorrente nasce negli anni '60, proprio nell'ambito dei Sistemi Operativi, quando ci fu l'introduzione dei canali o controllori di dispositivi (hardware): questi consentono l'esecuzione concorrente di operazioni nei dispositivi ed istruzioni nei programmi eseguiti dall'unità di elaborazione centrale.\n\nL'interazione tra dispositivi ed unità centrale di elaborazione (processore) è basata fortemente sul meccanismo delle interruzioni (segnali di interrupt).\nQuando la CPU riceve un segnale di interrupt dalla periferica, può tempestivamente gestiree quel particolare evento, che potrebbe essere ad esempio il trasferimento di dati.\\\nQuesto meccanismo di interruzioni è stato poi importato ed utilizzato ampiamente in sistemi multiprogrammati time-sharing, in cui è impiegato il concetto di **quanto  di tempo** che consente di dividere equamente il tempo di CPU tra tutte le applicazioni in esecuzione su quel sistema/ambiente di esecuzione. Il modo per sancire il termine di un quanto di tempo assegnato ad un certo processo, che esegue un'applicazione, è ancora rappresentato dall'interruzione. Si ha lo scatto all'interruzione quando il quanto di tempo è esaurito, e dunque tempestivamente il Sistema Operativo si occupa di gestire il *cambio di contesto* tra un'applicazione e la successiva, secondo le politiche di scheduling che possiede.\\\nLe interruzioni possono accadere ad istanti impredicibili, dunque in un sistema time-sharing parti di programmi possono essere eseguite in modo non predicibile. Infatti, una delle principali caratteristiche delle applicazioni concorrenti è il *non determinismo*: lo stesso programma eseguito in tempi diversi può comportare risultati diversi anche se il codice non cambia. Questo, ad esempio, si può rilevare quando cci sono parti di programmi che condividono le stesse variabili comuni: in questi casi, se non viene sincronizzato l'accesso a tali variabili, si possono creare delle interferenze.\n\nSuccessivamente sono stati introdotti i sistemi multiprocessore, ovvero con più unità di elaborazione (parallelismo supportato a livello hardware). Se prima il parallelismo era puramente virtuale, con tali architetture il parallelismo era diventato effettivamente \"reale\", in quanto si potevano avere fisicamente diversi microprocessori che lavoravano in modo concorrente.\nCiò ha comportato diversi vantaggi, soprattutto in termini di prestazioni: in particolare, vengono abbattuti i tempi di esecuzione.\n\nIn un sistema concorrente i principali problemi sono:\n- con quale criterio modellare l'applicazione concorrente;\n- come suddividerla in attività concorrenti (quanti processi utilizzare);\n- come garantire la corretta sincronizzazione delle loro operazioni (in generale le attività nelle quali si scompone l'applicaczione possono aver bisogno di interagire fra di loro, dunque è necessario imporre dei vincoli di precedenza).\nQueste decisioni dipendono da:\n- tipo di architettura hardware;\n- tipo di applicazione.\n\n### Tipi di Architettura\n\n#### Single Processor\nSi ha un solo processore che possiede delle memorie ad accesso rapido (tipicamente 2 cache) ed una memoria primaria. Non sono necessari ulteriori layer di comunicazione con altre unità di calcolo, in quanto ne è presente solo una.\n\n\u003cimg width=\"20%\" src=\"gfx/03%20-%20Programmazione%20Concorrente/Single%20Processor.png\" alt=\"Single Processor\"/\u003e\n\n#### Shared-Memory Multiprocessors\nSi tratta di un'architettura costituita da diversi nodi, ciascuno dei quali ha una propria unità di calcolo (microprocessore) e delle memorie ad accesso rapido (cache). Ogni nodo ha la possibilità di accedere a qualunque parte della memoria, grazie alla **rete di interconnessione**. È il più comune al giorno d'oggi.\n\n\u003cimg width=\"45%\" src=\"gfx/03%20-%20Programmazione%20Concorrente/Shared-Memory%20Multiprocessors.png\" alt=\"Shared-Memory Multiprocessors\"/\u003e\n\nPossiamo distinguere due modelli di sistemi multiprocessore:\n**UMA (Uniform Memory Access)**: sistemi a multiprocessore con un numero ridotto di processori (da 2 a circa 30). Sono caratterizzati da un'interconnessione realizzata tipicamente da memory bus o crossbar switch; *tempo di accesso alla memoria uniforme* (indipendentemente dal processore e dalla cella di memoria da accedere, il tempo di accesso rimane costante); sono chiamati anche SMP (Symmetric MultiProcessors).\\\n**NUMA (Non Uniform Memory Access)**: sistemi con un numero elevato di processori (decine o centinaia). Sono caratterizzati da: memoria organizzata gerarchicamente, per evitare la congestione del bus; rete di interconnessione strutturata anch'essa in modo gerarchico (insieme di switch e memorie strutturato ad albero) ed ogniprocessore ha memorie più vicine ed altre più lontane; tempo di accesso dipendente dalla distanza tra processore e memoria (NUMA).\n\n#### Distributed-Memory\nNelle architetture con memoria distribuita ogni processore accede alla propria memoria che non è condivisa tra i nodi di elaborazione. La memoria è quindi specifica del processore a cui è associata ed un'unità di elaborazione non può fare riferimento alla memoria di un altro nodo. In questo tipo di architettura i nodi possono essere singoli processori o multiprocessori a memoria condivisa.\\\nRientrano in questa categoria i *Multicomputers* ed i *Network Systems*.\n\n\u003cimg width=\"50%\" src=\"gfx/03%20-%20Programmazione%20Concorrente/Distributed-Memory.png\" alt=\"Distributed-Memory\"/\u003e\n\n##### Multicomputers\nModello in cui i nodi e la rete sono *fisicamente vicini*, ovvero nella stessa struttura fisica. La rete di interconnessione offre un cammino di comunicazione tra i processi ad alta velocità e larghezza di banda. Ad esempio i Cluster ed i sistemi ad alto parallelismo (HPC). I multicomputer sono fatti per essere aggregati in una stessa struttura fisica.\n```\nNB: un Cluster of Computers (CoW), un insieme di nodi, tipicamente chiamati server, fi-\nsicamente vicini, in cui ogni nodo è una scheda inserita in una struttura fisica, detta\n\"rack\", dove solitamente la rete di interconnessione è una linea ad alta velocità e \ncon larghezza di banda sufficientemente ampia. \n```\n\n##### Network Systems\nSistemi in cui i nodi sono collegati da una rete locale (es: Ethernet) o geografica (es: Internet).\n\n### Classificazione delle Architetture\nLa classificazione dei sistemi di calcolo più utilizzata è la *Tassonomia di Flynn (1972)*, in cui vengono inquadrate architetture e sistemi di elaborazione secondo due parametri:\n1. **parallelismo a livello di istruzioni**\n\t- **Single Instruction Stream**, può essere eseguito un solo singolo flusso di istruzioni;\n\t- **Multiple Instruction Stream**, possono essere eseguiti più flussi di istruzioni in parallelo.\n2. **parallelismo a livello di dati**\n\t- **Single Data Stream**, l'architettura è in grado di elaborare un singolo flusso sequenziale di dati;\n\t- **Multiple Data Streams**, l'architettura è in grado di processare più flussi di dati paralleli.\n\n\u003cimg width=\"50%\" src=\"gfx/03%20-%20Programmazione%20Concorrente/Tassonomia%20di%20Flynn%20(1972)%20(1).png\" alt=\"Tassonomia di Flynn (1972) (1)\"/\u003e\u003cimg width=\"50%\" src=\"gfx/03%20-%20Programmazione%20Concorrente/Tassonomia%20di%20Flynn%20(1972)%20(2).png\" alt=\"Tassonomia di Flynn (1972) (2)\"/\u003e\n\n**SISD - Single Instruction (stream), Single Data (stream)**: sistemi monoprocessore che fanno riferimento all'architettura classica della macchina di Von Newman. Come dice il nome è in grado di gestire un singolo flusso di istruzioni (un programma) alla volta, su un singolo flusso di dati.\n\n**SIMD - Single Instruction, Multiple Data**: architetture tipicamente parallele in cui vi sono diversi processori che, ad ogni istante, possono eseguire la stessa singola istruzione ma su dati diversi. Ad esempio rientrano in questa categoria gli array processors, di cui fanno parte anche le GPU.\n```\nNB: le GPU sono costituite da un insieme di nodi di elaborazione, a cui è assegnato una\nsingola control unit. Poiché elaborano dati che sono rappresentati da grandi matrici \ndi informazioni (elaborazione di immagini), il modello SIMD risulta particolarmente ef-\nficace.\n```\nRientrano in questa categoria anche i vector processors (migliaia di unità di elaborazione, non troppo potenti, ma che messe insieme e se controllate opportunamente, possono risolvere particolari classi di problemi in modo piuttosto efficiente e veloce).\n\n**MIMD - Multiple Instruction, Multiple Data**: insieme di nodi di elaborazione ognuno dei quali può eseguire flussi di istruzioni diverse su dati diversi. Ogni nodo può essere utilizzato da un processo che svolge operazioni diverse su dati differenti. Rientrano in questa categoria i sistemi multiprocessore (quelli che probabilmente conosciamo meglio), ma anche i MultiComputers.\n\n**MISD - Multiple Instruction, Single Data**: il sistema è in grado di gestire un unico flusso di dati che ad ogni istante può essere elaborato con molteplici flussi di istruzioni. Non ci sono esempi particolarmente significativi da portare, ma è il caso dei \"pipelined computer\", dove lee diverse unità di elaborazione sono messe in cascata (pipeline), che lavora su quel flusso di dati, ognuna facendo qualcosa di differente.\n\n### Tipi di Applicazioni\nRicapitolando, il progetto di applicazioni concorrenti dev'essere sviluppato in base al tipo di architettura, ma anche in base ai vincoli dati dal Sistema Operativo.\n\n1. **multithreaded**:\n\t- si ha un'applicazione strutturata come un insieme di processi (thread) che:\n\t\t- permette di dominare la complessità del problema da risolvere;\n\t\t- aumentare l'efficienza, in quanto il carico di lavoro viene \"scaricato\" in parallelo;\n\t\t- semplificare la programmazione (secondo un modello di scomposizione dell'algoritmo in più parti che possono procedere contemporaneamente).\n\t- i processi possono condividere variabili;\n\t- sono caratterizzati dal fatto che generalmente esistono più processi che processori;\n\t- i processi sono schedulati ed eseguiti indipendentemente.\n2. **sistemi multitasking/sistemi distribuiti**:\n\t- le componenti dell'applicazione (task) vengono eseguite su nodi (eventualmente virtuali) collegati tramite opportuni mezzi di interconnessione (es: canali);\n\t- i processi non possono condividere variabili, infatti comunicano scambiandosi messaggi;\n\t- questa organizzazione è tipica del modello client/server.\n\tI componenti in un sistema distribuito sono spesso multithreaded.\n```\nNB: in certi ambiti (sistemi distribuiti) esistono anche sistemi ibridi di applicazioni\nin cui alcune parti sono multithreaded, mentre altre interagiscono a scambio di messag-\ngio.\n```\n3. **applicazioni parallele**:\n\t- possiamo avere sia un modello in cui i processi condividono memoria, sia un modello a scambio di emssaggi;\n\t- hanno l'obbiettivo di risolvere il problema dato nel modo più veloce possibile, oppure un problema di dimensioni più grandi nello stesso tempo, sfruttando efficacemente il parallelismo disponibile a livello hardware;\n\t- sono eseguite su sistemi paralleli (es: HPC, array processors), facendo uso di algoritmi paralleli;\n\t- a seconda del modello architetturale, l'esecuzione è portata avanti da istruzioni/thread/processi paralleli che interagiscono utilizzando librerie specifiche.\n\n### Processi Non Sequenziali e Tipi di Iterazione\n**Algoritmo**: procedimento logico che deve essere eseguito per risolvere un determinato problema. È ciò che succede quando mettiamo in esecuzione un programma\n\n**Programma**: descrizione di un algoritmo mediante un opportuno formalismo (linguaggio di programmazione), che rende possibile l'esecuzione dell'algoritmo da parte di un particolare elaboratore.\n\n**Processo**: insieme ordinato degli eventi cui dà luogo un elaboratore quando opera sotto il controllo di un programma.\n\n**Elaboratore**: entità astratta realizzata in hardware e parzialmente in software, in grado di eseguire programmi (descritti in un dato linguaggio).\n\n**Evento**: esecuzione di un'operazione tra quelle appartenenti all'insieme che l'elaboratore sa riconoscere ed eseguire. Ogni evento determina una transizione di stato dell'elaboratore.\n```\nNB: un programma descrive non un processo, ma un insieme di processi, ognuno dei quali\nè relativo all'esecuzione del programma da parte dell'elaboratore per un determinato \ninsieme di dati in ingresso.\n```\n\n#### Processo Sequenziale\nCon *processo sequenziale* si intende il caso in cui l'insieme degli eventi che avvengono all'interno dell'elaboratore quando esegue un dato programma (l'insieme degli eventi che fanno parte dell'esecuzione prende il nome di \"traccia del programma\"), sia una vera e propria sequenza. Ovvero che gli eventi siano ordinati in modo sequenziale: per ogni evento, tranne il primo e l'ultimo, c'è sempre un solo evento che lo precede ed un solo evento che lo segue.\n\n**Grafo di Precedenza**: è uno schema che permette di rappresentare, tramite un formalismo, la traccia del programma. Ogni nodo rappresenta un singolo evento durante l'esecuzione del programma, ogni arco rappresenta la *precedenza temporale* tra un nodo ed il successivo. Nel caso di un algoritmo strettamente sequenziale, il grafo di precedenza che lo rappresenta si dice ad **ordinamento totale** (qualunque coppia di nodi venga presa nel grafo, questa coppia è sempre ordinata).\n\n\u003cimg width=\"60%\" src=\"gfx/03%20-%20Programmazione%20Concorrente/Esempio%20MCD%20(algoritmo).png\" alt=\"Algoritmo MCD\"/\u003e \u003cimg width=\"11%\" src=\"gfx/03%20-%20Programmazione%20Concorrente/Esempio%20MCD%20(grafo).png\" alt=\"Grafo MCD\"/\u003e\n\n#### Processo Non Sequenziale\nCon *processo non sequenziale* si intende il caso in cui l'insieme degli eventi che lo descrive è ordinato secondo una relazione d'ordine parziale. In altre parole, un processo si dice non sequenziale se il grafo di precedenza che lo descrive non è ordinato in modo totale, ma è caratterizzato da un **ordinamento parziale**.\n\n\u003cimg width=\"40%\" src=\"gfx/03%20-%20Programmazione%20Concorrente/Esempio%20Elaborazione%20File%20(algoritmo).png\" alt=\"Algoritmo Elaborazione File\"/\u003e \u003cimg width=\"9%\" src=\"gfx/03%20-%20Programmazione%20Concorrente/Esempio%20Elaborazione%20File%20(grafo).png\" alt=\"Grafo Elaborazione File\"/\u003e\n\nL'esecuzione di un processo non sequenziale richiede:\n- innanzitutto che o a livello software o hardware l'*elaboratore* sia *non sequenziale*, ovvero ci dia la possibilità di eseguire operazioni simultanee;\n- un *linguaggio di programmazione non sequenziale*.\n\n###### Elaboratore Non Sequenziale\nÈ in grado di eseguire più operazioni contemporaneamente e si hanno due possibilità:\n- sistemei multielaboratori (a)\n- sistemi monoelaboratori (b)\n\n\u003cimg width=\"60%\" src=\"gfx/03%20-%20Programmazione%20Concorrente/Elaboratori%20Non%20Sequenziali.png\" alt=\"Elaboratori Non Sequenziali\"/\u003e\n\n###### Linguaggi Concorrenti\nI linguaggi concorrenti (o non sequenziali) hanno la caratteristica comune di consentire, a livello di programma, la descrizione di un insieme di attività concorrenti, tramite moduli che possono essere eseguiti in parallelo (es: processi sequenziali).\\\nIn generale, un linguaggio concorrente permette di esprimere il (potenziale) parallelismo nell'esecuzione di moduli differenti.\n\nTipicamente ci sono due modi in cui viene realizzato il modulo concorrente di un linguaggio:\n- parallelismo espresso a livello di **singola istruzione**, oggi poco usato (es: CSP, Occam);\n- parallelismo a livello di **sequenza di istruzioni**, molto più frequente (es: Java, Ada, Go, ...).\n\n#### Scomposizione di un Processo Non Sequenziale\nSe il linguaggio concorrente permette di esprimere il parallelismo a livello di sequenza di istruzioni, allora si può scomporre un processo non sequenziale in un insieme di processi sequenziali eseguiti contemporaneamente, e far fronte alla complessità di un algoritmo non sequenziale.\\\nUna volta noto l'algoritmo non sequenziale si tratta di ricavare dal suo grafo di precedenza una collezione di grafi di processi sequenziali, che chiaramente saranno legati fra di loro da vincoli di precedenza.\\\nLe attività rappresentate dai processi possono essere:\n- **completamente indipententi**, se l'evoluzione del processo non influenza quella degli altri. Di fatto nel grafo abbiamo un unico punto di partenza ed un unico punto di arrivo, ma i nodi potrebbero esprimersi, ad esempio, come una serie di 3 sequenze di nodi, che non sono però legate fra loro da vincoli di precedenza (gli eventi che appartengono ad un processo non sono legati ad altri eventi appartenenti ad altri processi);\n- **interagenti**, se sono assoggettati a vincoli di precedenza tra stati che appartengono a processi diversi (vincoli di precedenza fra le operazioni e vincoli di sincronizzazione).\n\n\u003c!-- lezione 2021/10/06 --\u003e\n##### Interazione tra Processi\nEsistono tre possibili tipi di interazione tra processi: *cooperazione*, *competizione*, *interferenza*.\n\n###### Cooperazione\nComprende tutte le interazioni *prevedibili* e *desiderate*, che sono in qualche modo dettate dall'algoritmo (date cioè dagli archi del grafo di precedenza ad ordinamento parziale). È insita nella logica che vogliamo rappresentare. Si può esprimere in 2 modi: **segnali temporali**, ovvero sincronizzazione pura, che esprime solo ed unicamente un vincolo di precedenza; **scambio di dati**, ovvero comunicazione vera e propria. In entrambi i casi esiste comunque un vincolo di precedenza tra gli eventi di processi diversi.\\\nC'è una relazione di causa ed effetto tra l'esecuzione dell'operazione di invio da parte del processo mittente e l'operazione di ricezione da parte del processo ricevente, con un vincolo di precedenza tra questi eventi (*sincronizzazione* di due processi). Il linguaggio di programmazione deve fornire i costrutti linguistici necessari a specificare la sincronizzazione e la eventuale comunicazione tra i processi.\\\nEsempio di cooperazione: interazione data da vincoli temporali (es: un processo esegue delle operazioni ogni 2 secondi, un altro ogni 3 ed un terzo li coordina attivando periodicamente tali processi).\n\n###### Competizione\nConsiste in un'interazione *prevedibile* e *non desiderata* (in quanto non fa parte dell'algoritmo che si vuole implementare, ma è solitamente dato da un limite della risorsa fisica o logica), ma *necessaria*. Infatti, la macchina concorrente, su cui i processi sono eseguiti, mette a disposizione un numero limitato di risorse condivise, disponibili nell'ambiente di esecuzione. Poiché alcune di queste non possono essere accedute o utilizzate contemporaneamente da più processi (o lo sono solo per un numero limitato), è necessario prevedere meccanismi che regolino la competizione, coordinando l'accesso alla risorsa da parte dei vari processi, in modo **mutuamente esclusivo**. Questo può determinare l'imposizione di vincoli di sincronizzazione (se una risorsa può essere usata da un solo processo alla volta, nella fase in cui sta venendo usata da un certo processo, nessun altro deve poterla utilizzare): un processo che tenta di accedere una risorsa già occupata (se non rispetta certi vincoli) dev'essere bloccato.\\\n**Sezione critica**: indica una sequenza di istruzioni con cui un processo accede ad una risorsa condivisa mutuamente esclusiva. Ad una risorsa possono essere associate, in casi particolari, anche più di una sezione critica. Se su una risorsa vale la mutua esclusione, sezioni critiche appartenenti alla stessa classe non possono eseguire contemporaneamente.\\\nEsempio di competizione: processi che devono accedere ad una stampante (risorsa mutuamente esclusiva).\n\n###### Interferenza\nÈ un tipo di interazione *non prevista* e *non desiderata*. Solitamente è provocata da errori del programmatore (infatti solitamente si cerca di eliminarle o escluderle), il quale non ha modellato correttamente l'interazione dei propri processi non sequenziali interagenti.\\\nPuò non manifestarsi, in ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikyll%2Fsistemi-operativi-m","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmikyll%2Fsistemi-operativi-m","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikyll%2Fsistemi-operativi-m/lists"}