Gestione della sicurezza nel sistema Android · Capitolo 3: Sicurezza del dispositivo fisico La...

32
Scuola Politecnica e delle Scienze di Base Corso di Laurea in Ingegneria Informatica Elaborato finale in Sistemi Operativi Gestione della sicurezza nel sistema Android Anno Accademico 2014/2015 Candidato: Giuseppe Guida matr. N46000585

Transcript of Gestione della sicurezza nel sistema Android · Capitolo 3: Sicurezza del dispositivo fisico La...

Scuola Politecnica e delle Scienze di Base Corso di Laurea in Ingegneria Informatica Elaborato finale in Sistemi Operativi

Gestione della sicurezza nel sistema Android

Anno Accademico 2014/2015 Candidato: Giuseppe Guida matr. N46000585

A mio padre.

Indice

Indice .................................................................................................................................................. III

Capitolo 1: Introduzione al progetto Android ...................................................................................... 4

Capitolo 2: Android Security Framework ............................................................................................ 8

2.1 Sandboxing............................................................................................................................... 10

2.2 Permessi Linux e Capabilities .................................................................................................. 11

2.3 Permessi Android ..................................................................................................................... 13

2.4 SELinux e SEAndroid .............................................................................................................. 17

2.5 Firma dei package .................................................................................................................... 20

Capitolo 3: Sicurezza del dispositivo fisico ....................................................................................... 23

3.1 Boot .......................................................................................................................................... 23

3.2 Crittografia ............................................................................................................................... 25

3.3 Screen Lock.............................................................................................................................. 26

3.3 Sicurezza del Radio Interface Layer ........................................................................................ 27

Conclusioni ........................................................................................................................................ 30

Bibliografia ........................................................................................................................................ 31

Lista delle Figure ............................................................................................................................... 32

4

Capitolo 1: Introduzione al progetto Android

Nel 2005 la Google Inc. rilevò dal mercato la Android Inc., azienda specializzata nello

sviluppo di sistemi embedded basati sul kernel di Linux, per poter dar vita ad un proprio

progetto di sistema operativo mobile. La prima versione di Android fu terminata nel

Novembre del 2007 e messa in commercio a partire da Settembre 2008, da allora si sono

succedute molte versioni del sistema operativo ed ognuna di esse ha introdotto novità e

raffinamenti rispetto ai modelli precedenti.

Tuttavia la filosofia che sta dietro allo sviluppo del sistema operativo mobile non è mai

cambiata, essa rispecchia fedelmente la filosofia alla base di Linux, Android infatti è un

progetto open source noto come AOSP (Android Open Source Project) quindi il suo

codice può essere usato, distribuito e modificato liberamente da chiunque. Il primo

riverbero della filosofia dell’Android Open Source Project si è avuto con la sigla

5

dell’accordo noto come Open Handset Alliance (OHA) il quale prevede che tutte le

aziende stipulanti, guidate da Google, impieghino risorse per sviluppare standard open

source per i dispositivi mobili.

Come per la filosofia così per gli obiettivi principali di Android tutto è rimasto immutato

dalle prime versioni, essi possono essere sintetizzati nei seguenti punti:

1. Provvedere ad un sistema di Application Programming Interface (API) capace di

gestire il maggior numero possibile di applicazioni sviluppate da terze parti, quindi

anche con codice proprietario.

2. Permettere a tutte le applicazioni sviluppate da terze parti di competere fra loro

lealmente, cercando di fornire servizi eguali a ciascuna di esse, come la

sincronizzazione dei dati o lo scambio dei messaggi tra cloud e dispositivo.

3. Semplificare la vita all'utente facendo sì che esso debba spendere il minor tempo

possibile ad occuparsi di questioni inerenti alla gestione dei processi applicativi.

4. Avvicinarsi sempre più ad un sistema operativo mobile full general-purpose come i

sistemi operativi dei computer desktop.

5. Fornire un modello di sicurezza che protegga non solo il sistema operativo, ma

anche le applicazioni di terze parti e la privacy dell'utente.

Cenni sull’architettura

L’architettura di Android può essere rappresentata come uno stack composto da quattro

strati fondamentali, analizzandola in prospettiva bottom-up abbiamo: lo strato del kernel

Linux, lo strato Native Userspace, lo strato Application Framework ed infine lo strato

Applicazioni. Spesso ci si riferisce ai due strati centrali come Android Middleware.

6

I

l

Il kernel Linux presente in Android fornisce tutte le funzionalità tipiche di un sistema

operativo Unix: i driver per comunicare con l’hardware, funzionalità di rete, accesso al file

system e gestione dei processi. Tuttavia il kernel di Android introduce delle aggiunte

rispetto al normale kernel di Linux, queste aggiunte sono chiamate Androidismi e servono

a rendere il sistema operativo più adatto a dispositivi mobili. Gli Androidismi sono:

il Binder, il Paranoid Networking, i wakelocks, la ashmem (anonymous shared memory),

gli alarms ed il low memory killer; dal punto di vista della sicurezza i primi due rivestono

una grande importanza in quanto il binder implementa il meccanismo di IPC e il paranoid

networking gestisce l’accesso alla rete.

Il Native Userspace è formato da quattro componenti fondamentali: l’Init, i daemons

nativi, le librerie native e l’Hardware Abstraction Layer (HAL). L’Init è il primo processo

ad essere eseguito dopo la fase di booting, esso dà inizio a tutti gli altri. I daemons nativi

sono dei processi propri del sistema operativo che forniscono funzionalità essenziali al

dispositivo, ad esempio il rild (radio interface level daemon) si occupa della

comunicazione tra il processore in banda base e gli altri componenti. Le librerie native

sono librerie caricate dinamicamente e servono i processi nelle più disparate modalità.

L’Hardware Abstraction Layer è un’interfaccia che gestisce i moduli driver e le relative

7

API forniti dai costruttori di hardware senza conoscerne i relativi dettagli implementativi.

L’Application Framework è composta dalla Dalvik virtual machine, dalle Java Runtime

Libraries, dai System Services e dalle Android Framework Libraries. La Dalvik Virtual

Machine è una Java Virtual Machine costruita su misura per Android, essa non è in grado

di leggere i file .class del linguaggio Java in quanto è stata progettata per leggere i file

DEX (Dalvik EXecutable) i quali sono raggruppati in file con estensione .dex, questi

ultimi a loro volta sono raccolti in un file APK (Android Application) o JAR (Java

libraries). Le Java Runtime Libraries supportano il codice scritto in linguaggio Java,

poiché la gran parte di Android è scritta proprio in questo linguaggio, la presenza di queste

librerie è fondamentale. Tutte le funzionalità che il sistema operativo ha da offrire sono

racchiuse nelle System Services, esse comprendono ad esempio: la connettività di rete, il

supporto del display touch screen e la telefonia. Il linguaggio dominante per

l’implementazione delle System Services è il Java, ma possono essere anche scritte in

codice nativo. Quasi tutte le funzionalità forniscono un’interfaccia utilizzata dalle altre

funzionalità o dal livello superiore per comunicare o chiedere servizi. Infine le Android

Framework Libraries raccolgono tutte le librerie Java che non sono incluse nelle Java

Runtime Libraries.

Lo strato Applications è destinato a contenere le app che compongono Android, le app si

dividono in built-in apps ed user apps. Le prime sono incluse nel sistema operativo mentre

le seconde sono scaricate manualmente dell’utente da uno dei numerosi app market.

Android è ad oggi il sistema operativo mobile più diffuso al mondo. Il numero totale di

dispositivi che lo utilizzano è stimato per oltre un miliardo di unità, inoltre gli analisti

prevedono che una crescita continua per tutto il prossimo decennio. Visto il bacino di

utenza così grande e l’arricchimento giornaliero dei mercati delle app, Android ha fatto

della sicurezza uno dei suoi obiettivi principali. La sicurezza è gestita sotto tutti e tre gli

aspetti che essa concerne: evitare che un’app danneggi il sistema operativo, evitare che

un’app danneggi un’altra app ma soprattutto evitare che un’app arrechi danni o diffonda i

dati dell’utente [1], [2], [3], [7].

8

Capitolo 2: Android Security Framework

Il modello di sicurezza proposto da Android è in gran parte ereditato dal modello di

sicurezza del sistema operativo Linux, tuttavia è stata fatta qualche modifica per adattarlo

alle esigenze dei dispositivi mobili. Il concetto fondamentale della sicurezza del sistema

operativo Linux è il totale isolamento dei processi e delle relative risorse; in altre parole i

processi sono tutti identificati da un numero intero (da 0 a 65535) chiamato UID - User ID

e quindi sono logicamente separati gli uni dagli altri, stesso discorso vale per le risorse

personali di ogni processo le quali oltre ad essere separate sono anche inaccessibili

dall’esterno. Android isola i processi e le risorse a guisa di Linux ma assegna gli

identificativi differentemente, infatti essendo Linux un sistema operativo per desktop

assegna gli UID sia ad utenti fisici sia ai system services. Poiché Android è progettato per

dispositivi mobili personali non c’è alcun bisogno di assegnare più di un UID per l’utente

fisico, perciò gli UID sono assegnati alle applicazioni.

Sebbene l’isolamento dei processi sia un caposaldo della sicurezza di Android, affinché il

sistema operativo possa essere di una qualche utilità i processi devono comunicare fra

loro. Le comunicazioni sono gestite dall’Androidismo Binder che è un meccanismo di IPC

– Inter Process Communication, esso è stato progettato per un sistema operativo mobile e

quindi diversamente dal meccanismo di IPC System V non prevede strutture come:

semafori, code di messaggi e segmenti di memoria condivisa. La gestione delle

comunicazioni è quindi affidata interamente allo strato kernel, il quale mette a

disposizione un’interfaccia utile all’interazione tra processi. Questa interfaccia è il device

/dev/binder il quale è implementato dal driver del Binder. Tutte le comunicazioni passano

9

per il driver del Binder il quale gestisce una parte read-only dello spazio di indirizzamento

di ogni processo. Questo driver ha un’unica chiamata di sistema utilizzata sia per inviare

messaggi sia per riceverli, la ioctl(), che utilizza una struttura dati chiamata

binder_write_read. La struttura ha due buffer: write_buffer per la scrittura e read_buffer

per la lettura. La sequenza di comunicazione fra due processi è la seguente:

Il kernel si accorge che il processo A vuole comunicare con il processo B ed alloca nella

memoria a sola lettura di B lo spazio che andrà ad occupare con il messaggio che A

desidera inviare. Dopo il kernel notifica al processo B la locazione di memoria occupata

dal messaggio, una volta che il messaggio è stato letto e le eventuali richieste processate il

processo B notificherà al kernel di ripulire la locazione di memoria utilizzata.

La sicurezza dell’IPC è garantita dall’automatica scrittura del PID (personal ID) e del

EUID (Effective UID) del processo A nel messaggio da inviare, così facendo il processo B

può decidere se eseguire o meno i compiti che gli sono stati richiesti dal processo A.

Poiché è lo stesso kernel a scrivere nel messaggio il PID e l’EUID del processo chiamante,

quest’ultimo non può in alcun modo ottenere privilegi non consentitigli.

10

Gli altri aspetti principali della sicurezza in Android sono riassumibili nei seguenti

argomenti:

- Application Sandboxing.

- Gestione dei permessi.

- SEAndroid.

- Firma dei package.

2.1 Sandboxing

L’application sandboxing è stato progettato con la duplice intenzione di evitare sia che le

applicazioni consumino tutte le risorse del sistema operativo a discapito delle altre, sia che

le stesse applicazioni abbiano piena ed incontrollata libertà di interagire tra loro. Lo strato

del kernel Linux applica il sandboxing sia per le applicazioni normali che per i system

service. All’atto dell’installazione di una nuova app, Android automaticamente gli

assegna un UID univoco; l’esecuzione dell’applicazione avviene poi all’interno di un

processo che gira con il medesimo UID. Inoltre ogni applicazione possiede uno spazio di

memoria personale la cui lettura e scrittura è permessa solo al proprietario. In questo modo

un’app è totalmente isolata (sandboxed) dalle altre.

11

Gli UID sono generati ed assegnati seguendo un determinato criterio, in generale l’UID

rispecchia anche i privilegi concessi all’applicazione o al system service. Se un system

service ha come UID 0 esso avrà privilegi da root user, cioè avrà tutti i privilegi possibili,

tuttavia sono pochi i daemons ad avere questo grado. Per la maggior parte dei system

service gli UID partono da 1000, questo numero sta ad indicare il system user

(AID_SYSTEM) il quale ha accesso ad un gran numero di privilegi ma ha comunque delle

limitazioni. Invece gli UID generati per per le normali app partono dal numero 10000

(AID_APP). Ogni app ha un username simbolico scritto nella forma app_XXX , le tre X

rappresentano lo scostamento dell’UID dell’app da quello dell’AID_APP. Per esempio, se

c’è un’app con username app_37 l’UID corrispondente sarà AID_APP + 37 = 10037.

L’username simbolico dell’app è anche usato per dare il nome alla directory dei dati

personali dell’applicazione, la directory si trova nel percorso /data/data.

Android dà la possibilità alle applicazioni che sono strettamente accoppiate, cioè quelle

che hanno bisogno di comunicare di frequente e di accedere alle stesse risorse, di essere

installate con lo stesso UID. Questo UID prende il nome di shared user ID e permette alle

applicazioni di essere eseguite all’interno dello stesso processo. I presupposti per poter

utilizzare lo shared user ID sono due: le app richiedenti devono essere firmate con la stessa

chiave e devono richiedere lo shared user ID a tempo di installazione poiché Android non

permette di cambiare UID una volta che l’app è stata installata. Molte app di sistema

utilizzano lo shared user ID mentre questo comportamento per le app comuni è raro e

sconsigliato [3], [7], [8], [9].

2.2 Permessi Linux e capabilities

Per capire come Android coniuga il bisogno delle applicazioni di comunicare fra loro

attraverso l’IPC e la necessità del sistema operativo di isolare tutti i processi è necessario

capire come avviene la gestione dei permessi in Linux e le sue capabilities.

Fondamentalmente in Linux ad ogni file è associata una tripla di permessi e, se qualche

processo richiede un’operazione sul file, il kernel controlla se quel processo ha il diritto

per eseguire quell’operazione. All’atto di creazione di un file esso ha un solo proprietario

(colui che crea il file) ed un solo gruppo proprietario. È possibile fare tre tipi di operazione

su di un file: lo si può leggere ( r ), lo si può scrivere ( w ) e lo si può eseguire se il file è

12

eseguibile ( x ).

Linux permette di specificare quali di queste tre operazioni può eseguire: il proprietario, il

gruppo proprietario e tutti gli altri.

Per vedere i permessi di un file in Linux è sufficiente usare il comando ls –l seguito dal

nome del file, il risultato sarà una stringa di caratteri simile a questa:

-rwxr-x--- 1 username group date hour name

La prima linea indica che il file è un file normale. Se fosse stata una cartella ci sarebbe

stata la lettera d. I primi tre caratteri rwx indicano che l’utente proprietario username può

leggere, scrivere ed eseguire il file, i seguenti tre caratteri r-x indicano che il gruppo

proprietario group può solo leggere ed eseguire il file, gli ultimi tre caratteri --- indicano

che tutti gli altri utenti non possono eseguire alcuna operazione sul file.

Le operazioni che possono essere richieste ad una cartella sono le stesse ma il significato è

differente da quello dei file normali. Avere il permesso di leggere una cartella vuol dire

poter vedere la lista dei file che essa contiene. Avere il permesso di scrivere una cartella

significa che un utente può aggiungere o eliminare file dalla cartella. Poter eseguire una

cartella significa poter accedere a tutti i file che essa contiene. In aggiunta ai normali

permessi alcune directory in Linux hanno un grado di protezione supplementare, lo sticky

bit. Lo sticky bit è un bit che, se è alto, permette l’eliminazione di un file dalla directory

solo al proprietario del file stesso, ovviamente il proprietario del file per poterlo eliminare

deve possedere anche il permesso di write.

Quindi il controllo che esegue il kernel è un semplice confronto tra l’operazione richiesta

dall’utente ed i bit di permesso associati alla categoria in cui ricade l’utente, l’utente root

può sempre eseguire qualsiasi operazione.

Possiamo quindi suddividere gli utenti in due macrocategorie: gli utenti non privilegiati

(UID diverso da 0) o normali e gli utenti privilegiati o root (UID = 0); i primi hanno

capacità molto limitate e sono soggetti ai controlli da parte del kernel, mentre i secondi

hanno la capacità di superare ogni controllo. Spesso capita che un utente normale debba

eseguire un’operazione permessa solo ad utenti privilegiati. Affinché l’utente possa

svolgere il proprio compito gli si potrebbero affidare i privilegi di root, ma ciò porterebbe

13

ad una situazione incredibilmente pericolosa giacché potrebbero verificarsi molteplici

abusi di sistema causati dall’utilizzo improprio di tutti i privilegi. È necessaria quindi una

via di mezzo che permetta all’utente normale di ottenere soltanto un numero ristretto di

privilegi, corrispondenti all’operazione che deve eseguire. Gli sviluppatori del kernel

Linux hanno così creato le Posix capabilities. Le capabilities sono disposte in tre bitmap:

l’inheritable (I), la permitted (P) e la effective (E); ogni capability è rappresentata da un bit

in queste bitmap. Se un processo vuole eseguire un’operazione che richiede privilegi root

allora il kernel controlla nelle bitmap se il bit della capability relativo all’operazione

richiesta è alto oppure no. La bitmap Inheritable contiene le capabilities che possono

essere ereditate da un programma che è eseguito dal processo. La bitmap Permitted mostra

le capabilities che possono essere utilizzate dal processo, mentre la bitmap Effective

mostra le capabilities usate attualmente dal processo. Una lista commentata di tutte le

capabilities esistenti in Linux è presente in usr/src/linux/include/linux/capability.h [10].

2.3 Permessi Android

La soluzione trovata dagli sviluppatori del kernel Linux per assegnare solo determinati

privilegi a processi non root è alla base della gestione dei permessi in Android. L’idea

fondamentale è la stessa ma i meccanismi con i quali essa è applicata sono diversi poiché

sono stati adattati ad un sistema operativo mobile.

Le applicazioni di Android per espandere le proprie funzionalità o per eseguire i propri

compiti sono in grado di richiedere un set di permessi che consente loro di avere

determinati privilegi. Questi permessi sono delle stringhe di caratteri e se accordati

possono garantire l’utilizzo delle risorse hardware, delle risorse del sistema operativo e dei

dati delle altre app. Il rilascio dei permessi avviene a tempo di installazione ed una volta

che sono stati accordati essi sono validi per tutta la vita dell’app. I permessi si dividono in

due categorie: quelli preinstallati e quelli personalizzati. Il numero dei permessi

preinstallati disponibili cresce con l’arricchimento delle funzionalità di base presenti nelle

versioni recenti di Android, una lista aggiornata è disponibile all’indirizzo ufficiale degli

14

sviluppatori: http://developer.android.com/reference/android/Manifest.permission.html

Si possono conoscere i permessi anche operarando da terminale attraverso il comando

pm list permissions.

Tutti i permessi sono definiti all’interno del package android e sono scritti nella seguente

forma: permission:android.permission.PERMISSION_NAME.

Un’app richiede al sistema operativo uno o più permessi attraverso un file chiamato

AndroidManifest.xml usando il tag <uses-permissions>.

Ad esempio un’app che richiede il permesso per utilizzare internet userà il tag in questo

modo: <uses-permission android:name=”android.permission.INTERNET”/>.

La gestione dei permessi è operata dal system service package manager il quale gestisce

tutte le informazioni sui package installati, ad esempio: versione, percorso di installazione,

permessi rilasciati e certificato. Se l’app subisce un update o viene disinstallata il package

manager aggiorna le informazioni disponibili, queste ultime sono memorizzate in un file

XML collocato nel percorso data/system/packages.xml.

Android non pone i permessi tutti sullo stesso piano infatti esistono quattro livelli di

protezione ed ogni permesso appartiene ad un solo livello. Ogni livello indica sia il rischio

che può comportare il rilascio del permesso sia il criterio da adottare per decidere se

rilasciare o meno il permesso ad un’app.

Normal. È il livello di protezione di base, i permessi che rientrano in questa categoria sono

quelli a rischio minimo. Il rilascio di questo permesso avviene in maniera automatica e

trasparente all’utente.

Dangerous. È il livello di protezione i cui permessi possono costituire un pericolo per il

sistema operativo o per le altre applicazioni. In genere i permessi richiedono la gestione

dei dati utente o il controllo di risorse hardware. Il rilascio dei permessi avviene solo se

l’utente, all’atto dell’installazione e attraverso una schermata, accetta tutte quante le

richieste. Android non permette di accettare solo una parte dei permessi, infatti vige la

regola del tutto o niente cioè o i permessi sono tutti rilasciati oppure l’app non viene

installata.

Signature. È un livello di protezione esclusivo, i permessi che ricadono in questa categoria

15

possono essere rilasciati solo alle applicazioni firmate con la stessa chiave crittografica

dell’applicazione che ha dichiarato il permesso. Questa condizione è molto stringente

poiché la chiave è posseduta solo dal proprietario dell’app o della piattaforma.

SignatureOrSystem. È un livello di protezione esclusivo i cui permessi possono essere

richiesti solo dalle app che sono firmate con la stessa chiave crittografica del possessore

dell’app o dalle applicazioni che fanno parte dell’immagine del sistema.

Dopo che l’applicazione ha ricevuto tutti i permessi richiesti bisogna memorizzare quali

permessi sono stati rilasciati per quell’app così da permettergli di funzionare, per fare ciò

si utilizza il concetto di gruppo visto in Linux.

All’atto di installazione l’app riceve un UID e viene eseguita in un processo che avrà lo

stesso UID, un GID e diversi GID supplementari.

In Android, l’appartenenza di un’applicazione ad uno o più gruppi è resa esplicita dal

possesso dei GID. Questo meccanismo consente di restringere l’accesso alle risorse

hardware o di sistema operativo solo a chi appartiene ad un determinato gruppo e cioè solo

alle applicazioni che hanno ricevuto il relativo permesso. Un file che contiene le

associazioni tra gruppi e permessi built-in è presente nel percorso

etc/permission/platform.xml.

Ad esempio tutte le app che hanno ricevuto il permesso per utilizzare connessioni internet

apparterranno al gruppo inet.

<permission name=”android.permission.INTERNET”>

<group gid=”inet” />

</permission>

In Linux le connessioni di rete possono essere create da tutti i processi, in Android invece

ciò è stato reso possibile solo per un ristretto gruppo di processi. Limitare l’uso delle

connessioni di rete fa parte del meccanismo di controllo, applicato dal kernel, noto come

Paranoid Networking. Il Paranoid Networking controlla non solo la creazione di socket di

rete di natura IPv4, ma anche di natura IPv6 e Bluetooth.

16

Lo strato di Application Framework si occupa di controllare che un processo chiamante

abbia tutti i permessi necessari per poter utilizzare le risorse che sta chiedendo. Il controllo

può essere di due tipi: dinamico o statico.

Il controllo dinamico sfrutta il fatto che ogni UID è associato ad un solo package ed il

system service package manager gestisce un database aggiornato di tutti i permessi

rilasciati ad ogni package. Android per semplificare le operazioni di controllo, giacché

sono molto frequenti, mette a disposizione una classe che possiede metodi funzionali a

questi controlli, android.content.Context è il nome della classe. Il metodo più importante

della classe è: int Context.checkPermission(String permission, int pid, int uid), il cui

compito è di restituire il valore PERMISSION_GRANTED se il controllo va buon fine

mentre deve restituire il valore PERMISSION_DENIED se il processo chiamante non ha i

permessi necessari. Tutti i processi chiamanti di grado root o system ottengono

direttamente il valore PERMISSION_GRANTED, così come se il processo chiamante è lo

stesso che ha dichiarato il permesso. Se invece è un normale processo a chiedere la risorsa

vengono effettuati due controlli: il primo controllo mira ad identificare se la risorsa

richiesta è pubblica o privata, se la risorsa è privata allora si restituisce il valore

PERMISSION_DENIED; il secondo avviene solo se la risorsa è pubblica, in questo caso il

package manager risale all’app partendo dall’UID e controlla nel database il file che

contiene tutti i permessi accordati all’app. Se il permesso necessario è fra quelli rilasciati

allora si ha il ritorno del valore PERMISSION_GRANTED, altrimenti si ha il caso duale.

Il controllo statico ha luogo quando un’app cerca di utilizzare un metodo o una risorsa di

un’altra app e per fare ciò l’app chiamante deve aver ottenuto un permesso specifico.

Android tramite il meccanismo degli intenti dà la possibilità al processo chiamante di

scegliere se il componente cercato deve essere di un’app ben specifica (explicit intent)

oppure di un’app generica (implicit intent), l’ultima opzione fa sì che stesso Android

cerchi un componente soddisfacente i criteri e se ne viene trovato più di uno viene

mostrata all’utente una finestra di selezione. Il processo di controllo prevede che vengano

ottenuti sia il PID che l’UID del processo chiamante attraverso le system call

17

Binder.getCallingUid() e Binfer.getCallingPid(). Ancora una volta si sfrutta l’associazione

univoca tra UID e package e si ricorre al file del database che contiene le informazioni sui

permessi rilasciati, se il permesso necessario è presente allora la chiamata va a buon fine

altrimenti viene lanciata un’eccezione. Il system service che effettua il controllo è

l’activity manager.

Con l’introduzione della versione 6.0 di Android, chiamata M, la gestione dei permessi ha

subito una sostanziale modifica. Non sarà più necessario rilasciare i permessi a tempo di

installazione, infatti le app saranno installate automaticamente ed i permessi necessari

saranno autorizzati solo a tempo di esecuzione quando sarà necessario utilizzare la relativa

funzionalità [2], [3], [7].

2.4 SELinux e SEAndroid

La sicurezza di Android si basa su due aspetti fondamentali ereditati dalla cultura di

Linux: l’application sandbox e la gestione dei permessi, queste due tecniche fanno

riferimento al meccanismo di sicurezza noto come DAC – Discretionary Access Control.

In senso generale si controlla l’accesso ad una risorsa basandosi sull’identità di chi lo

richiede o dalla sua appartenenza ad un gruppo, la discrezionalità giace nel fatto che un

soggetto che possiede il permesso può passarlo ad un altro soggetto anche in maniera

involontaria. Questo passaggio di permessi clandestino renderebbe vano il meccanismo di

protezione fornito dal sandboxing e dalla gestione dei permessi, inoltre il fatto che un

processo root disponga di privilegi illimitati e non separati come accade nelle capabilities

di Linux rende Android suscettibile ad abusi da parte di processi che hanno ottenuto il

grado root attraverso un exploit. Per contrastare queste problematiche è stato progettato un

nuovo meccanismo di sicurezza chiamato MAC – Mandatory Access Control

implementato in SELinux e recentemente anche in SEAndroid. Security Enhanced Linux è

un modulo di sicurezza che fa parte di una framework chiamata Linux Security Modules,

tutti i moduli che fanno parte di questa framework migliorano il controllo degli accessi in

Linux.

Esistono due tipi di MAC: Type Enforcement e Multi-Level Security, SELinux li supporta

18

entrambi ma verrà trattato in questo elaborato solo il primo tipo, poiché Android non

contempla il secondo. L’architettura di SELinux può essere schematizzata come un

insieme di quattro componenti: il manager degli oggetti (OM), un vettore di accessi cache

(AVC), un server di sicurezza e una politica di sicurezza. I primi tre componenti risiedono

nel kernel Linux mentre l’ultimo è parte dello spazio utente. La sequenza di azioni che

avvengono se un processo chiede una determinata risorsa è la seguente:

il processo chiede di effettuare un’azione su di un oggetto, il manager dell’oggetto in

questione chiede al vettore degli accessi se il processo ha fatto una richiesta lecita. L’AVC

tiene in memoria le decisioni di sicurezza già prese e se quella relativa al nostro caso è

presente in lista allora egli risponde all’OM con la decisione. Se la decisione non è

presente nella lista allora l’AVC deve contattare il security server il quale è l’entità

preposta a prendere una decisione in base alla politica di sicurezza stabilita. Dopo aver

preso la decisione il security server la invia all’AVC il quale prima la memorizza e poi la

invia all’OM. Infine l’OM permette o nega l’azione in funzione del responso.

Affinché una decisione possa essere presa, sia i soggetti richiedenti che gli oggetti richiesti

sono dotati di un insieme di quattro attributi di sicurezza noto come security context, gli

attributi sono: username, role, type e range. Gli username sono usati in genere per

identificare un gruppo di utenti, ogni utente possiede almeno un ruolo che gli permette di

accedere a determinati oggetti associati ad un tipo, il tipo serve per raggruppare i processi

in un dominio (in questo caso prende il nome di dominio) o gli oggetti in una logica. Il

campo range invece nel Type Enforcement è riempito da una costante poiché è necessario

solo per il MLS.

Il security context deve essere prima assegnato e poi memorizzato. Gli oggetti sono visti

come file, la memorizzazione avviene in un campo dei metadati del file mentre

l’assegnazione dei campi del security context può avvenire in due modi: esplicitamente

attraverso l’inizializzazione dell’oggetto o implicitamente attraverso l’ereditarietà.

L’oggetto figlio quindi riceve lo stesso contesto dell’oggetto padre e se la politica di

sicurezza lo permette egli può cambiare il proprio contesto in un secondo momento. Per i

soggetti, perlopiù processi, l’assegnazione del security context avviene in maniera analoga

19

alle modalità degli oggetti.

Le decisioni sull’accesso ad un oggetto kernel da parte di un processo sono prese dal

security server; esse sono ponderate sulla base della politica di sicurezza vigente. Le

politiche di sicurezza sono implementate in un linguaggio apposito formato da statements

e rules: gli statement definiscono i tipi, i ruoli e gli utenti mentre le rules definiscono il

permesso o il divieto di accesso ad una risorsa.

SELinux si può presentare in tre stati: disabilitato, permissive ed enforcing. Il primo stato

non prevede alcuna applicazione del meccanismo MAC, quando SELinux è disabilitato

infatti il DAC è operativo. Lo stato permissive fa sì che la politica sia caricata ed i

controlli sugli oggetti vengano effettuati ma il rifiuto di fornire l’accesso ad un soggetto

non conforme è solo notificato tramite un messaggio. Infine nello stato Enforcing la

politica è sia caricata che applicata.

L’implementazione del meccanismo MAC in Android è una conseguenza naturale del

fatto che sia quest’ultimo che Linux condividono lo stesso kernel, seppur con qualche

differenza. Proprio a causa di queste differenze non è stato possibile applicare SELinux ad

Android e si quindi venuti alla creazione di un meccanismo adatto al sistema operativo

mobile noto come SEAndroid.

Per implementare SEAndroid sono stati necessari dei cambiamenti sia a livello kernel sia a

livello userspace. A livello kernel sono state fatte delle modifiche affinché il Binder IPC

potesse supportare le funzioni dei Linux Security Modules. A livello userspace invece è

stato introdotto il labelling per il nucleo della libreria C e i daemons nativi insieme

all’application framework sono stati resi adatti a SEAndroid.

Allo start-up di Android tutti i processi di sistema sono inizializzati a partire dal primo

processo che viene eseguito, init. Questo processo carica la politica di sicurezza contenuta

nella directory /sepolicy e poi setta il modo in cui SEAndroid dovrà operare: enforcing,

permissive o disable. La scelta su come applicare la sicurezza è presa in base al valore di

ro.boot.selinux, il valore di questo campo varia a sua volta a seconda del contenuto del

campo androidboot.selinux il quale è modificato tramite linea di comando.

Come in SELinux, anche in SEAndroid i security context sono salvati negli attributi estesi

20

del relativo file. Tuttavia SEAndroid mantiene una corrispondenza tra il path dell’oggetto

salvato e il suo security context nel file chiamato file_contexts.

Android usa alcune proprietà di sistema a visibilità globale per informare i vari processi

sullo stato dell’hardware, dei servizi o delle risorse. Queste proprietà sono ovviamente

disponibili solo in lettura ai processi comuni, la scrittura è riservata ai processi con

privilegi root, system o radio. SEAndroid aggiunge un livello di protezione MAC a questo

meccanismo facendo sì che solo i processi appartenenti ad un determinato dominio

possano modificare determinate proprietà. A questo proposito si fornisce un security

context ad ogni proprietà di sistema e si salva la corrispondenza in un file apposito,

chiamato property_context.

Il processo zygote è colui che setta le credenziali DAC (UID, GID e GID supplementari)

per ogni processo che genera, SEAndroid ha introdotto in zygote il controllo e

l’assegnazione dei security context per ognuno dei processi. Il modo attraverso cui zygote

genera il security context è il file di configurazione seapp_contexts il quale contiene delle

regole di assegnazione universali. Confrontando le proprietà del processo con le regole

presenti nel file, zygote riesce a dettagliare il security context.

Il meccanismo di sicurezza MAC previsto da SEAndroid è disponibile a partire dalla

versione 4.0 di Android Ice Cream Sandwich ma solo in modalità permissive, dalla

versione 4.4 KitKat invece è disponibile anche in modalità enforcing.

SEAndroid però non è solo una prerogativa dello strato kernel, infatti gli sviluppatori

hanno deciso che il meccanismo MAC può essere applicato anche allo strato Middleware.

Il concetto di Middleware MAC mira ad espandere la sicurezza che SEAndroid può

fornire a tempo di installazione, infatti nonostante la volontà dell’utente di rilasciare i

permessi necessari per installare un’app, il Middleware MAC ne può impedire il rilascio

effettivo sulla base del certificato dell’app e sul nome del relativo package [6], [7].

2.5 Firma dei package

In ambito della sicurezza la firma del codice è una strategia usata per assicurare due

concetti: l’autenticità e l’integrità. Il codice è autentico se è possibile far corrispondere il

21

reale creatore del codice con l’entità che afferma di averlo creato. Il codice è integro se

esso non è stato alterato in alcun modo. Il creatore per dimostrare queste cose deve

possedere una chiave di firma, unica e personale, la cui verifica da parte dell’utilizzatore

del prodotto mira a verificare che il codice sia stato firmato con la chiave attesa. Questa

tecnica non può essere adoperata per constatare se il codice è malevolo oppure no.

Android controlla i propri package attraverso la verifica della relativa firma, sia per

garantire i due aspetti citati prima ma anche per rilasciare i permessi di livello signature.

I package di Android sono distribuiti sotto forma di file APK la cui estensione è .apk , è

possibile esplorare il contenuto di questi package giacché essi non sono altro che

un’estensione del formato .jar e quindi indirettamente del formato .zip.

Fondamentalmente, questi package contengono: il codice eseguibile, le risorse associate, il

file AndroidManifest.xml e la firma. La firma è contenuta nella directory nota come

META-INF.

In Android la firma del codice è simile a quella usata in Java infatti usa la crittografia a

chiave pubblica ed il certificato X.509. In molti ambienti la firma del codice deve essere

emessa da una CA – Certificate Authority la quale è fonte di fiducia. Tuttavia in Android

non è necessario ricorrere alla CA per firmare il codice poiché non è possibile trovare un

certificato che sia valido ed accettato da tutte le aziende che usano Android, a questo

proposito è stata resa disponibile l’autocertificazione.

Per firmare il codice o per verificarlo è possibile usare lo strumento di firma del codice

disponibile nella JDK jarsigner oppure il tool di Android signapk.

Per firmare con jarsigner basta usare il comando jarsigner dalla linea di comando

specificando: il keystore file, l’alias della chiave usata per firmare e l’algoritmo di firma.

$ jarsigner –keystore debug.keystore –sigalg SHA1withRSA test.apk androiddebugkey

Le versioni di Android precedenti alla 4.3 supportano solo l’algoritmo di firma

SHA1withRSA, mentre dalla versione 4.3 in poi si può utilizzare anche SHA256withRSA

e SHA512withRSA.

Per usare jarsigner per verificare il package si usa il comando seguente :

$ jarsigner –keystore debug.keystore –verify –verbose –certs test.apk

22

Prima viene eseguito il controllo del blocco firmato e del certificato di firma infine si

controlla che i digest appartenti al CERT.SF corrispondano ai relativi blocchi del

MANIFEST.MF.

Signapk ha bisogno di due ingressi per firmare il package : la chiave di firma ed il file

certificato.

$ java –jar signapk.jar cert.cer key.pk8 test.apk test-signed.apk

Signapk dà anche la possibilità di firmare un intero file per proteggere gli aggiornamenti

fatti OTA- Over The Air, può essere utilizzata inserendo il comando –w [7].

23

Capitolo 3: Sicurezza del dispositivo fisico

La sicurezza di Android non contempla solo i processi, le risorse di sistema e le varie

interazioni fra di esse, ma abbraccia anche tutto ciò che riguarda la sicurezza dell’handset

in sé. La protezione dei dati personali, dell’accesso al dispositivo e dell’hardware sono le

tematiche che più coinvolgono gli utenti di Android interessati alla salvaguardia del

proprio dispositivo; gli sviluppatori del sistema operativo mobile affrontano con grande

attenzione questi aspetti ed a questo proposito aggiungono migliorie alle precedenti

funzionalità e ne introducono di recenti ad ogni nuova versione.

3.1 Boot

All’accensione del dispositivo l’utente vede in genere comparire per alcuni secondi sul

display il logo di Android oppure il logo del brand dell’handset, il tempo usato per

mostrare una delle due immagini è il tempo necessario al dispositivo per eseguire la fase di

booting o bootloading. In realtà questa fase è composta da più fasi, ognuna delle quali

svolge un compito ben specifico, tuttavia possiamo tranquillamente considerarla come

unica giacché il numero di fasi del booting varia a seconda del costruttore dell’hardware. I

compiti del booting sono: inizializzare l’hardware del dispositivo e caricare il sistema

operativo nella memoria RAM e se possibile disporre un’interfaccia utente.

Questa fase è soggetta ad alcuni meccanismi di protezione, infatti è possibile usufruire di

alcune vulnerabilità per far caricare un sistema operativo diverso da quello usuale che dia

l’accesso ai dati personali dell’utente. È anche possibile sfruttare il modo in cui avvengono

gli aggiornamenti per eliminare i controlli di sicurezza presenti sui dati utente.

24

Nonostante le diversità dei vari processi di booting, ognuna di essa dà la possibilità,

tramite la pressione simultanea di un insieme di tasti o attraverso la linea di comando

dell’ADB - Android Debug Bridge, di entrare in download mode e di eseguire la scrittura

di un file immagine sul disco rigido. Per evitare che il dispositivo venga violato entrando

in download mode e caricando un sistema operativo ad hoc si è soliti usare un bootloader

bloccato il quale impedisce che vengano scritti sul disco rigido file immagine oppure

permette la scrittura solo ai file immagine dotati di una firma valida. È possibile sbloccare

il bootloader ma il prezzo da pagare è dover formattare tutti i dati utente così da prevenire

una violazione dei dati personali in caso venisse montato un sistema operativo malevolo.

Attraverso la pressione di un’altra combinazione di tasti è possibile entrare in recovery, un

sistema operativo mobile minimale usato per installare gli aggiornamenti OTA. Gli

aggiornamenti OTA sono firmati con la chiave privata del costruttore e per assicurare

l’integrità e l’autenticità il recovery esegue il controllo degli aggiornamenti attraverso la

chiave pubblica. Il recovery può essere sostituito da un recovery sviluppato da terze parti,

generalmente lo si fa per installare una versione di Android customizzata. L’insidia

nascosta in questa pratica è che può permettere l’accesso al dispositivo con privilegi di

root attraverso l’uso dell’ADB. Crittografare i file può essere inutile giacché attraverso

l’uso di un rootkit si può aggirare la cifratura. È stato previsto quindi di usare un boot

verificato al fine di evitare violazioni derivanti da questa tecnica, questo meccanismo

prevede l’impiego di un utility del kernel chiamata device mapper la quale effettua una

corrispondenza uno ad uno oppure uno a molti tra blocchi virtuali e blocchi fisici del

dispositivo e poi ne verifica l’integrità. Se si usa device mapper usando dm-crypt i blocchi

vengono automaticamente decriptati in lettura e criptati in scrittura. La lettura di un blocco

è permessa solo se il controllo di integrità effettuato da device mapper ha avuto successo,

se altrimenti il blocco è stato corrotto dal rootkit che l’ha modificato, viene generato un

errore di sistema e la lettura viene impedita [4], [7].

25

3.2 Crittografia

I dati personali dell’utente rappresentano nella maggior parte dei casi l’obiettivo primario

di un attacco da parte di malintenzionato. Android offre diversi meccanismi di sicurezza

affinché l’attacco venga sventato ed uno dei pilastri fondamentali è la cifratura dei dati.

Cifrare i dati è una tecnica molto antica che consiste nel convertire il testo in chiaro in un

testo cifrato usando un schema di cifratura noto solo al proprietario dei dati.

Android implementa questa funzionalità attraverso la Full Disk Encryption - FDE cioè

tutto ciò che è presente sul disco rigido nella partizione userdata è criptato, solo una

piccola parte del sistema operativo viene lasciata in chiaro ed è la parte in cui è

memorizzata la chiave di decifratura attraverso la quale è possibile decriptare i file. Questa

chiave di decifratura però è un componente sensibile del meccanismo e perciò va cifrata

anch’essa attraverso una chiave di cifratura di chiave nota come KEK – Key Encryption

Key. La KEK è mantenuta separata in un blocco hardware oppure è derivata da una

password inserita dall’utente. Come scritto in precedenza il modulo attraverso cui è

possibile criptare i dati è dm-crypt, esso usa una chiave crittografica casuale a 128 bit

insieme al sistema AES - Advanced Encryption Standard nella modalità CBC. Il problema

di questa tecnica crittografica è che essa necessita di una sequenza di bit generata in modo

casuale nota come IV – Initialization Vector, essendo la memoria acceduta in maniera non

sequenziale è quindi necessario generare tante sequenze quanti sono i blocchi criptati.

Android affronta la situazione usando il vettore ESSIV – Encrypted Salt Selector IV e

l’algoritmo di hashing SHA-256. L’algoritmo SHA-256 è usato dall’ESSIV per generare

una chiave secondaria, nota come salt, a partire dalla chiave di crittazione del disco. La

chiave salt è poi usata come chiave crittografica per criptare i numeri di settore di ogni

blocco, il risultato di ciascuna operazione di crittazione è l’IV, generato casualmente, del

relativo settore.

Per cifrare la chiave di decifratura attraverso la KEK è possibile utilizzare una password

immessa dall’utente. Android ha utilizzato a lungo l’algoritmo di derivazione PBKDF2

per generare una chiave crittografica a partire da una password, quest’ultimo utilizza una

sequenza casuale di 128 bit e solo 2000 iterazioni. Un numero così basso di iterazioni per

26

generare una chiave crittografica è diventato un ostacolo alla sicurezza della chiave

giacché attraverso tecniche di brute force che impiegano il multi core e le GPU di un

calcolatore è possibile trovare la chiave in un lasso di tempo ragionevole.

Per ovviare a questo problema gli sviluppatori di Android a partire dalla versione 4.4

KitKat hanno introdotto un nuovo metodo di cifratura noto come script il quale impiega

un numero molto più elevato di iterazioni e tende a saturare la memoria fisica dei

calcolatori che impiegano tecniche di brute force [7].

3.3 Screen lock

Lo screen locking è un meccanismo di sicurezza che mira ad evitare che una persona non

autorizzata acceda all’interfaccia utente del dispositivo in maniera incontrollata; gli screen

lock non sono altro che applicazioni regolari eseguite ogni volta che il dispositivo viene

acceso oppure lo schermo viene illuminato.

Queste applicazioni sono delle viste appartenenti ad una classe contenitore chiamata

KeyguardHostView, che invoca di volta in volta il metodo di screen lock impostato e

memorizza le password selezionate, il controllo delle password è effettuato dalla classe

LockPatternUtils. Android ad oggi prevede cinque metodi di screen lock: slide, face

unlock, pattern unlock e pin/password.

Il metodo slide è equivalente a nessuna protezione, infatti l’applicazione dedicata mostra

solo una schermata il cui sblocco è possibile trascinando il dito verso destra o sinistra.

Il metodo face unlock fa parte della sicurezza biometrica ed è disponibile solo per i

dispositivi provvisti di una fotocamera frontale, attraverso quest’ultima è possibile

mostrare il viso dell’utente all’applicazione integrata di rilievo facciale. Sebbene questo

metodo possa sembrare sicuro in realtà esso non lo è affatto giacché il controllo fallisce in

caso di luce non sufficiente, ad ogni modo questo metodo necessita di uno degli altri

metodi di sblocco in caso non sia possibile usarlo.

Il metodo del pattern unlock prevede che l’utente digiti una sequenza di punti attraverso

l’uso di una matrice 3x3, la sequenza per essere valida deve essere maggiore di tre punti

ed inferiore a dieci punti, inoltre non deve contenere ripetizioni. Ad ogni punto è associato

27

un numero: 0 è associato al punto in alto a sinistra e 8 al punto in basso a destra, questa

associazione rende il pattern simile ad un pin tuttavia l’esclusione delle ripetizioni fa sì

che il pattern sia molto più semplice. Il pattern selezionato viene salvato dal metodo

saveLockPattern() della classe LockScreenUtils che ne salva l’hash e lo ripone nella

directory di sistema /data/system/gesture.key. L’hash dei pattern però non viene generato

usando sequenze casuali e ciò rende gli hash delle varie sequenze tutti uguali per ogni

dispositivo, online sono disponibile delle tabelle che associano ad ogni hash la rispettiva

sequenza. Ciò che rende il pattern unlock un metodo non sicuro è una tecnica di

ingegneria sociale chiamata smudge attack, questa tecnica sfrutta la striscia lasciata dal

dito sul touch screen per discernere il pattern di sblocco.

I metodi pin/password unlock sono simili e quindi possono essere trattati insieme, viene

chiesto all’utente di inserire un pin o una password di cui ne sarà calcolato l’hash

combinando gli hash di SHA-1 e MD5 con un valore casuale a 64 bit. L’hash viene poi

salvato in una directory di sistema, /data/misc/password.key, dal metodo

saveLockPassword() della classe LockPatternUtils. Il pin/password inserito viene

confrontato dal metodo checkPassword() della medesima classe [5], [7].

3.4 Sicurezza del Radio Interface Layer

Il Radio Interface Layer - RIL è lo strato costruito appositamente per gestire tutti i tipi di

comunicazione radiotelefonica disponibili: GSM, GPRS, EDGE, CDMA (3G) e LTE

(4G). Va da sé che i servizi come le telefonate, gli sms, le videochiamate ed il networking

non potrebbero esistere senza il supporto di questo strato. Ogni pacchetto dati inviato o

ricevuto passa per lo stack RIL prima di giungere a destinazione. Proprio a causa di questa

sua centralità il RIL è un obiettivo appetibile per malintenzionati, i quali se avessero

successo nei loro attacchi potrebbero spiare le comunicazioni o sfruttare le risorse

economiche della vittima. Le comunicazioni radio in Android avvengono tramite

l’interazione di due sistemi: il sistema principale ed il sistema in banda base. Il sistema

principale è quello classico rappresentato dall’architettura di Von Neumann, il sistema in

banda base invece è costituito da due blocchi correlati il primo blocco indica qual è la rete

28

di dati utilizzata (es. GSM) ed il secondo blocco invece è l’insieme di una CPU, una

memoria ed un DSP - Digital Signal Processor. I due blocchi comunicano con il sistema

principale attraverso l’uso di dispositivi UART- Universal Asynchronous Receiver

Transmitter. Lo stack può essere visto come segue:

Analizzando la struttura seguendo un approccio bottom-up, notiamo che:

il kernel di Android possiede i driver per interagire con il sistema in banda base ed allo

stesso tempo mette a disposizione un’interfaccia allo strato userspace per far sì che il suo

daemon possa disporre dei servizi necessari. Lo strato userspace possiede appunto un

daemon nativo chiamato rild ed una relativa libreria nota come vendor RIL. Lo strato di

application framework a sua volta fornisce un’interfaccia alle applicazioni dello strato

sovrastante per usufruire dei servizi del rild ed inoltre provvede a delle astrazioni utili a

29

diversificare i servizi richiesti in base alla rete utilizzata. Infine lo strato application ospita

tutte le applicazioni che sfruttano i servizi di radiotelefonia. Google chiama queste

applicazioni tracker.

È chiaro che la più importante dello stack è il daemon nativo rild, esso ha il compito di

gestire le comunicazioni tra l’application framework e l’hardware di sistema. Per svolgere

le sue mansioni il daemon allo start up carica le librerie vendor e poi crea una interfaccia

Binder verso lo strato superiore. Le API del rild devono gestire una grande varietà di

hardware pertanto la libreria possiedono un gran numero di funzioni specifiche per ciascun

componente. Il daemon possiede all’inizio della propria vita i privilegi di root, ma essendo

un componente attaccabile dall’esterno gli vengono revocati e gli sono accordati i privilegi

di rango radio.

Il protocollo con cui il rild comunica con lo strato hardware è differente da costruttore a

costruttore, quest’inclinazione verso protocolli proprietari ha portato alla possibilità di

personalizzare lo stack telefonico in modo da renderlo più adatto alle esigenze degli

sviluppatori di terze parti.

L’arma usata dagli sviluppatori di Android per prevenire gli attacchi al Radio Interface

Layer è quello di eseguire il fuzzing, cioè porre in ingresso dei dati malevoli, documentare

il comportamento del sistema e se si è in presenza di un exploit o di un malfunzionamento,

correggerlo. Il fuzzing si è rivelato molto utile in quanto dal primo rilascio di Android esso

ha permesso di scovare e correggere molti malfunzionamenti, come quello relativo al

servizio SMS [2], [4].

30

Conclusioni

L’attenzione con cui sono stati progettati i meccanismi di sicurezza del sistema operativo

Android ne fa senza dubbio uno dei sistemi informatici più sicuri disponibili attualmente

per i dispositivi mobili.1 Ogni nuova versione porta con sé innovazioni o perfezioni dei

meccanismi di sicurezza in modo tale da rendere l’esperienza dell’utilizzo sempre più

fidata. Tuttavia la cura quasi maniacale per tutti i dettagli implicati nella gestione della

sicurezza non rende Android un sistema operativo perfetto, impenetrabile oppure

infallibile. Se da un lato ci sono migliaia di uomini e donne che si impegnano a rendere

Android sempre più sicuro, dall’altro lato ci sono sempre più persone che lavorano per

sfruttare le vulnerabilità di Android a proprio favore. In mezzo a queste due categorie si

trovano gli utenti di Android i quali spesso sono ignari del lavoro di ambo le parti. Google

cerca di tutelare i suoi utenti anche attraverso la divulgazione informatica, infatti ha reso

disponibili il sito web: https://source.android.com/devices/tech/security/index.html e la

community: https://groups.google.com/forum/#!forum/android-security-discuss affinché

gli utenti possano imparare di più sul sistema operativo mobile e possano confrontarsi

sulle varie tematiche relative alla sicurezza. Molti ricercatori convengono, ed io mi trovo

d’accordo, che bisognerebbe introdurre in Android un piccolo manuale che spieghi

all’utente quali sono le azioni da intraprendere e quali quelle da evitare per migliorare al

massimo la sicurezza del sistema operativo.

1https://static.googleusercontent.com/media/source.android.com/it//devices/tech/security/reports/Google_Android_Secu

rity_2014_Report_Final.pdf

31

Bibliografia

[1] Sito ufficiale di Android, https://www.android.com/history/

[2] Sito ufficiale di Android Open source project,

https://source.android.com/devices/tech/security/

[3] A. Tanenbaum, Modern Operating Systems 4th ed, Pearson, pp 802-850

[4] J. J. Drake, P. Oliva Fora, Z. Lanier, C. Mulliner, Stephen A. Ridley, G. Wicherski.

Android Hacker's Handbook, Riley, cap. 5, cap. 10 e cap. 11

[5] A. Gargenta, Deep Dive into Android Security, The Android Developer Conference II

[6] Sito di divulgazione su Android,

http://seandroid.bitbucket.org/PapersandPresentations.html#3

[7] N. Elenkov, Android Security Internals, No Starch Press, 2014

[8] P. Faruki, A. Bharmal, V. Laxmi, V. Ganmoor, M. Gaur, M. Conti, M. Rajarajan,

Android Security: A Survey of Issues, Malware Penetration and Defenses, IEEE

Communications Surveys and Tutorials, January 2015

[9] Y. Zhaunirovich, Android Securty (and not) Internals, ebook gratuito

[10] M. Mitchell, J. Oldham, A. Samuel, Advanced Linux Programming, New Rider

Publishing, 2001, cap 10

32

Lista delle figure

[1] http://jaredrummler.com/2014/11/09/lollipop-land/

[2] Android Security Internals, pp. 2

[3] http://www.cubrid.org/blog/dev-platform/binder-communication-mechanism-of-

android-processes/

[4] Deep Dive into Android Security, slide 7.

[5] Android Hacker's Handbook, pp. 370