Add attribute expansion options

This commit adds attribute expansion statements to the policy
language allowing compiler defaults to be overridden.

Always expands an attribute example:
expandattribute { foo } true;
CIL example:
(expandtypeattribute (foo) true)

Never expand an attribute example:
expandattribute { bar } false;
CIL example:
(expandtypeattribute (bar) false)

Adding the annotations directly to policy was chosen over other
methods as it is consistent with how targeted runtime optimizations
are specified in other languages. For example, in C the "inline"
command.

Motivation

expandattribute true:
Android has been moving away from a monolithic policy binary to
a two part split policy representing the Android platform and the
underlying vendor-provided hardware interface. The goal is a stable
API allowing these two parts to be updated independently of each
other. Attributes provide an important mechanism for compatibility.
For example, when the vendor provides a HAL for the platform,
permissions needed by clients of the HAL can be granted to an
attribute. Clients need only be assigned the attribute and do not
need to be aware of the underlying types and permissions being
granted.

Inheriting permissions via attribute creates a convenient mechanism
for independence between vendor and platform policy, but results
in the creation of many attributes, and the potential for performance
issues when processes are clients of many HALs. [1] Annotating these
attributes for expansion at compile time allows us to retain the
compatibility benefits of using attributes without the performance
costs. [2]

expandattribute false:
Commit 0be23c3f15 added the capability to aggresively remove unused
attributes. This is generally useful as too many attributes assigned
to a type results in lengthy policy look up times when there is a
cache miss. However, removing attributes can also result in loss of
information used in external tests. On Android, we're considering
stripping neverallow rules from on-device policy. This is consistent
with the kernel policy binary which also did not contain neverallows.
Removing neverallow rules results in a 5-10% decrease in on-device
policy build and load and a policy size decrease of ~250k. Neverallow
rules are still asserted at build time and during device
certification (CTS). If neverallow rules are absent when secilc is
run, some attributes are being stripped from policy and neverallow
tests in CTS may be violated. [3] This change retains the aggressive
attribute stripping behavior but adds an override mechanism to
preserve attributes marked as necessary.

[1] https://github.com/SELinuxProject/cil/issues/9
[2] Annotating all HAL client attributes for expansion resulted in
    system_server's dropping from 19 attributes to 8. Because these
    attributes were not widely applied to other types, the final
    policy size change was negligible.
[3] data_file_type and service_manager_type are stripped from AOSP
    policy when using secilc's -G option. This impacts 11 neverallow
    tests in CTS.

Test: Build and boot Marlin with all hal_*_client attributes marked
    for expansion. Verify (using seinfo and sesearch) that permissions
    are correctly expanded from attributes to types.
Test: Mark types being stripped by secilc with "preserve" and verify
    that they are retained in policy and applied to the same types.

Signed-off-by: Jeff Vander Stoep <jeffv@google.com>
This commit is contained in:
Jeff Vander Stoep 2017-05-04 14:36:49 -07:00 committed by James Carter
parent 63aa7fc036
commit 1089665e31
16 changed files with 307 additions and 5 deletions

View File

@ -1139,6 +1139,88 @@ int define_attrib(void)
return 0;
}
int expand_attrib(void)
{
char *id;
ebitmap_t attrs;
type_datum_t *attr;
ebitmap_node_t *node;
uint32_t i;
int rc = -1;
int flags = 0;
if (pass == 1) {
for (i = 0; i < 2; i++) {
while ((id = queue_remove(id_queue))) {
free(id);
}
}
return 0;
}
ebitmap_init(&attrs);
while ((id = queue_remove(id_queue))) {
if (!id) {
yyerror("No attribute name for expandattribute statement?");
goto exit;
}
if (!is_id_in_scope(SYM_TYPES, id)) {
yyerror2("attribute %s is not within scope", id);
goto exit;
}
attr = hashtab_search(policydbp->p_types.table, id);
if (!attr) {
yyerror2("attribute %s is not declared", id);
goto exit;
}
if (attr->flavor != TYPE_ATTRIB) {
yyerror2("%s is a type, not an attribute", id);
goto exit;
}
if (attr->flags & TYPE_FLAGS_EXPAND_ATTR) {
yyerror2("%s already has the expandattribute option specified", id);
goto exit;
}
if (ebitmap_set_bit(&attrs, attr->s.value - 1, TRUE)) {
yyerror("Out of memory!");
goto exit;
}
free(id);
}
id = (char *) queue_remove(id_queue);
if (!id) {
yyerror("No option specified for attribute expansion.");
goto exit;
}
if (!strcmp(id, "T")) {
flags = TYPE_FLAGS_EXPAND_ATTR_TRUE;
} else {
flags = TYPE_FLAGS_EXPAND_ATTR_FALSE;
}
ebitmap_for_each_bit(&attrs, node, i) {
if (!ebitmap_node_get_bit(node, i)){
continue;
}
attr = hashtab_search(policydbp->p_types.table,
policydbp->sym_val_to_name[SYM_TYPES][i]);
attr->flags |= flags;
}
rc = 0;
exit:
ebitmap_destroy(&attrs);
free(id);
return rc;
}
static int add_aliases_to_type(type_datum_t * type)
{
char *id;

View File

@ -65,6 +65,7 @@ int define_typebounds(void);
int define_type(int alias);
int define_user(void);
int define_validatetrans(constraint_expr_t *expr);
int expand_attrib(void);
int insert_id(const char *id,int push);
int insert_separator(int push);
role_datum_t *define_role_dom(role_datum_t *r);

View File

@ -103,6 +103,7 @@ typedef int (* require_func_t)(int pass);
%token TYPES
%token ALIAS
%token ATTRIBUTE
%token EXPANDATTRIBUTE
%token BOOL
%token TUNABLE
%token IF
@ -314,6 +315,7 @@ rbac_decl : attribute_role_def
| role_attr_def
;
te_decl : attribute_def
| expandattribute_def
| type_def
| typealias_def
| typeattribute_def
@ -328,6 +330,9 @@ te_decl : attribute_def
attribute_def : ATTRIBUTE identifier ';'
{ if (define_attrib()) return -1;}
;
expandattribute_def : EXPANDATTRIBUTE names bool_val ';'
{ if (expand_attrib()) return -1;}
;
type_def : TYPE identifier alias_def opt_attr_list ';'
{if (define_type(1)) return -1;}
| TYPE identifier opt_attr_list ';'

View File

@ -106,6 +106,8 @@ ALIAS |
alias { return(ALIAS); }
ATTRIBUTE |
attribute { return(ATTRIBUTE); }
EXPANDATTRIBUTE |
expandattribute { return(EXPANDATTRIBUTE); }
TYPE_TRANSITION |
type_transition { return(TYPE_TRANSITION); }
TYPE_MEMBER |

View File

@ -159,6 +159,7 @@ static void cil_init_keys(void)
CIL_KEY_SELINUXUSERDEFAULT = cil_strpool_add("selinuxuserdefault");
CIL_KEY_TYPEATTRIBUTE = cil_strpool_add("typeattribute");
CIL_KEY_TYPEATTRIBUTESET = cil_strpool_add("typeattributeset");
CIL_KEY_EXPANDTYPEATTRIBUTE = cil_strpool_add("expandtypeattribute");
CIL_KEY_TYPEALIAS = cil_strpool_add("typealias");
CIL_KEY_TYPEALIASACTUAL = cil_strpool_add("typealiasactual");
CIL_KEY_TYPEBOUNDS = cil_strpool_add("typebounds");
@ -623,6 +624,9 @@ void cil_destroy_data(void **data, enum cil_flavor flavor)
case CIL_TYPEATTRIBUTESET:
cil_destroy_typeattributeset(*data);
break;
case CIL_EXPANDTYPEATTRIBUTE:
cil_destroy_expandtypeattribute(*data);
break;
case CIL_TYPEALIASACTUAL:
cil_destroy_aliasactual(*data);
break;
@ -987,6 +991,8 @@ const char * cil_node_to_string(struct cil_tree_node *node)
return CIL_KEY_TYPEALIAS;
case CIL_TYPEATTRIBUTESET:
return CIL_KEY_TYPEATTRIBUTESET;
case CIL_EXPANDTYPEATTRIBUTE:
return CIL_KEY_EXPANDTYPEATTRIBUTE;
case CIL_TYPEALIASACTUAL:
return CIL_KEY_TYPEALIASACTUAL;
case CIL_TYPEBOUNDS:
@ -2038,6 +2044,15 @@ void cil_typeattributeset_init(struct cil_typeattributeset **attrset)
(*attrset)->datum_expr = NULL;
}
void cil_expandtypeattribute_init(struct cil_expandtypeattribute **expandattr)
{
*expandattr = cil_malloc(sizeof(**expandattr));
(*expandattr)->attr_strs = NULL;
(*expandattr)->attr_datums = NULL;
(*expandattr)->expand = 0;
}
void cil_alias_init(struct cil_alias **alias)
{
*alias = cil_malloc(sizeof(**alias));

View File

@ -3176,6 +3176,75 @@ void cil_destroy_typeattributeset(struct cil_typeattributeset *attrset)
free(attrset);
}
int cil_gen_expandtypeattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
CIL_SYN_STRING,
CIL_SYN_STRING | CIL_SYN_LIST,
CIL_SYN_STRING,
CIL_SYN_END
};
char *expand_str;
int syntax_len = sizeof(syntax)/sizeof(*syntax);
struct cil_expandtypeattribute *expandattr = NULL;
int rc = SEPOL_ERR;
if (db == NULL || parse_current == NULL || ast_node == NULL) {
goto exit;
}
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
if (rc != SEPOL_OK) {
goto exit;
}
cil_expandtypeattribute_init(&expandattr);
if (parse_current->next->cl_head == NULL) {
cil_list_init(&expandattr->attr_strs, CIL_TYPE);
cil_list_append(expandattr->attr_strs, CIL_STRING, parse_current->next->data);
} else {
rc = cil_fill_list(parse_current->next->cl_head, CIL_TYPE, &expandattr->attr_strs);
if (rc != SEPOL_OK) {
goto exit;
}
}
expand_str = parse_current->next->next->data;
if (expand_str == CIL_KEY_CONDTRUE) {
expandattr->expand = CIL_TRUE;
} else if (expand_str == CIL_KEY_CONDFALSE) {
expandattr->expand = CIL_FALSE;
} else {
cil_log(CIL_ERR, "Value must be either \'true\' or \'false\'");
goto exit;
}
ast_node->data = expandattr;
ast_node->flavor = CIL_EXPANDTYPEATTRIBUTE;
return SEPOL_OK;
exit:
cil_tree_log(parse_current, CIL_ERR, "Bad expandtypeattribute statement");
cil_destroy_expandtypeattribute(expandattr);
return rc;
}
void cil_destroy_expandtypeattribute(struct cil_expandtypeattribute *expandattr)
{
if (expandattr == NULL) {
return;
}
cil_list_destroy(&expandattr->attr_strs, CIL_TRUE);
cil_list_destroy(&expandattr->attr_datums, CIL_FALSE);
free(expandattr);
}
int cil_gen_typepermissive(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
{
enum cil_syntax syntax[] = {
@ -6013,6 +6082,9 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f
} else if (parse_current->data == CIL_KEY_TYPEATTRIBUTESET) {
rc = cil_gen_typeattributeset(db, parse_current, ast_node);
*finished = CIL_TREE_SKIP_NEXT;
} else if (parse_current->data == CIL_KEY_EXPANDTYPEATTRIBUTE) {
rc = cil_gen_expandtypeattribute(db, parse_current, ast_node);
*finished = CIL_TREE_SKIP_NEXT;
} else if (parse_current->data == CIL_KEY_TYPEALIAS) {
rc = cil_gen_alias(db, parse_current, ast_node, CIL_TYPEALIAS);
} else if (parse_current->data == CIL_KEY_TYPEALIASACTUAL) {

View File

@ -138,6 +138,8 @@ int cil_gen_aliasactual(struct cil_db *db, struct cil_tree_node *parse_current,
void cil_destroy_aliasactual(struct cil_aliasactual *aliasactual);
int cil_gen_typeattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_typeattributeset(struct cil_typeattributeset *attrtypes);
int cil_gen_expandtypeattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_expandtypeattribute(struct cil_expandtypeattribute *expandattr);
int cil_gen_typebounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
int cil_gen_typepermissive(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
void cil_destroy_typepermissive(struct cil_typepermissive *typeperm);

View File

@ -648,6 +648,29 @@ int cil_copy_typeattributeset(struct cil_db *db, void *data, void **copy, __attr
return SEPOL_OK;
}
int cil_copy_expandtypeattribute(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
{
struct cil_expandtypeattribute *orig = data;
struct cil_expandtypeattribute *new = NULL;
fprintf(stderr, "%s %u\n", __func__, __LINE__);
cil_expandtypeattribute_init(&new);
if (orig->attr_strs != NULL) {
cil_copy_list(orig->attr_strs, &new->attr_strs);
}
if (orig->attr_datums != NULL) {
cil_copy_list(orig->attr_datums, &new->attr_datums);
}
new->expand = orig->expand;
*copy = new;
return SEPOL_OK;
}
int cil_copy_alias(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
{
struct cil_alias *orig = data;
@ -1808,6 +1831,9 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u
case CIL_TYPEATTRIBUTESET:
copy_func = &cil_copy_typeattributeset;
break;
case CIL_EXPANDTYPEATTRIBUTE:
copy_func = &cil_copy_expandtypeattribute;
break;
case CIL_TYPEALIAS:
copy_func = &cil_copy_alias;
break;

View File

@ -73,6 +73,7 @@ enum cil_flavor {
CIL_ROLETYPE,
CIL_ROLEBOUNDS,
CIL_TYPEATTRIBUTESET,
CIL_EXPANDTYPEATTRIBUTE,
CIL_TYPEALIASACTUAL,
CIL_TYPEBOUNDS,
CIL_TYPEPERMISSIVE,

View File

@ -174,6 +174,7 @@ char *CIL_KEY_SELINUXUSER;
char *CIL_KEY_SELINUXUSERDEFAULT;
char *CIL_KEY_TYPEATTRIBUTE;
char *CIL_KEY_TYPEATTRIBUTESET;
char *CIL_KEY_EXPANDTYPEATTRIBUTE;
char *CIL_KEY_TYPEALIAS;
char *CIL_KEY_TYPEALIASACTUAL;
char *CIL_KEY_TYPEBOUNDS;
@ -515,9 +516,11 @@ struct cil_type {
int value;
};
#define CIL_ATTR_AVRULE 0x01
#define CIL_ATTR_NEVERALLOW 0x02
#define CIL_ATTR_CONSTRAINT 0x04
#define CIL_ATTR_AVRULE (1 << 0)
#define CIL_ATTR_NEVERALLOW (1 << 1)
#define CIL_ATTR_CONSTRAINT (1 << 2)
#define CIL_ATTR_EXPAND_TRUE (1 << 3)
#define CIL_ATTR_EXPAND_FALSE (1 << 4)
struct cil_typeattribute {
struct cil_symtab_datum datum;
struct cil_list *expr_list;
@ -531,6 +534,12 @@ struct cil_typeattributeset {
struct cil_list *datum_expr;
};
struct cil_expandtypeattribute {
struct cil_list *attr_strs;
struct cil_list *attr_datums;
int expand;
};
struct cil_typepermissive {
char *type_str;
void *type; /* type or alias */
@ -977,6 +986,7 @@ void cil_roleattributeset_init(struct cil_roleattributeset **attrset);
void cil_roletype_init(struct cil_roletype **roletype);
void cil_typeattribute_init(struct cil_typeattribute **attribute);
void cil_typeattributeset_init(struct cil_typeattributeset **attrset);
void cil_expandtypeattribute_init(struct cil_expandtypeattribute **expandattr);
void cil_alias_init(struct cil_alias **alias);
void cil_aliasactual_init(struct cil_aliasactual **aliasactual);
void cil_typepermissive_init(struct cil_typepermissive **typeperm);

View File

@ -1194,6 +1194,14 @@ static int cil_typeattribute_used(struct cil_typeattribute *attr, struct cil_db
return CIL_FALSE;
}
if (attr->used & CIL_ATTR_EXPAND_FALSE) {
return CIL_TRUE;
}
if (attr->used & CIL_ATTR_EXPAND_TRUE) {
return CIL_FALSE;
}
if (attr->used & CIL_ATTR_CONSTRAINT) {
return CIL_TRUE;
}

View File

@ -549,6 +549,7 @@ int __cil_reset_node(struct cil_tree_node *node, __attribute__((unused)) uint32
case CIL_CLASSORDER:
case CIL_CATORDER:
case CIL_SENSITIVITYORDER:
case CIL_EXPANDTYPEATTRIBUTE:
break; /* Nothing to reset */
default:
break;

View File

@ -271,14 +271,24 @@ exit:
int cil_type_used(struct cil_symtab_datum *datum, int used)
{
int rc = SEPOL_ERR;
struct cil_typeattribute *attr = NULL;
if (FLAVOR(datum) == CIL_TYPEATTRIBUTE) {
attr = (struct cil_typeattribute*)datum;
attr->used |= used;
if ((attr->used & CIL_ATTR_EXPAND_TRUE) &&
(attr->used & CIL_ATTR_EXPAND_FALSE)) {
cil_log(CIL_ERR, "Conflicting use of expandtypeattribute. "
"Expandtypeattribute may be set to true or false "
"but not both. \n");
goto exit;
}
}
return 0;
return SEPOL_OK;
exit:
return rc;
}
int cil_resolve_permissionx(struct cil_tree_node *current, struct cil_permissionx *permx, void *extra_args)
@ -453,6 +463,44 @@ exit:
return rc;
}
int cil_resolve_expandtypeattribute(struct cil_tree_node *current, void *extra_args)
{
struct cil_expandtypeattribute *expandattr = current->data;
struct cil_symtab_datum *attr_datum = NULL;
struct cil_tree_node *attr_node = NULL;
struct cil_list_item *curr;
int used;
int rc = SEPOL_ERR;
cil_list_init(&expandattr->attr_datums, CIL_TYPE);
cil_list_for_each(curr, expandattr->attr_strs) {
rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_TYPES, extra_args, &attr_datum);
if (rc != SEPOL_OK) {
goto exit;
}
attr_node = attr_datum->nodes->head->data;
if (attr_node->flavor != CIL_TYPEATTRIBUTE) {
rc = SEPOL_ERR;
cil_log(CIL_ERR, "Attribute type not an attribute\n");
goto exit;
}
used = expandattr->expand ? CIL_ATTR_EXPAND_TRUE : CIL_ATTR_EXPAND_FALSE;
rc = cil_type_used(attr_datum, used);
if (rc != SEPOL_OK) {
goto exit;
}
cil_list_append(expandattr->attr_datums, CIL_TYPE, attr_datum);
}
return SEPOL_OK;
exit:
return rc;
}
int cil_resolve_aliasactual(struct cil_tree_node *current, void *extra_args, enum cil_flavor flavor, enum cil_flavor alias_flavor)
{
int rc = SEPOL_ERR;
@ -3432,6 +3480,9 @@ int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args)
case CIL_TYPEATTRIBUTESET:
rc = cil_resolve_typeattributeset(node, args);
break;
case CIL_EXPANDTYPEATTRIBUTE:
rc = cil_resolve_expandtypeattribute(node, args);
break;
case CIL_TYPEBOUNDS:
rc = cil_resolve_bounds(node, args, CIL_TYPE, CIL_TYPEATTRIBUTE);
break;

View File

@ -703,6 +703,17 @@ void cil_tree_print_node(struct cil_tree_node *node)
cil_log(CIL_INFO, "TYPE: %s\n", type->datum.name);
return;
}
case CIL_EXPANDTYPEATTRIBUTE: {
struct cil_expandtypeattribute *attr = node->data;
fprintf(stderr, "%s %u\n", __func__, __LINE__);
cil_log(CIL_INFO, "(EXPANDTYPEATTRIBUTE ");
cil_tree_print_expr(attr->attr_datums, attr->attr_strs);
cil_log(CIL_INFO, "%s)\n",attr->expand ?
CIL_KEY_CONDTRUE : CIL_KEY_CONDFALSE);
return;
}
case CIL_TYPEATTRIBUTESET: {
struct cil_typeattributeset *attr = node->data;

View File

@ -178,7 +178,11 @@ typedef struct type_datum {
#define TYPE_ALIAS 2 /* alias in modular policy */
uint32_t flavor;
ebitmap_t types; /* types with this attribute */
#define TYPE_FLAGS_PERMISSIVE 0x01
#define TYPE_FLAGS_PERMISSIVE (1 << 0)
#define TYPE_FLAGS_EXPAND_ATTR_TRUE (1 << 1)
#define TYPE_FLAGS_EXPAND_ATTR_FALSE (1 << 2)
#define TYPE_FLAGS_EXPAND_ATTR (TYPE_FLAGS_EXPAND_ATTR_TRUE | \
TYPE_FLAGS_EXPAND_ATTR_FALSE)
uint32_t flags;
uint32_t bounds; /* bounds type, if exist */
} type_datum_t;

View File

@ -2244,6 +2244,17 @@ static int type_to_cil(int indent, struct policydb *pdb, struct avrule_block *UN
cil_println(indent, "(typeattribute %s)", key);
}
if (type->flags & TYPE_FLAGS_EXPAND_ATTR) {
cil_indent(indent);
cil_printf("(expandtypeattribute (%s) ", key);
if (type->flags & TYPE_FLAGS_EXPAND_ATTR_TRUE) {
cil_printf("true");
} else if (type->flags & TYPE_FLAGS_EXPAND_ATTR_FALSE) {
cil_printf("false");
}
cil_printf(")\n");
}
if (ebitmap_cardinality(&type->types) > 0) {
cil_indent(indent);
cil_printf("(typeattributeset %s (", key);