User-centric - programs run on behalf of users, thus can access any of the user’s files!
Running a UNIX program:
fork
+ exec
ld.so
dynamic library loading + sharing → memory savingComposition on shell:
pipe
s + fork
+ exec
$ echo $PATH | tr : "\n" | wc -l
files
directories
/proc/*
/dev/*
→ Shell composition of programs can process on all system resources!
→ UNIX APIs for file manipulation manipulate all resources (polymorphism)!
setuid
BitsWe can use setuid
bits to coordinate services that serve multiple users.
/etc/passwd
)setuid
bit programs update filesdaemons
) consume and act on filesroot
root
permission is all or nothingroot
required for many roles (e.g. chown
)Examples:
root
required for login
? Only require 1. access to password file, and 2. ability to setuid
to user./etc/
owned by root
; why are the files in /dev/
all owned by root
(e.g. /dev/mem
)Traditional services:
→ Each user (and all of their programs) can interact with the service
Should everyone’s programs be able to interact with core services?
Discretionary Access Control (DAC): Users restrict access to their own files/data, and can indiscriminately pass that privilege.
Mandatory Access Control (MAC): Users restricted in sharing files/data by system-wide policies that restrict sharing relationships.
All of a user’s data is accessible to every program they execute. Assume a program will be attacked and compromised. How can we minimize its negative effects?
Principle of least privilege: Only give the access required to accomplish a program’s goals.
Examples:
App-store model is central
Apps cannot access each other’s resources!
Default: share nothing.
App-centric - programs have separate, limited access to files
Sensitive resources are not just files
Must limit App access to each of these, based on App’s goals/requirements.
By-default deny App access to resources, mediated IPC
Idea: Apps are not trusted. Isolate them from each other!
They are run by the user, but
Example: Banking App running alongside flashlight app
Services oversee key abstraction/resources
Resources include
Only Apps with permissions given by the user should be able to communicate with these services.
UNIX programs:
fork
+ exec
ld.so
dynamic library loadingJava VM program execution:
fork
classpath
)imports
)An application’s computation is always within a JVM. This means:
JVM-first execution abstractions
The Java VM has a huge number of large packages
Zygote: single process that is the parent of all Apps and Services.
fork
s the new App/Servicesetuid
to the App’s uid
(zygote is root
)uid
/gid
s, not usersApps explicitly specify their resource requirements
Apps have a permission manifest: what resources they can access.
<permission name="android.permission.BLUETOOTH" >
<group gid="net_bt" />
</permission>
<permission name="android.permission.WRITE_MEDIA_STORAGE" >
<group gid="media_rw" />
<group gid="sdcard_rw" />
</permission>
<permission name="android.permission.INTERNET" >
<group gid="inet" />
</permission>
All of the system’s potential permissions.
READ_CONTACTS
permissionApp and Service permissions are tracked and queried:
PermissionManager
+ PackageManager
return AppGlobals.getPackageManager()
.checkUidPermission(permission, uid);
Applications have access only to a small part of the filesystem
uid
and gid
are a unique, per-app values app_N
. I.e. app_6
/data/app/<app_name>/
binary and “ELF-like” data/data/data/<app_name>/
storageIf Apps cannot access each other’s data, how do we have a cohesive, single experience as user?
Our human experience is clicking buttons, and seeing actions. The system need only provide the illusion of a single, shared device.
How?
Illusion of a single, shared device:
Apps communicate to services that provide shared resources
Composition of Apps: communication through intents
/* This is the master Users and Groups config for the platform.*/
#define AID_ROOT 0 /* traditional unix root user */
#define AID_SYSTEM 1000 /* system server */
#define AID_RADIO 1001 /* telephony subsystem, RIL */
#define AID_BLUETOOTH 1002 /* bluetooth subsystem */
#define AID_GRAPHICS 1003 /* graphics devices */
#define AID_INPUT 1004 /* input devices */
#define AID_AUDIO 1005 /* audio devices */
#define AID_CAMERA 1006 /* camera devices */
#define AID_LOG 1007 /* log devices */
#define AID_COMPASS 1008 /* compass device */
#define AID_MOUNT 1009 /* mountd socket */
#define AID_WIFI 1010 /* wifi subsystem */
#define ...
#define AID_WEBVIEW_ZYGOTE 1053 /* WebView zygote process */
/* The 3000 series are intended for use as supplemental group id's only*/
#define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */
#define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm, ... */
#define AID_APP 10000 /* first app user */
#define AID_USER 100000 /* offset for uid ranges for each user */
0
/1000
- root
+ System, 1001...1052
- Devices1053
- Zygote, 10000+
- AppsBinder: domain-socket analog for IPC
names
names
can mimic function calls→ cross App/Service “function invocations”
IPC Connections can be passed to Apps
ServiceManager
nameserver: “here you go, have this connection”uid/gid
of Apps using connection can be queried
AID_INPUT
to be able to input?Package/PermissionManager
: “are they allowed?”Who is making a request to a service? Do they have permissions?
pid
and euid
Binder.getCallingPid()
& Binder.getCallingUid()
ActivityManager.checkComponentPermission(permission, uid, owningUid, exported)
android.os.ServiceManager
includes:
public static void addService(String name, IBinder service) { /* ... */ }
public static IBinder getService(String name) { /* ... */ }
We can see that at its core, Android has a nameserver to map names to IPC channels.
surfaceflinger
to display contents)Coordination:
UNIX focuses on pipelines for composition
stdin
, output on stdout
pipe
s for compositionread
/write
callsAndroid:
Intents: simple action you’d like to perform, identified by a name
List of default intents. These include:
ActivityManager
is nameserver for intents
// java code to send an email!
public void composeEmail(String[] addresses, String subject, Uri attachment) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_EMAIL, addresses);
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_STREAM, attachment);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
}
PRE_BOOT_COMPLETED
intentBOOT_COMPLETED
intentApp might trigger many intents
INPUT_METHOD_SERVICE
to read from onscreen keyboardACTION_SEND
to send emailActivityManager
implements this intent system
SystemServer
processFor functionality: void startActivity (Intent intent)
intent
the InputManager
multiplexes user input between InputMethod
s.
stdin
? Up to the system to decide if stdin
is a pipe, or a terminal. Polymorphic!InputMethod
s (link) are things like on-screen keyboards that are Services activated by intents from the InputManager
.
INPUT_METHOD_SERVICE
intent0
”; we know it will give us input.App → ActivityManager
(INPUT_METHOD_SERVICE
) → InputMethod
uid
/pid
of clientActivityManager
checks if the client has permissions to access resource/trigger intentroot
// frameworks/base/core/java/android/app/ActivityManager.java
public class ActivityManager {
public static int checkComponentPermission(String permission, int uid,
int owningUid, boolean exported) {
final int appId = UserHandle.getAppId(uid);
if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) {
return PackageManager.PERMISSION_GRANTED;
}
if (UserHandle.isIsolated(uid)) {
return PackageManager.PERMISSION_DENIED;
}
if (owningUid >= 0 && UserHandle.isSameApp(uid, owningUid)) {
return PackageManager.PERMISSION_GRANTED;
}
if (!exported) {
return PackageManager.PERMISSION_DENIED;
}
if (permission == null) {
return PackageManager.PERMISSION_GRANTED;
}
try {
return AppGlobals.getPackageManager()
.checkUidPermission(permission, uid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
uid
) for each App/Serviceuid
/pid
of calling AppPackage/PermissionManager
lets us query App permissions→ foundation for per-App access control/privileges
SystemManager
nameserver maps unique name
to a ServiceApps use IPC to request resources from Services
Zygote as the parent of each App
fork
setuid
to restrict App’s privilegesIntent
sApps and Services are activated by intents.
Polymorphic
PRE_BOOT_COMPLETED
intent.INPUT_METHOD_SERVICE
intent.Drives App/Service activation
Communication driven by the ActivityManager
UNIX:
open(Stringpath) → intdescriptor
uid
/gid
descriptortable(intdescriptor) → char[]file
Android:
open(Stringpath) → intdescriptor
uid
/gid
descriptortable(intdescriptor) → char[]file
and
ActivityManager(StringIntent) → BinderChannel
PackageManager
BinderChannel(fn, args…) Service
POSIX | Android |
---|---|
User-centric | App-centric, per-App permissions |
Security through FS | Security through permission manifests |
Shared resources on FS | Shared resources via Services |
Everything’s a file | Everything’s App (JVM) execution |
Shell + pipe composition |
Composition via App IPC through Intent s |
Similar set of system calls to normal UNIX system…
…augmented with pervasive use of IPC…
…to coordinate between Apps and Services…
…while checking per-App permissions…
…all driven by the special trust relationship of untrusted Apps.