Introduce app_data_file_type attribute.
This gives us an easy way for the policy to refer to all existing or
future types used for app private data files in type= assignments in
seapp_contexts.
Apply the label to all the existing types, then refactor rules to use
the new attribute.
This is intended as a pure refactoring, except that:
- Some neverallow rules are extended to cover types they previous
omitted;
- We allow iorap_inode2filename limited access to shell_data_file and
nfc_data_file;
- We allow zygote limited access to system_app_data_file.
Also extend check_seapp to check that all types specified in
seapp_contexts files have the attribute, to ensure that the neverallow
rules apply to them. As a small bonus, also verify that domain and
type values are actually types not attributes.
Test: Presubmits
Test: Manual: specify an invalid type, build breaks.
Bug: 171795911
Change-Id: Iab6018af449dab3b407824e635dc62e3d81e07c9
diff --git a/private/app_zygote.te b/private/app_zygote.te
index 9285323..98ef3ed 100644
--- a/private/app_zygote.te
+++ b/private/app_zygote.te
@@ -93,14 +93,7 @@
neverallow app_zygote property_type:property_service set;
# Should not have any access to data files.
-neverallow app_zygote {
- bluetooth_data_file
- nfc_data_file
- radio_data_file
- shell_data_file
- app_data_file
- privapp_data_file
-}:file { rwx_file_perms };
+neverallow app_zygote app_data_file_type:file { rwx_file_perms };
neverallow app_zygote {
service_manager_type
diff --git a/private/seapp_contexts b/private/seapp_contexts
index 487a577..dedc315 100644
--- a/private/seapp_contexts
+++ b/private/seapp_contexts
@@ -79,7 +79,8 @@
# domain= determines the label to be used for the app process; entries
# without domain= are ignored for this purpose.
# type= specifies the label to be used for the app data directory; entries
-# without type= are ignored for this purpose.
+# without type= are ignored for this purpose. The label specified must
+# have the app_data_file_type attribute.
# levelFrom and level are used to determine the level (sensitivity + categories)
# for MLS/MCS.
# levelFrom=none omits the level.
diff --git a/private/system_server.te b/private/system_server.te
index 0d48554..889a11b 100644
--- a/private/system_server.te
+++ b/private/system_server.te
@@ -519,16 +519,7 @@
allow system_server staging_data_file:file create_file_perms;
# Walk /data/data subdirectories.
-# Types extracted from seapp_contexts type= fields.
-allow system_server {
- system_app_data_file
- bluetooth_data_file
- nfc_data_file
- radio_data_file
- shell_data_file
- app_data_file
- privapp_data_file
-}:dir { getattr read search };
+allow system_server app_data_file_type:dir { getattr read search };
# Also permit for unlabeled /data/data subdirectories and
# for unlabeled asec containers on upgrades from 4.2.
@@ -541,16 +532,7 @@
allow system_server system_app_data_file:file create_file_perms;
# Receive and use open app data files passed over binder IPC.
-# Types extracted from seapp_contexts type= fields.
-allow system_server {
- system_app_data_file
- bluetooth_data_file
- nfc_data_file
- radio_data_file
- shell_data_file
- app_data_file
- privapp_data_file
-}:file { getattr read write append map };
+allow system_server app_data_file_type:file { getattr read write append map };
# Access to /data/media for measuring disk usage.
allow system_server media_rw_data_file:dir { search getattr open read };
@@ -1041,14 +1023,11 @@
# system server should never be operating on zygote spawned app data
# files directly. Rather, they should always be passed via a
# file descriptor.
-# Types extracted from seapp_contexts type= fields, excluding
-# those types that system_server needs to open directly.
+# Exclude those types that system_server needs to open directly.
neverallow system_server {
- bluetooth_data_file
- nfc_data_file
- shell_data_file
- app_data_file
- privapp_data_file
+ app_data_file_type
+ -system_app_data_file
+ -radio_data_file
}:file { open create unlink link };
# Forking and execing is inherently dangerous and racy. See, for
diff --git a/private/webview_zygote.te b/private/webview_zygote.te
index 969ab9c..bdad219 100644
--- a/private/webview_zygote.te
+++ b/private/webview_zygote.te
@@ -103,15 +103,7 @@
neverallow webview_zygote property_type:property_service set;
# Should not have any access to app data files.
-neverallow webview_zygote {
- app_data_file
- privapp_data_file
- system_app_data_file
- bluetooth_data_file
- nfc_data_file
- radio_data_file
- shell_data_file
-}:file { rwx_file_perms };
+neverallow webview_zygote app_data_file_type:file { rwx_file_perms };
neverallow webview_zygote {
service_manager_type
diff --git a/private/zygote.te b/private/zygote.te
index fac9ad0..d3d08bf 100644
--- a/private/zygote.te
+++ b/private/zygote.te
@@ -77,15 +77,10 @@
allow zygote mirror_data_file:dir r_dir_perms;
-# Get inode of data directories
+# Get inode of directories for app data isolation
allow zygote {
+ app_data_file_type
system_data_file
- radio_data_file
- app_data_file
- shell_data_file
- bluetooth_data_file
- privapp_data_file
- nfc_data_file
mnt_expand_file
}:dir getattr;
@@ -245,7 +240,4 @@
}:file create_file_perms;
# Zygote should not be able to access app private data.
-neverallow zygote {
- privapp_data_file
- app_data_file
-}:dir ~getattr;
+neverallow zygote app_data_file_type:dir ~getattr;
diff --git a/public/attributes b/public/attributes
index 2ebcd6f..754dd9e 100644
--- a/public/attributes
+++ b/public/attributes
@@ -34,6 +34,10 @@
attribute core_data_file_type;
expandattribute core_data_file_type false;
+# All types used for app private data files under /data/data.
+attribute app_data_file_type;
+expandattribute app_data_file_type false;
+
# All types in /system
attribute system_file_type;
diff --git a/public/domain.te b/public/domain.te
index 0e5dde9..4e7347b 100644
--- a/public/domain.te
+++ b/public/domain.te
@@ -1216,6 +1216,7 @@
-dumpstate
-init
-installd
+ -iorap_inode2filename
-simpleperf_app_runner
-system_server # why?
userdebug_or_eng(`-uncrypt')
diff --git a/public/file.te b/public/file.te
index 8ddaf2f..782ea40 100644
--- a/public/file.te
+++ b/public/file.te
@@ -299,7 +299,7 @@
# /data/resource-cache
type resourcecache_data_file, file_type, data_file_type, core_data_file_type;
# /data/local - writable by shell
-type shell_data_file, file_type, data_file_type, core_data_file_type, mlstrustedobject;
+type shell_data_file, file_type, data_file_type, core_data_file_type, app_data_file_type, mlstrustedobject;
# /data/property
type property_data_file, file_type, data_file_type, core_data_file_type;
# /data/bootchart
@@ -369,7 +369,7 @@
type apex_wifi_data_file, file_type, data_file_type, core_data_file_type;
type audio_data_file, file_type, data_file_type, core_data_file_type;
type audioserver_data_file, file_type, data_file_type, core_data_file_type;
-type bluetooth_data_file, file_type, data_file_type, core_data_file_type;
+type bluetooth_data_file, file_type, data_file_type, core_data_file_type, app_data_file_type;
type bluetooth_logs_data_file, file_type, data_file_type, core_data_file_type;
type bootstat_data_file, file_type, data_file_type, core_data_file_type;
type boottrace_data_file, file_type, data_file_type, core_data_file_type;
@@ -384,9 +384,9 @@
type misc_user_data_file, file_type, data_file_type, core_data_file_type;
type net_data_file, file_type, data_file_type, core_data_file_type;
type network_watchlist_data_file, file_type, data_file_type, core_data_file_type;
-type nfc_data_file, file_type, data_file_type, core_data_file_type;
+type nfc_data_file, file_type, data_file_type, core_data_file_type, app_data_file_type;
type nfc_logs_data_file, file_type, data_file_type, core_data_file_type;
-type radio_data_file, file_type, data_file_type, core_data_file_type, mlstrustedobject;
+type radio_data_file, file_type, data_file_type, core_data_file_type, app_data_file_type, mlstrustedobject;
type recovery_data_file, file_type, data_file_type, core_data_file_type;
type shared_relro_file, file_type, data_file_type, core_data_file_type, mlstrustedobject;
type snapshotctl_log_data_file, file_type, data_file_type, core_data_file_type;
@@ -407,11 +407,11 @@
type gsi_data_file, file_type, data_file_type, core_data_file_type;
# /data/data subdirectories - app sandboxes
-type app_data_file, file_type, data_file_type, core_data_file_type;
+type app_data_file, file_type, data_file_type, core_data_file_type, app_data_file_type;
# /data/data subdirectories - priv-app sandboxes
-type privapp_data_file, file_type, data_file_type, core_data_file_type;
+type privapp_data_file, file_type, data_file_type, core_data_file_type, app_data_file_type;
# /data/data subdirectory for system UID apps.
-type system_app_data_file, file_type, data_file_type, core_data_file_type, mlstrustedobject;
+type system_app_data_file, file_type, data_file_type, core_data_file_type, app_data_file_type, mlstrustedobject;
# Compatibility with type name used in Android 4.3 and 4.4.
# Default type for anything under /cache
type cache_file, file_type, data_file_type, core_data_file_type, mlstrustedobject;
diff --git a/public/installd.te b/public/installd.te
index c8cc89d..53acaf0 100644
--- a/public/installd.te
+++ b/public/installd.te
@@ -111,27 +111,8 @@
# upon creation via setfilecon or running restorecon_recursive,
# setting owner/mode, creating symlinks within them, and deleting them
# upon package uninstall.
-
-# Types extracted from seapp_contexts type= fields.
-allow installd {
- system_app_data_file
- bluetooth_data_file
- nfc_data_file
- radio_data_file
- shell_data_file
- app_data_file
- privapp_data_file
-}:dir { create_dir_perms relabelfrom relabelto };
-
-allow installd {
- system_app_data_file
- bluetooth_data_file
- nfc_data_file
- radio_data_file
- shell_data_file
- app_data_file
- privapp_data_file
-}:notdevfile_class_set { create_file_perms relabelfrom relabelto };
+allow installd app_data_file_type:dir { create_dir_perms relabelfrom relabelto };
+allow installd app_data_file_type:notdevfile_class_set { create_file_perms relabelfrom relabelto };
# Allow zygote to unmount mirror directories
allow installd labeledfs:filesystem unmount;
diff --git a/public/iorap_inode2filename.te b/public/iorap_inode2filename.te
index 4041ddd..aaf4520 100644
--- a/public/iorap_inode2filename.te
+++ b/public/iorap_inode2filename.te
@@ -21,24 +21,18 @@
allow iorap_inode2filename apex_mnt_dir:file { getattr };
allow iorap_inode2filename apk_data_file:dir { getattr open read search };
allow iorap_inode2filename apk_data_file:file { getattr };
-allow iorap_inode2filename app_data_file:dir { getattr open read search };
-allow iorap_inode2filename app_data_file:file { getattr };
+allow iorap_inode2filename app_data_file_type:dir { getattr open read search };
+allow iorap_inode2filename app_data_file_type:file { getattr };
allow iorap_inode2filename backup_data_file:dir { getattr open read search };
allow iorap_inode2filename backup_data_file:file { getattr };
-allow iorap_inode2filename bluetooth_data_file:dir { getattr open read search };
-allow iorap_inode2filename bluetooth_data_file:file { getattr };
allow iorap_inode2filename bootchart_data_file:dir { getattr open read search };
allow iorap_inode2filename bootchart_data_file:file { getattr };
allow iorap_inode2filename metadata_file:dir { getattr open read search search };
allow iorap_inode2filename metadata_file:file { getattr };
allow iorap_inode2filename packages_list_file:dir { getattr open read search };
allow iorap_inode2filename packages_list_file:file { getattr };
-allow iorap_inode2filename privapp_data_file:dir { getattr open read search };
-allow iorap_inode2filename privapp_data_file:file { getattr };
allow iorap_inode2filename property_data_file:dir { getattr open read search };
allow iorap_inode2filename property_data_file:file { getattr };
-allow iorap_inode2filename radio_data_file:dir { getattr open read search };
-allow iorap_inode2filename radio_data_file:file { getattr };
allow iorap_inode2filename resourcecache_data_file:dir { getattr open read search };
allow iorap_inode2filename resourcecache_data_file:file { getattr };
allow iorap_inode2filename recovery_data_file:dir { getattr open read search };
@@ -51,8 +45,6 @@
allow iorap_inode2filename staging_data_file:file { getattr };
allow iorap_inode2filename system_bootstrap_lib_file:dir { getattr open read search };
allow iorap_inode2filename system_bootstrap_lib_file:file { getattr };
-allow iorap_inode2filename system_app_data_file:dir { getattr open read search };
-allow iorap_inode2filename system_app_data_file:file { getattr };
allow iorap_inode2filename system_data_file:dir { getattr open read search };
allow iorap_inode2filename system_data_file:file { getattr };
allow iorap_inode2filename system_data_file:lnk_file { getattr open read };
diff --git a/public/netd.te b/public/netd.te
index 48e79b7..ff0bff6 100644
--- a/public/netd.te
+++ b/public/netd.te
@@ -128,7 +128,7 @@
neverallow netd system_file:dir_file_class_set write;
# Write to files in /data/data or system files on /data
-neverallow netd { app_data_file privapp_data_file system_data_file }:dir_file_class_set write;
+neverallow netd { app_data_file_type system_data_file }:dir_file_class_set write;
# only system_server, dumpstate and network stack app may find netd service
neverallow {
diff --git a/tools/check_seapp.c b/tools/check_seapp.c
index 1d695c0..2b06c11 100644
--- a/tools/check_seapp.c
+++ b/tools/check_seapp.c
@@ -20,6 +20,8 @@
#define log_warn(fmt, ...) log_msg(stderr, "Warning: ", fmt, ##__VA_ARGS__)
#define log_info(fmt, ...) if (logging_verbose ) { log_msg(stdout, "Info: ", fmt, ##__VA_ARGS__); }
+#define APP_DATA_REQUIRED_ATTRIB "app_data_file_type"
+
/**
* Initializes an empty, static list.
*/
@@ -192,7 +194,8 @@
/* validation call backs */
static bool validate_bool(char *value, char **errmsg);
static bool validate_levelFrom(char *value, char **errmsg);
-static bool validate_selinux_type(char *value, char **errmsg);
+static bool validate_domain(char *value, char **errmsg);
+static bool validate_type(char *value, char **errmsg);
static bool validate_selinux_level(char *value, char **errmsg);
static bool validate_uint(char *value, char **errmsg);
@@ -213,8 +216,8 @@
{ .name = "minTargetSdkVersion", .dir = dir_in, .fn_validate = validate_uint },
{ .name = "fromRunAs", .dir = dir_in, .fn_validate = validate_bool },
/*Outputs*/
- { .name = "domain", .dir = dir_out, .fn_validate = validate_selinux_type },
- { .name = "type", .dir = dir_out, .fn_validate = validate_selinux_type },
+ { .name = "domain", .dir = dir_out, .fn_validate = validate_domain },
+ { .name = "type", .dir = dir_out, .fn_validate = validate_type },
{ .name = "levelFromUid", .dir = dir_out, .fn_validate = validate_bool },
{ .name = "levelFrom", .dir = dir_out, .fn_validate = validate_levelFrom },
{ .name = "level", .dir = dir_out, .fn_validate = validate_selinux_level },
@@ -295,28 +298,39 @@
}
/**
- * Checks for a type in the policy.
+ * Look up a type in the policy.
* @param db
* The policy db to search
* @param type
* The type to search for
+ * @param flavor
+ * The expected flavor of type
* @return
- * 1 if the type is found, 0 otherwise.
+ * Pointer to the type's datum if it exists in the policy with the expected
+ * flavor, NULL otherwise.
* @warning
- * This function always returns 1 if libsepol is not linked
- * statically to this executable and LINK_SEPOL_STATIC is not
- * defined.
+ * This function should not be called if libsepol is not linked statically
+ * to this executable and LINK_SEPOL_STATIC is not defined.
*/
-static int check_type(sepol_policydb_t *db, char *type) {
+static type_datum_t *find_type(sepol_policydb_t *db, char *type, uint32_t flavor) {
- int rc = 1;
-#if defined(LINK_SEPOL_STATIC)
- policydb_t *d = (policydb_t *)db;
- hashtab_datum_t dat;
- dat = hashtab_search(d->p_types.table, type);
- rc = (dat == NULL) ? 0 : 1;
-#endif
- return rc;
+ policydb_t *d = &db->p;
+ hashtab_datum_t dat = hashtab_search(d->p_types.table, type);
+ if (!dat) {
+ return NULL;
+ }
+ type_datum_t *type_dat = (type_datum_t *) dat;
+ if (type_dat->flavor != flavor) {
+ return NULL;
+ }
+ return type_dat;
+}
+
+static bool type_has_attribute(sepol_policydb_t *db, type_datum_t *type_dat,
+ type_datum_t *attrib_dat) {
+ policydb_t *d = &db->p;
+ ebitmap_t *attr_bits = &d->type_attr_map[type_dat->s.value - 1];
+ return ebitmap_get_bit(attr_bits, attrib_dat->s.value - 1) != 0;
}
static bool match_regex(key_map *assert, const key_map *check) {
@@ -375,7 +389,7 @@
static bool validate_levelFrom(char *value, char **errmsg) {
- if(strcasecmp(value, "none") && strcasecmp(value, "all") &&
+ if (strcasecmp(value, "none") && strcasecmp(value, "all") &&
strcasecmp(value, "app") && strcasecmp(value, "user")) {
*errmsg = "Expecting one of: \"none\", \"all\", \"app\" or \"user\"";
return false;
@@ -383,8 +397,9 @@
return true;
}
-static bool validate_selinux_type(char *value, char **errmsg) {
+static bool validate_domain(char *value, char **errmsg) {
+#if defined(LINK_SEPOL_STATIC)
/*
* No policy file present means we cannot check
* SE Linux types
@@ -393,10 +408,45 @@
return true;
}
- if(!check_type(pol.db, value)) {
+ if (!find_type(pol.db, value, TYPE_TYPE)) {
*errmsg = "Expecting a valid SELinux type";
return false;
}
+#endif
+
+ return true;
+}
+
+static bool validate_type(char *value, char **errmsg) {
+
+#if defined(LINK_SEPOL_STATIC)
+ /*
+ * No policy file present means we cannot check
+ * SE Linux types
+ */
+ if (!pol.policy_file) {
+ return true;
+ }
+
+ type_datum_t *type_dat = find_type(pol.db, value, TYPE_TYPE);
+ if (!type_dat) {
+ *errmsg = "Expecting a valid SELinux type";
+ return false;
+ }
+
+ type_datum_t *attrib_dat = find_type(pol.db, APP_DATA_REQUIRED_ATTRIB,
+ TYPE_ATTRIB);
+ if (!attrib_dat) {
+ /* If the policy doesn't contain the attribute, we can't check it */
+ return true;
+ }
+
+ if (!type_has_attribute(pol.db, type_dat, attrib_dat)) {
+ *errmsg = "Missing required attribute " APP_DATA_REQUIRED_ATTRIB;
+ return false;
+ }
+
+#endif
return true;
}
@@ -807,7 +857,7 @@
oom:
log_error("Out of memory!\n");
err:
- if(new_map) {
+ if (new_map) {
rule_map_free(new_map, false);
for (; i < num_of_keys; i++) {
k = &(keys[i]);
@@ -1013,7 +1063,7 @@
* when you want to override the outputs for a given input set, as well as
* checking for duplicate entries.
*/
- if(f) {
+ if (f) {
log_info("Existing entry found!\n");
tmp = (hash_entry *)f->data;
cmp = rule_map_cmp(rm, tmp->r);
@@ -1035,7 +1085,7 @@
e.data = entry;
f = hsearch(e, ENTER);
- if(f == NULL) {
+ if (f == NULL) {
goto oom;
}
@@ -1143,7 +1193,7 @@
err:
log_error("Reading file: \"%s\" line: %zu name: \"%s\" value: \"%s\"\n",
in_file->name, lineno, name, value);
- if(found_whitespace && name && !strcasecmp(name, "neverallow")) {
+ if (found_whitespace && name && !strcasecmp(name, "neverallow")) {
log_error("perhaps whitespace before neverallow\n");
}
exit(EXIT_FAILURE);