diff --git a/.gitignore b/.gitignore index e38af3e..dea000f 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,4 @@ libsepol-2.0.41.tgz /libsepol-2.1.5.tgz /libsepol-2.1.7.tgz /libsepol-2.1.8.tgz +/libsepol-2.1.9.tgz diff --git a/libsepol-bad.patch b/libsepol-bad.patch deleted file mode 100644 index 55b59e8..0000000 --- a/libsepol-bad.patch +++ /dev/null @@ -1,175 +0,0 @@ -diff --git a/libsepol/include/sepol/policydb/polcaps.h b/libsepol/include/sepol/policydb/polcaps.h -diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c -index bef759c..4663321 100644 ---- a/libsepol/src/expand.c -+++ b/libsepol/src/expand.c -@@ -49,6 +49,79 @@ typedef struct expand_state { - int expand_neverallow; - } expand_state_t; - -+struct linear_probe { -+ filename_trans_t **table; /* filename_trans chunks with same stype */ -+ filename_trans_t **ends; /* pointers to ends of **table chunks */ -+ uint32_t length; /* length of the table */ -+}; -+ -+static int linear_probe_create(struct linear_probe *probe, uint32_t length) -+{ -+ probe->table = calloc(length, sizeof(*probe->table)); -+ if (probe->table == NULL) -+ return -1; -+ -+ probe->ends = calloc(length, sizeof(*probe->ends)); -+ if (probe->ends == NULL) -+ return -1; -+ -+ probe->length = length; -+ -+ return 0; -+} -+ -+static void linear_probe_destroy(struct linear_probe *probe) -+{ -+ if (probe->length == 0) -+ return; -+ -+ free(probe->table); -+ free(probe->ends); -+ memset(probe, 0, sizeof(*probe)); -+} -+ -+static void linear_probe_insert(struct linear_probe *probe, uint32_t key, -+ filename_trans_t *data) -+{ -+ assert(probe->length > key); -+ -+ if (probe->table[key] != NULL) { -+ data->next = probe->table[key]; -+ probe->table[key] = data; -+ } else { -+ probe->table[key] = probe->ends[key] = data; -+ } -+} -+ -+static filename_trans_t *linear_probe_find(struct linear_probe *probe, uint32_t key) -+{ -+ assert(probe->length > key); -+ -+ return probe->table[key]; -+} -+ -+/* Returns all chunks stored in the *probe as single-linked list */ -+static filename_trans_t *linear_probe_dump(struct linear_probe *probe, -+ filename_trans_t **endp) -+{ -+ uint32_t i; -+ filename_trans_t *result = NULL; -+ filename_trans_t *end = NULL; -+ -+ for (i = 0; i < probe->length; i++) { -+ if (probe->table[i] != NULL) { -+ if (end == NULL) -+ end = probe->ends[i]; -+ probe->ends[i]->next = result; -+ result = probe->table[i]; -+ probe->table[i] = probe->ends[i] = NULL; -+ } -+ } -+ -+ *endp = end; -+ return result; -+} -+ - static void expand_state_init(expand_state_t * state) - { - memset(state, 0, sizeof(expand_state_t)); -@@ -1352,10 +1425,20 @@ static int copy_role_trans(expand_state_t * state, role_trans_rule_t * rules) - static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *rules) - { - unsigned int i, j; -- filename_trans_t *new_trans, *cur_trans; -+ filename_trans_t *new_trans, *cur_trans, *end; - filename_trans_rule_t *cur_rule; - ebitmap_t stypes, ttypes; - ebitmap_node_t *snode, *tnode; -+ struct linear_probe probe; -+ -+ /* -+ * Linear probing speeds-up finding filename_trans rules with certain -+ * "stype" value. -+ */ -+ if (linear_probe_create(&probe, 4096)) { /* Assume 4096 is enough for most cases */ -+ ERR(state->handle, "Out of memory!"); -+ return -1; -+ } - - cur_rule = rules; - while (cur_rule) { -@@ -1378,6 +1461,14 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r - - mapped_otype = state->typemap[cur_rule->otype - 1]; - -+ if (ebitmap_length(&stypes) > probe.length) { -+ linear_probe_destroy(&probe); -+ if (linear_probe_create(&probe, ebitmap_length(&stypes))) { -+ ERR(state->handle, "Out of memory!"); -+ return -1; -+ } -+ } -+ - ebitmap_for_each_bit(&stypes, snode, i) { - if (!ebitmap_node_get_bit(snode, i)) - continue; -@@ -1385,16 +1476,14 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r - if (!ebitmap_node_get_bit(tnode, j)) - continue; - -- cur_trans = state->out->filename_trans; -- while (cur_trans) { -- if ((cur_trans->stype == i + 1) && -- (cur_trans->ttype == j + 1) && -+ cur_trans = linear_probe_find(&probe, i); -+ while (cur_trans != NULL) { -+ if ((cur_trans->ttype == j + 1) && - (cur_trans->tclass == cur_rule->tclass) && - (!strcmp(cur_trans->name, cur_rule->name))) { - /* duplicate rule, who cares */ - if (cur_trans->otype == mapped_otype) - break; -- - ERR(state->handle, "Conflicting filename trans rules %s %s %s : %s otype1:%s otype2:%s", - cur_trans->name, - state->out->p_type_val_to_name[i], -@@ -1402,7 +1491,7 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r - state->out->p_class_val_to_name[cur_trans->tclass - 1], - state->out->p_type_val_to_name[cur_trans->otype - 1], - state->out->p_type_val_to_name[mapped_otype - 1]); -- -+ - return -1; - } - cur_trans = cur_trans->next; -@@ -1417,8 +1506,6 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r - return -1; - } - memset(new_trans, 0, sizeof(*new_trans)); -- new_trans->next = state->out->filename_trans; -- state->out->filename_trans = new_trans; - - new_trans->name = strdup(cur_rule->name); - if (!new_trans->name) { -@@ -1429,9 +1516,14 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r - new_trans->ttype = j + 1; - new_trans->tclass = cur_rule->tclass; - new_trans->otype = mapped_otype; -+ linear_probe_insert(&probe, i, new_trans); - } - } - -+ cur_trans = linear_probe_dump(&probe, &end); -+ end->next = state->out->filename_trans; -+ state->out->filename_trans = cur_trans; -+ - ebitmap_destroy(&stypes); - ebitmap_destroy(&ttypes); - diff --git a/libsepol-rhat.patch b/libsepol-rhat.patch index efe98bf..552c827 100644 --- a/libsepol-rhat.patch +++ b/libsepol-rhat.patch @@ -1,38 +1,28 @@ diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h -index f53a499..0165eed 100644 +index c27275e..0165eed 100644 --- a/libsepol/include/sepol/policydb/policydb.h +++ b/libsepol/include/sepol/policydb/policydb.h -@@ -116,6 +116,7 @@ typedef struct class_datum { - #define DEFAULT_TARGET 2 - char default_user; - char default_role; -+ char default_type; - /* Options how a new object range should be decided */ - #define DEFAULT_SOURCE_LOW 1 - #define DEFAULT_SOURCE_HIGH 2 -@@ -681,10 +682,12 @@ extern int policydb_set_target_platform(policydb_t *p, int platform); - #define POLICYDB_VERSION_FILENAME_TRANS 25 +@@ -683,10 +683,11 @@ extern int policydb_set_target_platform(policydb_t *p, int platform); #define POLICYDB_VERSION_ROLETRANS 26 #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 -+#define POLICYDB_VERSION_DEFAULT_TYPE 28 + #define POLICYDB_VERSION_DEFAULT_TYPE 28 +#define POLICYDB_VERSION_CONSTRAINT_NAMES 29 /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE --#define POLICYDB_VERSION_MAX POLICYDB_VERSION_NEW_OBJECT_DEFAULTS +-#define POLICYDB_VERSION_MAX POLICYDB_VERSION_DEFAULT_TYPE +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES /* Module versions and specific changes*/ #define MOD_POLICYDB_VERSION_BASE 4 -@@ -701,9 +704,11 @@ extern int policydb_set_target_platform(policydb_t *p, int platform); - #define MOD_POLICYDB_VERSION_ROLEATTRIB 13 +@@ -704,9 +705,10 @@ extern int policydb_set_target_platform(policydb_t *p, int platform); #define MOD_POLICYDB_VERSION_TUNABLE_SEP 14 #define MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 15 -+#define MOD_POLICYDB_VERSION_DEFAULT_TYPE 16 + #define MOD_POLICYDB_VERSION_DEFAULT_TYPE 16 +#define MOD_POLICYDB_VERSION_CONSTRAINT_NAMES 17 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE --#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS +-#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_DEFAULT_TYPE +#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_CONSTRAINT_NAMES #define POLICYDB_CONFIG_MLS 1 @@ -80,106 +70,11 @@ index aef0c7b..1969a10 100644 /* * Compute a SID to use for labeling a new object in the * class `tclass' based on a SID pair. -diff --git a/libsepol/src/avrule_block.c b/libsepol/src/avrule_block.c -index 16c89f3..84cfaf8 100644 ---- a/libsepol/src/avrule_block.c -+++ b/libsepol/src/avrule_block.c -@@ -61,7 +61,6 @@ avrule_decl_t *avrule_decl_create(uint32_t decl_id) - for (i = 0; i < SYM_NUM; i++) { - if (symtab_init(&decl->symtab[i], symtab_sizes[i])) { - avrule_decl_destroy(decl); -- free(decl); - return NULL; - } - } diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c -index 2003eb6..81dcbba 100644 +index f0555bb..6fd992f 100644 --- a/libsepol/src/expand.c +++ b/libsepol/src/expand.c -@@ -49,6 +49,82 @@ typedef struct expand_state { - int expand_neverallow; - } expand_state_t; - -+struct linear_probe { -+ filename_trans_t **table; /* filename_trans chunks with same stype */ -+ filename_trans_t **ends; /* pointers to ends of **table chunks */ -+ uint32_t length; /* length of the table */ -+}; -+ -+static int linear_probe_create(struct linear_probe *probe, uint32_t length) -+{ -+ probe->table = calloc(length, sizeof(*probe->table)); -+ if (probe->table == NULL) -+ return -1; -+ -+ probe->ends = calloc(length, sizeof(*probe->ends)); -+ if (probe->ends == NULL) -+ return -1; -+ -+ probe->length = length; -+ -+ return 0; -+} -+ -+static void linear_probe_destroy(struct linear_probe *probe) -+{ -+ if (probe->length == 0) -+ return; -+ -+ free(probe->table); -+ free(probe->ends); -+ memset(probe, 0, sizeof(*probe)); -+} -+ -+static void linear_probe_insert(struct linear_probe *probe, uint32_t key, -+ filename_trans_t *data) -+{ -+ assert(probe->length > key); -+ -+ if (probe->table[key] != NULL) { -+ data->next = probe->table[key]; -+ probe->table[key] = data; -+ } else { -+ probe->table[key] = probe->ends[key] = data; -+ } -+} -+ -+static filename_trans_t *linear_probe_find(struct linear_probe *probe, uint32_t key) -+{ -+ assert(probe->length > key); -+ -+ return probe->table[key]; -+} -+ -+/* Returns all chunks stored in the *probe as single-linked list */ -+static filename_trans_t *linear_probe_dump(struct linear_probe *probe, -+ filename_trans_t **endp) -+{ -+ uint32_t i; -+ filename_trans_t *result = NULL; -+ filename_trans_t *end = NULL; -+ -+ for (i = 0; i < probe->length; i++) { -+ if (probe->table[i] != NULL) { -+ if (end == NULL) -+ end = probe->ends[i]; -+ probe->ends[i]->next = result; -+ result = probe->table[i]; -+ probe->table[i] = probe->ends[i] = NULL; -+ } -+ } -+ -+ /* Incoherent result and end pointers indicates bug */ -+ assert((result != NULL && end != NULL) || (result == NULL && end == NULL)); -+ -+ *endp = end; -+ return result; -+} -+ - static void expand_state_init(expand_state_t * state) - { - memset(state, 0, sizeof(expand_state_t)); -@@ -306,6 +382,17 @@ static int constraint_node_clone(constraint_node_t ** dst, +@@ -384,6 +384,17 @@ static int constraint_node_clone(constraint_node_t ** dst, new_expr->op = expr->op; if (new_expr->expr_type == CEXPR_NAMES) { if (new_expr->attr & CEXPR_TYPE) { @@ -197,510 +92,15 @@ index 2003eb6..81dcbba 100644 /* Type sets require expansion and conversion. */ if (expand_convert_type_set(state->out, state-> -@@ -377,6 +464,13 @@ static int class_copy_default_new_object(expand_state_t *state, - } - newdatum->default_role = olddatum->default_role; - } -+ if (olddatum->default_type) { -+ if (newdatum->default_type && olddatum->default_type != newdatum->default_type) { -+ ERR(state->handle, "Found conflicting default type definitions"); -+ return SEPOL_ENOTSUP; -+ } -+ newdatum->default_type = olddatum->default_type; -+ } - if (olddatum->default_range) { - if (newdatum->default_range && olddatum->default_range != newdatum->default_range) { - ERR(state->handle, "Found conflicting default range definitions"); -@@ -812,6 +906,7 @@ static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum, - new_id = strdup(id); - if (!new_id) { - ERR(state->handle, "Out of memory!"); -+ free(new_role); - return -1; - } - -@@ -877,9 +972,13 @@ int mls_semantic_level_expand(mls_semantic_level_t * sl, mls_level_t * l, - - l->sens = sl->sens; - levdatum = (level_datum_t *) hashtab_search(p->p_levels.table, -- p->p_sens_val_to_name[l-> -- sens - -- 1]); -+ p->p_sens_val_to_name[l->sens - 1]); -+ if (!levdatum) { -+ ERR(h, "%s: Impossible situation found, nothing in p_levels.table.\n", -+ __func__); -+ errno = ENOENT; -+ return -1; -+ } - for (cat = sl->cat; cat; cat = cat->next) { - if (cat->low > cat->high) { - ERR(h, "Category range is not valid %s.%s", -@@ -963,6 +1062,7 @@ static int user_copy_callback(hashtab_key_t key, hashtab_datum_t datum, - new_id = strdup(id); - if (!new_id) { - ERR(state->handle, "Out of memory!"); -+ free(new_user); - return -1; - } - ret = hashtab_insert(state->out->p_users.table, -@@ -1357,10 +1457,20 @@ static int copy_role_trans(expand_state_t * state, role_trans_rule_t * rules) - static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *rules) - { - unsigned int i, j; -- filename_trans_t *new_trans, *cur_trans; -+ filename_trans_t *new_trans, *cur_trans, *end; - filename_trans_rule_t *cur_rule; - ebitmap_t stypes, ttypes; - ebitmap_node_t *snode, *tnode; -+ struct linear_probe probe; -+ -+ /* -+ * Linear probing speeds-up finding filename_trans rules with certain -+ * "stype" value. -+ */ -+ if (linear_probe_create(&probe, 4096)) { /* Assume 4096 is enough for most cases */ -+ ERR(state->handle, "Out of memory!"); -+ return -1; -+ } - - cur_rule = rules; - while (cur_rule) { -@@ -1383,6 +1493,14 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r - - mapped_otype = state->typemap[cur_rule->otype - 1]; - -+ if (ebitmap_length(&stypes) > probe.length) { -+ linear_probe_destroy(&probe); -+ if (linear_probe_create(&probe, ebitmap_length(&stypes))) { -+ ERR(state->handle, "Out of memory!"); -+ return -1; -+ } -+ } -+ - ebitmap_for_each_bit(&stypes, snode, i) { - if (!ebitmap_node_get_bit(snode, i)) - continue; -@@ -1390,16 +1508,14 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r - if (!ebitmap_node_get_bit(tnode, j)) - continue; - -- cur_trans = state->out->filename_trans; -- while (cur_trans) { -- if ((cur_trans->stype == i + 1) && -- (cur_trans->ttype == j + 1) && -+ cur_trans = linear_probe_find(&probe, i); -+ while (cur_trans != NULL) { -+ if ((cur_trans->ttype == j + 1) && - (cur_trans->tclass == cur_rule->tclass) && - (!strcmp(cur_trans->name, cur_rule->name))) { - /* duplicate rule, who cares */ - if (cur_trans->otype == mapped_otype) - break; -- - ERR(state->handle, "Conflicting filename trans rules %s %s %s : %s otype1:%s otype2:%s", - cur_trans->name, - state->out->p_type_val_to_name[i], -@@ -1407,7 +1523,7 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r - state->out->p_class_val_to_name[cur_trans->tclass - 1], - state->out->p_type_val_to_name[cur_trans->otype - 1], - state->out->p_type_val_to_name[mapped_otype - 1]); -- -+ - return -1; - } - cur_trans = cur_trans->next; -@@ -1422,8 +1538,6 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r - return -1; - } - memset(new_trans, 0, sizeof(*new_trans)); -- new_trans->next = state->out->filename_trans; -- state->out->filename_trans = new_trans; - - new_trans->name = strdup(cur_rule->name); - if (!new_trans->name) { -@@ -1434,9 +1548,16 @@ static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *r - new_trans->ttype = j + 1; - new_trans->tclass = cur_rule->tclass; - new_trans->otype = mapped_otype; -+ linear_probe_insert(&probe, i, new_trans); - } - } - -+ cur_trans = linear_probe_dump(&probe, &end); -+ if (cur_trans != NULL) { -+ end->next = state->out->filename_trans; -+ state->out->filename_trans = cur_trans; -+ } -+ - ebitmap_destroy(&stypes); - ebitmap_destroy(&ttypes); - -@@ -1981,6 +2102,8 @@ static int cond_node_copy(expand_state_t * state, cond_node_t * cn) - } - - if (cond_node_map_bools(state, tmp)) { -+ cond_node_destroy(tmp); -+ free(tmp); - ERR(state->handle, "Error mapping booleans"); - return -1; - } -@@ -2188,9 +2311,15 @@ static int genfs_copy(expand_state_t * state) - memset(newgenfs, 0, sizeof(genfs_t)); - newgenfs->fstype = strdup(genfs->fstype); - if (!newgenfs->fstype) { -+ free(newgenfs); - ERR(state->handle, "Out of memory!"); - return -1; - } -+ if (!end) -+ state->out->genfs = newgenfs; -+ else -+ end->next = newgenfs; -+ end = newgenfs; - - l = NULL; - for (c = genfs->head; c; c = c->next) { -@@ -2203,6 +2332,7 @@ static int genfs_copy(expand_state_t * state) - newc->u.name = strdup(c->u.name); - if (!newc->u.name) { - ERR(state->handle, "Out of memory!"); -+ free(newc); - return -1; - } - newc->v.sclass = c->v.sclass; -@@ -2213,12 +2343,6 @@ static int genfs_copy(expand_state_t * state) - newgenfs->head = newc; - l = newc; - } -- if (!end) { -- state->out->genfs = newgenfs; -- } else { -- end->next = newgenfs; -- } -- end = newgenfs; - } - return 0; - } -@@ -3009,7 +3133,8 @@ int expand_module(sepol_handle_t * handle, - } - - cond_optimize_lists(state.out->cond_list); -- evaluate_conds(state.out); -+ if (evaluate_conds(state.out)) -+ goto cleanup; - - /* copy ocontexts */ - if (ocontext_copy(&state, out->target_platform)) -diff --git a/libsepol/src/genbools.c b/libsepol/src/genbools.c -index 612ff9a..6a06ec9 100644 ---- a/libsepol/src/genbools.c -+++ b/libsepol/src/genbools.c -@@ -33,7 +33,7 @@ static char *strtrim(char *dest, char *source, int size) - static int process_boolean(char *buffer, char *name, int namesize, int *val) - { - char name1[BUFSIZ]; -- char *ptr; -+ char *ptr = NULL; - char *tok = strtok_r(buffer, "=", &ptr); - if (tok) { - strncpy(name1, tok, BUFSIZ - 1); -diff --git a/libsepol/src/genusers.c b/libsepol/src/genusers.c -index 37528e2..7826b71 100644 ---- a/libsepol/src/genusers.c -+++ b/libsepol/src/genusers.c -@@ -92,22 +92,32 @@ static int load_users(struct policydb *policydb, const char *path) - } else { - char *id = strdup(q); - -+ if (!id) { -+ ERR(NULL, "out of memory"); -+ free(buffer); -+ fclose(fp); -+ return -1; -+ } -+ - /* Adding a new user definition. */ -- usrdatum = -- (user_datum_t *) malloc(sizeof(user_datum_t)); -- if (!id || !usrdatum) { -+ usrdatum = malloc(sizeof(user_datum_t)); -+ if (!usrdatum) { - ERR(NULL, "out of memory"); - free(buffer); -+ free(id); - fclose(fp); - return -1; - } -- memset(usrdatum, 0, sizeof(user_datum_t)); -+ -+ user_datum_init(usrdatum); - usrdatum->s.value = ++policydb->p_users.nprim; -- ebitmap_init(&usrdatum->roles.roles); - if (hashtab_insert(policydb->p_users.table, - id, (hashtab_datum_t) usrdatum)) { - ERR(NULL, "out of memory"); - free(buffer); -+ free(id); -+ user_datum_destroy(usrdatum); -+ free(usrdatum); - fclose(fp); - return -1; - } -diff --git a/libsepol/src/link.c b/libsepol/src/link.c -index 01d3231..31b955c 100644 ---- a/libsepol/src/link.c -+++ b/libsepol/src/link.c -@@ -223,6 +223,13 @@ static int class_copy_default_new_object(link_state_t *state, - } - newdatum->default_role = olddatum->default_role; - } -+ if (olddatum->default_type) { -+ if (newdatum->default_type && olddatum->default_type != newdatum->default_type) { -+ ERR(state->handle, "Found conflicting default type definitions"); -+ return SEPOL_ENOTSUP; -+ } -+ newdatum->default_type = olddatum->default_type; -+ } - if (olddatum->default_range) { - if (newdatum->default_range && olddatum->default_range != newdatum->default_range) { - ERR(state->handle, "Found conflicting default range definitions"); -@@ -676,13 +683,17 @@ static int sens_copy_callback(hashtab_key_t key, hashtab_datum_t datum, - "%s: Modules may not declare new sensitivities.", - state->cur_mod_name); - return SEPOL_ENOTSUP; -- } -- if (scope->scope == SCOPE_REQ) { -+ } else if (scope->scope == SCOPE_REQ) { - /* unmet requirement */ - ERR(state->handle, - "%s: Sensitivity %s not declared by base.", - state->cur_mod_name, id); - return SEPOL_ENOTSUP; -+ } else { -+ ERR(state->handle, -+ "%s: has an unknown scope: %d\n", -+ state->cur_mod_name, scope->scope); -+ return SEPOL_ENOTSUP; - } - } - -@@ -704,8 +715,7 @@ static int cat_copy_callback(hashtab_key_t key, hashtab_datum_t datum, - - base_cat = hashtab_search(state->base->p_cats.table, id); - if (!base_cat) { -- scope = -- hashtab_search(state->cur->policy->p_cat_scope.table, id); -+ scope = hashtab_search(state->cur->policy->p_cat_scope.table, id); - if (!scope) - return SEPOL_ERR; - if (scope->scope == SCOPE_DECL) { -@@ -714,13 +724,18 @@ static int cat_copy_callback(hashtab_key_t key, hashtab_datum_t datum, - "%s: Modules may not declare new categories.", - state->cur_mod_name); - return SEPOL_ENOTSUP; -- } -- if (scope->scope == SCOPE_REQ) { -+ } else if (scope->scope == SCOPE_REQ) { - /* unmet requirement */ - ERR(state->handle, - "%s: Category %s not declared by base.", - state->cur_mod_name, id); - return SEPOL_ENOTSUP; -+ } else { -+ /* unknown scope? malformed policy? */ -+ ERR(state->handle, -+ "%s: has an unknown scope: %d\n", -+ state->cur_mod_name, scope->scope); -+ return SEPOL_ENOTSUP; - } - } - -@@ -2001,6 +2016,7 @@ static int is_decl_requires_met(link_state_t * state, - struct find_perm_arg fparg; - class_datum_t *cladatum; - uint32_t perm_value = j + 1; -+ int rc; - scope_datum_t *scope; - - if (!ebitmap_node_get_bit(node, j)) { -@@ -2022,11 +2038,13 @@ static int is_decl_requires_met(link_state_t * state, - fparg.valuep = perm_value; - fparg.key = NULL; - -- hashtab_map(cladatum->permissions.table, find_perm, -+ (void)hashtab_map(cladatum->permissions.table, find_perm, - &fparg); -- if (fparg.key == NULL && cladatum->comdatum != NULL) -- hashtab_map(cladatum->comdatum->permissions. -- table, find_perm, &fparg); -+ if (fparg.key == NULL && cladatum->comdatum != NULL) { -+ rc = hashtab_map(cladatum->comdatum->permissions.table, -+ find_perm, &fparg); -+ assert(rc == 1); -+ } - perm_id = fparg.key; - - assert(perm_id != NULL); -@@ -2050,6 +2068,7 @@ static int debug_requirements(link_state_t * state, policydb_t * p) - int ret; - avrule_block_t *cur; - missing_requirement_t req; -+ memset(&req, 0, sizeof(req)); - - for (cur = p->global; cur != NULL; cur = cur->next) { - if (cur->enabled != NULL) -@@ -2062,34 +2081,27 @@ static int debug_requirements(link_state_t * state, policydb_t * p) - char *mod_name = cur->branch_list->module_name ? - cur->branch_list->module_name : "BASE"; - if (req.symbol_type == SYM_CLASSES) { -- - struct find_perm_arg fparg; - - class_datum_t *cladatum; -- cladatum = -- p->class_val_to_struct[req.symbol_value - -- 1]; -+ cladatum = p->class_val_to_struct[req.symbol_value - 1]; - - fparg.valuep = req.perm_value; - fparg.key = NULL; -- hashtab_map(cladatum->permissions.table, -- find_perm, &fparg); -+ (void)hashtab_map(cladatum->permissions.table, -+ find_perm, &fparg); - - if (cur->flags & AVRULE_OPTIONAL) { - ERR(state->handle, - "%s[%d]'s optional requirements were not met: class %s, permission %s", - mod_name, cur->branch_list->decl_id, -- p->p_class_val_to_name[req. -- symbol_value -- - 1], -+ p->p_class_val_to_name[req.symbol_value - 1], - fparg.key); - } else { - ERR(state->handle, - "%s[%d]'s global requirements were not met: class %s, permission %s", - mod_name, cur->branch_list->decl_id, -- p->p_class_val_to_name[req. -- symbol_value -- - 1], -+ p->p_class_val_to_name[req.symbol_value - 1], - fparg.key); - } - } else { -@@ -2137,7 +2149,7 @@ static void print_missing_requirements(link_state_t * state, - - fparg.valuep = req->perm_value; - fparg.key = NULL; -- hashtab_map(cladatum->permissions.table, find_perm, &fparg); -+ (void)hashtab_map(cladatum->permissions.table, find_perm, &fparg); - - ERR(state->handle, - "%s's global requirements were not met: class %s, permission %s", -@@ -2148,8 +2160,7 @@ static void print_missing_requirements(link_state_t * state, - "%s's global requirements were not met: %s %s", - mod_name, - symtab_names[req->symbol_type], -- p->sym_val_to_name[req->symbol_type][req->symbol_value - -- 1]); -+ p->sym_val_to_name[req->symbol_type][req->symbol_value - 1]); - } - } - -diff --git a/libsepol/src/module.c b/libsepol/src/module.c -index b5b807e..1665ede 100644 ---- a/libsepol/src/module.c -+++ b/libsepol/src/module.c -@@ -59,21 +59,34 @@ static int policy_file_seek(struct policy_file *fp, size_t offset) - } - } - --static size_t policy_file_length(struct policy_file *fp) -+static int policy_file_length(struct policy_file *fp, size_t *out) - { - long prev_offset, end_offset; -+ int rc; - switch (fp->type) { - case PF_USE_STDIO: - prev_offset = ftell(fp->fp); -- fseek(fp->fp, 0L, SEEK_END); -+ if (prev_offset < 0) -+ return prev_offset; -+ rc = fseek(fp->fp, 0L, SEEK_END); -+ if (rc < 0) -+ return rc; - end_offset = ftell(fp->fp); -- fseek(fp->fp, prev_offset, SEEK_SET); -- return end_offset; -+ if (end_offset < 0) -+ return end_offset; -+ rc = fseek(fp->fp, prev_offset, SEEK_SET); -+ if (rc < 0) -+ return rc; -+ *out = end_offset; -+ break; - case PF_USE_MEMORY: -- return fp->size; -+ *out = fp->size; -+ break;; - default: -- return 0; -+ *out = 0; -+ break; - } -+ return 0; - } - - static int module_package_init(sepol_module_package_t * p) -@@ -103,10 +116,17 @@ static int set_char(char **field, char *data, size_t len) - - int sepol_module_package_create(sepol_module_package_t ** p) - { -+ int rc; -+ - *p = calloc(1, sizeof(sepol_module_package_t)); - if (!(*p)) - return -1; -- return module_package_init(*p); -+ -+ rc = module_package_init(*p); -+ if (rc < 0) -+ free(*p); -+ -+ return rc; - } - - hidden_def(sepol_module_package_create) -@@ -413,7 +433,10 @@ static int module_package_read_offsets(sepol_module_package_t * mod, - } - } - -- off[nsec] = policy_file_length(file); -+ rc = policy_file_length(file, &off[nsec]); -+ if (rc < 0) -+ goto err; -+ - if (nsec && off[nsec] < off[nsec-1]) { - ERR(file->handle, "offset greater than file size (at %u, " - "offset %zu -> %zu", nsec, off[nsec - 1], diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c -index ff292f6..00cf6a8 100644 +index 1f49261..8c7efbc 100644 --- a/libsepol/src/policydb.c +++ b/libsepol/src/policydb.c -@@ -158,6 +158,20 @@ static struct policydb_compat_info policydb_compat[] = { +@@ -165,6 +165,13 @@ static struct policydb_compat_info policydb_compat[] = { .target_platform = SEPOL_TARGET_SELINUX, }, { + .type = POLICY_KERN, -+ .version = POLICYDB_VERSION_DEFAULT_TYPE, -+ .sym_num = SYM_NUM, -+ .ocon_num = OCON_NODE6 + 1, -+ .target_platform = SEPOL_TARGET_SELINUX, -+ }, -+ { -+ .type = POLICY_KERN, + .version = POLICYDB_VERSION_CONSTRAINT_NAMES, + .sym_num = SYM_NUM, + .ocon_num = OCON_NODE6 + 1, @@ -710,18 +110,11 @@ index ff292f6..00cf6a8 100644 .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_BASE, .sym_num = SYM_NUM, -@@ -242,6 +256,20 @@ static struct policydb_compat_info policydb_compat[] = { +@@ -256,6 +263,13 @@ static struct policydb_compat_info policydb_compat[] = { .target_platform = SEPOL_TARGET_SELINUX, }, { + .type = POLICY_BASE, -+ .version = MOD_POLICYDB_VERSION_DEFAULT_TYPE, -+ .sym_num = SYM_NUM, -+ .ocon_num = OCON_NODE6 + 1, -+ .target_platform = SEPOL_TARGET_SELINUX, -+ }, -+ { -+ .type = POLICY_BASE, + .version = MOD_POLICYDB_VERSION_CONSTRAINT_NAMES, + .sym_num = SYM_NUM, + .ocon_num = OCON_NODE6 + 1, @@ -731,19 +124,12 @@ index ff292f6..00cf6a8 100644 .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_BASE, .sym_num = SYM_NUM, -@@ -325,6 +353,20 @@ static struct policydb_compat_info policydb_compat[] = { +@@ -346,6 +360,13 @@ static struct policydb_compat_info policydb_compat[] = { .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, + { + .type = POLICY_MOD, -+ .version = MOD_POLICYDB_VERSION_DEFAULT_TYPE, -+ .sym_num = SYM_NUM, -+ .ocon_num = 0, -+ .target_platform = SEPOL_TARGET_SELINUX, -+ }, -+ { -+ .type = POLICY_MOD, + .version = MOD_POLICYDB_VERSION_CONSTRAINT_NAMES, + .sym_num = SYM_NUM, + .ocon_num = 0, @@ -752,43 +138,7 @@ index ff292f6..00cf6a8 100644 }; #if 0 -@@ -1074,7 +1116,7 @@ static int common_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p - if (key) - free(key); - comdatum = (common_datum_t *) datum; -- hashtab_map(comdatum->permissions.table, perm_destroy, 0); -+ (void)hashtab_map(comdatum->permissions.table, perm_destroy, 0); - hashtab_destroy(comdatum->permissions.table); - free(datum); - return 0; -@@ -1093,7 +1135,7 @@ static int class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p - if (cladatum == NULL) { - return 0; - } -- hashtab_map(cladatum->permissions.table, perm_destroy, 0); -+ (void)hashtab_map(cladatum->permissions.table, perm_destroy, 0); - hashtab_destroy(cladatum->permissions.table); - constraint = cladatum->constraints; - while (constraint) { -@@ -1261,7 +1303,7 @@ void policydb_destroy(policydb_t * p) - free(p->decl_val_to_struct); - - for (i = 0; i < SYM_NUM; i++) { -- hashtab_map(p->scope[i].table, scope_destroy, 0); -+ (void)hashtab_map(p->scope[i].table, scope_destroy, 0); - hashtab_destroy(p->scope[i].table); - } - avrule_block_list_destroy(p->global); -@@ -1351,7 +1393,7 @@ void symtabs_destroy(symtab_t * symtab) - { - int i; - for (i = 0; i < SYM_NUM; i++) { -- hashtab_map(symtab[i].table, destroy_f[i], 0); -+ (void)hashtab_map(symtab[i].table, destroy_f[i], 0); - hashtab_destroy(symtab[i].table); - } - } -@@ -1998,6 +2040,10 @@ static int read_cons_helper(policydb_t * p, constraint_node_t ** nodep, +@@ -2019,6 +2040,10 @@ static int read_cons_helper(policydb_t * p, constraint_node_t ** nodep, if (p->policy_type != POLICY_KERN && type_set_read(e->type_names, fp)) return -1; @@ -799,25 +149,8 @@ index ff292f6..00cf6a8 100644 break; default: return -1; -@@ -2097,6 +2143,16 @@ static int class_read(policydb_t * p, hashtab_t h, struct policy_file *fp) - cladatum->default_range = le32_to_cpu(buf[2]); - } - -+ if ((p->policy_type == POLICY_KERN && -+ p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) || -+ (p->policy_type == POLICY_BASE && -+ p->policyvers >= MOD_POLICYDB_VERSION_DEFAULT_TYPE)) { -+ rc = next_entry(buf, fp, sizeof(uint32_t)); -+ if (rc < 0) -+ goto bad; -+ cladatum->default_type = le32_to_cpu(buf[0]); -+ } -+ - if (hashtab_insert(h, key, cladatum)) - goto bad; - diff --git a/libsepol/src/services.c b/libsepol/src/services.c -index 9c2920c..e235ae4 100644 +index 7fac4a0..43ec07e 100644 --- a/libsepol/src/services.c +++ b/libsepol/src/services.c @@ -43,6 +43,11 @@ @@ -891,7 +224,7 @@ index 9c2920c..e235ae4 100644 int hidden sepol_set_sidtab(sidtab_t * s) { sidtab = s; -@@ -112,20 +162,195 @@ int sepol_set_policydb_from_file(FILE * fp) +@@ -113,20 +163,195 @@ int sepol_set_policydb_from_file(FILE * fp) static uint32_t latest_granting = 0; /* @@ -1092,7 +425,7 @@ index 9c2920c..e235ae4 100644 { uint32_t val1, val2; context_struct_t *c; -@@ -135,56 +360,135 @@ static int constraint_expr_eval(context_struct_t * scontext, +@@ -136,56 +361,137 @@ static int constraint_expr_eval(context_struct_t * scontext, int s[CEXPR_MAXDEPTH]; int sp = -1; @@ -1144,7 +477,8 @@ index 9c2920c..e235ae4 100644 + new_expr_list = realloc(expr_list, new_expr_list_len * sizeof(*expr_list)); + if (!new_expr_list) { + ERR(NULL, "failed to allocate expr buffer stack"); -+ return -ENOMEM; ++ rc = -ENOMEM; ++ goto out; + } + expr_list_len = new_expr_list_len; + expr_list = new_expr_list; @@ -1158,7 +492,8 @@ index 9c2920c..e235ae4 100644 + expr_list[expr_counter] = malloc(expr_buf_len); + if (!expr_list[expr_counter]) { + ERR(NULL, "failed to allocate expr buffer"); -+ return -ENOMEM; ++ rc = -ENOMEM; ++ goto out; + } + expr_buf_used = 0; + @@ -1241,7 +576,7 @@ index 9c2920c..e235ae4 100644 continue; default: break; -@@ -193,110 +497,325 @@ static int constraint_expr_eval(context_struct_t * scontext, +@@ -194,110 +500,327 @@ static int constraint_expr_eval(context_struct_t * scontext, case CEXPR_L1L2: l1 = &(scontext->range.level[0]); l2 = &(tcontext->range.level[0]); @@ -1444,7 +779,7 @@ index 9c2920c..e235ae4 100644 BUG(); - return 0; + goto out; -+ } + } + expr_counter++; + } + @@ -1472,9 +807,12 @@ index 9c2920c..e235ae4 100644 + answer_list = malloc(expr_count * sizeof(*answer_list)); + if (!answer_list) { + ERR(NULL, "failed to allocate answer stack"); -+ return -ENOMEM; -+ } -+ ++ rc = -ENOMEM; ++ goto out; + } + +- BUG_ON(sp != 0); +- return s[0]; + /* The pop operands */ + char *a; + char *b; @@ -1493,7 +831,8 @@ index 9c2920c..e235ae4 100644 + answer_list[answer_counter] = malloc(a_len + b_len + 8); + if (!answer_list[answer_counter]) { + ERR(NULL, "failed to allocate answer buffer"); -+ return -ENOMEM; ++ rc = -ENOMEM; ++ goto out; + } + memset(answer_list[answer_counter], '\0', a_len + b_len + 8); + @@ -1508,7 +847,8 @@ index 9c2920c..e235ae4 100644 + answer_list[answer_counter] = malloc(b_len + 8); + if (!answer_list[answer_counter]) { + ERR(NULL, "failed to allocate answer buffer"); -+ return -ENOMEM; ++ rc = -ENOMEM; ++ goto out; + } + memset(answer_list[answer_counter], '\0', b_len + 8); + @@ -1520,11 +860,11 @@ index 9c2920c..e235ae4 100644 + free(b); + } else { + push(expr_list[x]); - } - } ++ } ++ } + /* Get the final answer from tos and build constraint text */ + a = pop(); - ++ + /* Constraint calculation: rc = 0 is denied, rc = 1 is granted */ + sprintf(tmp_buf,"Constraint %s\n", s[0] ? "GRANTED" : "DENIED"); + @@ -1573,20 +913,18 @@ index 9c2920c..e235ae4 100644 + +out: + free(class_buf); -+ free(src); ++ free(src); + free(tgt); + + if (expr_counter) { + for (x = 0; expr_list[x] != NULL; x++) + free(expr_list[x]); + } - BUG_ON(sp != 0); -- return s[0]; + return rc; } /* -@@ -308,7 +827,9 @@ static int context_struct_compute_av(context_struct_t * scontext, +@@ -309,7 +832,9 @@ static int context_struct_compute_av(context_struct_t * scontext, sepol_security_class_t tclass, sepol_access_vector_t requested, struct sepol_av_decision *avd, @@ -1597,7 +935,7 @@ index 9c2920c..e235ae4 100644 { constraint_node_t *constraint; struct role_allow *ra; -@@ -383,8 +904,8 @@ static int context_struct_compute_av(context_struct_t * scontext, +@@ -384,8 +909,8 @@ static int context_struct_compute_av(context_struct_t * scontext, constraint = tclass_datum->constraints; while (constraint) { if ((constraint->permissions & (avd->allowed)) && @@ -1608,7 +946,7 @@ index 9c2920c..e235ae4 100644 avd->allowed = (avd->allowed) & ~(constraint->permissions); } -@@ -459,8 +980,8 @@ int hidden sepol_validate_transition(sepol_security_id_t oldsid, +@@ -460,8 +985,8 @@ int hidden sepol_validate_transition(sepol_security_id_t oldsid, constraint = tclass_datum->validatetrans; while (constraint) { @@ -1619,7 +957,7 @@ index 9c2920c..e235ae4 100644 return -EPERM; } constraint = constraint->next; -@@ -493,11 +1014,59 @@ int hidden sepol_compute_av_reason(sepol_security_id_t ssid, +@@ -494,11 +1019,59 @@ int hidden sepol_compute_av_reason(sepol_security_id_t ssid, } rc = context_struct_compute_av(scontext, tcontext, tclass, @@ -1680,7 +1018,7 @@ index 9c2920c..e235ae4 100644 int hidden sepol_compute_av(sepol_security_id_t ssid, sepol_security_id_t tsid, sepol_security_class_t tclass, -@@ -510,6 +1079,70 @@ int hidden sepol_compute_av(sepol_security_id_t ssid, +@@ -511,6 +1084,70 @@ int hidden sepol_compute_av(sepol_security_id_t ssid, } /* @@ -1751,7 +1089,7 @@ index 9c2920c..e235ae4 100644 * Write the security context string representation of * the context associated with `sid' into a dynamically * allocated string of the correct size. Set `*scontext' -@@ -1337,7 +1970,7 @@ int hidden sepol_get_user_sids(sepol_security_id_t fromsid, +@@ -1339,7 +1976,7 @@ int hidden sepol_get_user_sids(sepol_security_id_t fromsid, rc = context_struct_compute_av(fromcon, &usercon, SECCLASS_PROCESS, PROCESS__TRANSITION, @@ -1761,7 +1099,7 @@ index 9c2920c..e235ae4 100644 continue; rc = sepol_sidtab_context_to_sid(sidtab, &usercon, diff --git a/libsepol/src/write.c b/libsepol/src/write.c -index 22e6143..6fe73e6 100644 +index 55992f8..6fe73e6 100644 --- a/libsepol/src/write.c +++ b/libsepol/src/write.c @@ -893,8 +893,11 @@ static int write_cons_helper(policydb_t * p, @@ -1778,83 +1116,3 @@ index 22e6143..6fe73e6 100644 return POLICYDB_ERROR; } break; -@@ -988,6 +991,16 @@ static int class_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) - return POLICYDB_ERROR; - } - -+ if ((p->policy_type == POLICY_KERN && -+ p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) || -+ (p->policy_type == POLICY_BASE && -+ p->policyvers >= MOD_POLICYDB_VERSION_DEFAULT_TYPE)) { -+ buf[0] = cpu_to_le32(cladatum->default_type); -+ items = put_entry(buf, sizeof(uint32_t), 1, fp); -+ if (items != 1) -+ return POLICYDB_ERROR; -+ } -+ - return POLICYDB_SUCCESS; - } - -@@ -1795,34 +1808,38 @@ static int scope_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) - uint32_t static_buf[32], *dyn_buf = NULL, *buf; - size_t key_len = strlen(key); - unsigned int items = 2 + scope->decl_ids_len, i; -+ int rc; - -+ buf = static_buf; - if (items >= (sizeof(static_buf) / 4)) { - /* too many things required, so dynamically create a - * buffer. this would have been easier with C99's - * dynamic arrays... */ -- if ((dyn_buf = malloc(items * sizeof(*dyn_buf))) == NULL) { -- return POLICYDB_ERROR; -- } -+ rc = POLICYDB_ERROR; -+ dyn_buf = malloc(items * sizeof(*dyn_buf)); -+ if (!dyn_buf) -+ goto err; - buf = dyn_buf; -- } else { -- buf = static_buf; - } - buf[0] = cpu_to_le32(key_len); -+ -+ rc = POLICYDB_ERROR; - if (put_entry(buf, sizeof(*buf), 1, fp) != 1 || -- put_entry(key, 1, key_len, fp) != key_len) { -- return POLICYDB_ERROR; -- } -+ put_entry(key, 1, key_len, fp) != key_len) -+ goto err; - buf[0] = cpu_to_le32(scope->scope); - buf[1] = cpu_to_le32(scope->decl_ids_len); -- for (i = 0; i < scope->decl_ids_len; i++) { -+ -+ for (i = 0; i < scope->decl_ids_len; i++) - buf[2 + i] = cpu_to_le32(scope->decl_ids[i]); -- } -- if (put_entry(buf, sizeof(*buf), items, fp) != items) { -- free(dyn_buf); -- return POLICYDB_ERROR; -- } -+ -+ rc = POLICYDB_ERROR; -+ if (put_entry(buf, sizeof(*buf), items, fp) != items) -+ goto err; -+ rc = POLICYDB_SUCCESS; -+err: - free(dyn_buf); -- return POLICYDB_SUCCESS; -+ return rc; - } - - static int type_attr_uncount(hashtab_key_t key __attribute__ ((unused)), -@@ -2006,7 +2023,7 @@ int policydb_write(policydb_t * p, struct policy_file *fp) - ((p->policy_type == POLICY_KERN) || - (p->policy_type != POLICY_KERN && - p->policyvers < MOD_POLICYDB_VERSION_ROLEATTRIB))) -- hashtab_map(p->symtab[i].table, role_attr_uncount, &buf[1]); -+ (void)hashtab_map(p->symtab[i].table, role_attr_uncount, &buf[1]); - - buf[1] = cpu_to_le32(buf[1]); - items = put_entry(buf, sizeof(uint32_t), 2, fp); diff --git a/libsepol.spec b/libsepol.spec index b48296f..a792eba 100644 --- a/libsepol.spec +++ b/libsepol.spec @@ -1,7 +1,7 @@ Summary: SELinux binary policy manipulation library Name: libsepol -Version: 2.1.8 -Release: 8%{?dist} +Version: 2.1.9 +Release: 1%{?dist} License: LGPLv2+ Group: System Environment/Libraries Source: http://www.nsa.gov/selinux/archives/libsepol-%{version}.tgz @@ -99,6 +99,14 @@ exit 0 /%{_lib}/libsepol.so.1 %changelog +* Thu Feb 7 2013 Dan Walsh - 2.1.9-1 +- Update to upstream + * filename_trans: use some better sorting to compare and merge + * coverity fixes + * implement default type policy syntax + * Fix memory leak issues found by Klocwork +- Add CONTRAINT_NAMES to the kernel + * Sun Jan 27 2013 Dan Walsh - 2.1.8-8 - Update to latest patches from eparis/Upstream diff --git a/sources b/sources index acb2def..a44a262 100644 --- a/sources +++ b/sources @@ -1,2 +1 @@ -332c564144780537c25f4498578e531f libsepol-2.1.7.tgz -ce02057c3d0922dd7775f9948f7932af libsepol-2.1.8.tgz +2b8b25260264ec84f7efbdd3252aff29 libsepol-2.1.9.tgz