diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-06 08:06:39 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-06 08:06:39 -0700 |
commit | bb2cbf5e9367d8598fecd0c48dead69560750223 (patch) | |
tree | fb2c620451b90f41a31726bdd82077813f941e39 /security/selinux/ss | |
parent | e7fda6c4c3c1a7d6996dd75fd84670fa0b5d448f (diff) | |
parent | 478d085524c57cf4283699f529d5a4c22188ea69 (diff) | |
download | op-kernel-dev-bb2cbf5e9367d8598fecd0c48dead69560750223.zip op-kernel-dev-bb2cbf5e9367d8598fecd0c48dead69560750223.tar.gz |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris:
"In this release:
- PKCS#7 parser for the key management subsystem from David Howells
- appoint Kees Cook as seccomp maintainer
- bugfixes and general maintenance across the subsystem"
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (94 commits)
X.509: Need to export x509_request_asymmetric_key()
netlabel: shorter names for the NetLabel catmap funcs/structs
netlabel: fix the catmap walking functions
netlabel: fix the horribly broken catmap functions
netlabel: fix a problem when setting bits below the previously lowest bit
PKCS#7: X.509 certificate issuer and subject are mandatory fields in the ASN.1
tpm: simplify code by using %*phN specifier
tpm: Provide a generic means to override the chip returned timeouts
tpm: missing tpm_chip_put in tpm_get_random()
tpm: Properly clean sysfs entries in error path
tpm: Add missing tpm_do_selftest to ST33 I2C driver
PKCS#7: Use x509_request_asymmetric_key()
Revert "selinux: fix the default socket labeling in sock_graft()"
X.509: x509_request_asymmetric_keys() doesn't need string length arguments
PKCS#7: fix sparse non static symbol warning
KEYS: revert encrypted key change
ima: add support for measuring and appraising firmware
firmware_class: perform new LSM checks
security: introduce kernel_fw_from_file hook
PKCS#7: Missing inclusion of linux/err.h
...
Diffstat (limited to 'security/selinux/ss')
-rw-r--r-- | security/selinux/ss/conditional.c | 11 | ||||
-rw-r--r-- | security/selinux/ss/ebitmap.c | 133 | ||||
-rw-r--r-- | security/selinux/ss/ebitmap.h | 8 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 141 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 41 |
5 files changed, 132 insertions, 202 deletions
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 377d148..62c6773 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -402,19 +402,14 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp) int rc; struct cond_expr *expr = NULL, *last = NULL; - rc = next_entry(buf, fp, sizeof(u32)); + rc = next_entry(buf, fp, sizeof(u32) * 2); if (rc) - return rc; + goto err; node->cur_state = le32_to_cpu(buf[0]); - len = 0; - rc = next_entry(buf, fp, sizeof(u32)); - if (rc) - return rc; - /* expr */ - len = le32_to_cpu(buf[0]); + len = le32_to_cpu(buf[1]); for (i = 0; i < len; i++) { rc = next_entry(buf, fp, sizeof(u32) * 2); diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 820313a..afe6a26 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -86,51 +86,36 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src) * */ int ebitmap_netlbl_export(struct ebitmap *ebmap, - struct netlbl_lsm_secattr_catmap **catmap) + struct netlbl_lsm_catmap **catmap) { struct ebitmap_node *e_iter = ebmap->node; - struct netlbl_lsm_secattr_catmap *c_iter; - u32 cmap_idx, cmap_sft; - int i; - - /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, - * however, it is not always compatible with an array of unsigned long - * in ebitmap_node. - * In addition, you should pay attention the following implementation - * assumes unsigned long has a width equal with or less than 64-bit. - */ + unsigned long e_map; + u32 offset; + unsigned int iter; + int rc; if (e_iter == NULL) { *catmap = NULL; return 0; } - c_iter = netlbl_secattr_catmap_alloc(GFP_ATOMIC); - if (c_iter == NULL) - return -ENOMEM; - *catmap = c_iter; - c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1); + if (*catmap != NULL) + netlbl_catmap_free(*catmap); + *catmap = NULL; while (e_iter) { - for (i = 0; i < EBITMAP_UNIT_NUMS; i++) { - unsigned int delta, e_startbit, c_endbit; - - e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE; - c_endbit = c_iter->startbit + NETLBL_CATMAP_SIZE; - if (e_startbit >= c_endbit) { - c_iter->next - = netlbl_secattr_catmap_alloc(GFP_ATOMIC); - if (c_iter->next == NULL) + offset = e_iter->startbit; + for (iter = 0; iter < EBITMAP_UNIT_NUMS; iter++) { + e_map = e_iter->maps[iter]; + if (e_map != 0) { + rc = netlbl_catmap_setlong(catmap, + offset, + e_map, + GFP_ATOMIC); + if (rc != 0) goto netlbl_export_failure; - c_iter = c_iter->next; - c_iter->startbit - = e_startbit & ~(NETLBL_CATMAP_SIZE - 1); } - delta = e_startbit - c_iter->startbit; - cmap_idx = delta / NETLBL_CATMAP_MAPSIZE; - cmap_sft = delta % NETLBL_CATMAP_MAPSIZE; - c_iter->bitmap[cmap_idx] - |= e_iter->maps[i] << cmap_sft; + offset += EBITMAP_UNIT_SIZE; } e_iter = e_iter->next; } @@ -138,7 +123,7 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, return 0; netlbl_export_failure: - netlbl_secattr_catmap_free(*catmap); + netlbl_catmap_free(*catmap); return -ENOMEM; } @@ -153,58 +138,44 @@ netlbl_export_failure: * */ int ebitmap_netlbl_import(struct ebitmap *ebmap, - struct netlbl_lsm_secattr_catmap *catmap) + struct netlbl_lsm_catmap *catmap) { + int rc; struct ebitmap_node *e_iter = NULL; - struct ebitmap_node *emap_prev = NULL; - struct netlbl_lsm_secattr_catmap *c_iter = catmap; - u32 c_idx, c_pos, e_idx, e_sft; - - /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, - * however, it is not always compatible with an array of unsigned long - * in ebitmap_node. - * In addition, you should pay attention the following implementation - * assumes unsigned long has a width equal with or less than 64-bit. - */ - - do { - for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) { - unsigned int delta; - u64 map = c_iter->bitmap[c_idx]; - - if (!map) - continue; + struct ebitmap_node *e_prev = NULL; + u32 offset = 0, idx; + unsigned long bitmap; + + for (;;) { + rc = netlbl_catmap_getlong(catmap, &offset, &bitmap); + if (rc < 0) + goto netlbl_import_failure; + if (offset == (u32)-1) + return 0; - c_pos = c_iter->startbit - + c_idx * NETLBL_CATMAP_MAPSIZE; - if (!e_iter - || c_pos >= e_iter->startbit + EBITMAP_SIZE) { - e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); - if (!e_iter) - goto netlbl_import_failure; - e_iter->startbit - = c_pos - (c_pos % EBITMAP_SIZE); - if (emap_prev == NULL) - ebmap->node = e_iter; - else - emap_prev->next = e_iter; - emap_prev = e_iter; - } - delta = c_pos - e_iter->startbit; - e_idx = delta / EBITMAP_UNIT_SIZE; - e_sft = delta % EBITMAP_UNIT_SIZE; - while (map) { - e_iter->maps[e_idx++] |= map & (-1UL); - map = EBITMAP_SHIFT_UNIT_SIZE(map); - } + if (e_iter == NULL || + offset >= e_iter->startbit + EBITMAP_SIZE) { + e_prev = e_iter; + e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); + if (e_iter == NULL) + goto netlbl_import_failure; + e_iter->startbit = offset & ~(EBITMAP_SIZE - 1); + if (e_prev == NULL) + ebmap->node = e_iter; + else + e_prev->next = e_iter; + ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; } - c_iter = c_iter->next; - } while (c_iter); - if (e_iter != NULL) - ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; - else - ebitmap_destroy(ebmap); + /* offset will always be aligned to an unsigned long */ + idx = EBITMAP_NODE_INDEX(e_iter, offset); + e_iter->maps[idx] = bitmap; + + /* next */ + offset += EBITMAP_UNIT_SIZE; + } + + /* NOTE: we should never reach this return */ return 0; netlbl_import_failure: diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index 712c8a7..9637b8c 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h @@ -132,17 +132,17 @@ int ebitmap_write(struct ebitmap *e, void *fp); #ifdef CONFIG_NETLABEL int ebitmap_netlbl_export(struct ebitmap *ebmap, - struct netlbl_lsm_secattr_catmap **catmap); + struct netlbl_lsm_catmap **catmap); int ebitmap_netlbl_import(struct ebitmap *ebmap, - struct netlbl_lsm_secattr_catmap *catmap); + struct netlbl_lsm_catmap *catmap); #else static inline int ebitmap_netlbl_export(struct ebitmap *ebmap, - struct netlbl_lsm_secattr_catmap **catmap) + struct netlbl_lsm_catmap **catmap) { return -ENOMEM; } static inline int ebitmap_netlbl_import(struct ebitmap *ebmap, - struct netlbl_lsm_secattr_catmap *catmap) + struct netlbl_lsm_catmap *catmap) { return -ENOMEM; } diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 9c5cdc2ca..bc2a586 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -1080,6 +1080,26 @@ out: * binary representation file. */ +static int str_read(char **strp, gfp_t flags, void *fp, u32 len) +{ + int rc; + char *str; + + str = kmalloc(len + 1, flags); + if (!str) + return -ENOMEM; + + /* it's expected the caller should free the str */ + *strp = str; + + rc = next_entry(str, fp, len); + if (rc) + return rc; + + str[len] = '\0'; + return 0; +} + static int perm_read(struct policydb *p, struct hashtab *h, void *fp) { char *key = NULL; @@ -1100,15 +1120,9 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp) len = le32_to_cpu(buf[0]); perdatum->value = le32_to_cpu(buf[1]); - rc = -ENOMEM; - key = kmalloc(len + 1, GFP_KERNEL); - if (!key) - goto bad; - - rc = next_entry(key, fp, len); + rc = str_read(&key, GFP_KERNEL, fp, len); if (rc) goto bad; - key[len] = '\0'; rc = hashtab_insert(h, key, perdatum); if (rc) @@ -1146,15 +1160,9 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp) comdatum->permissions.nprim = le32_to_cpu(buf[2]); nel = le32_to_cpu(buf[3]); - rc = -ENOMEM; - key = kmalloc(len + 1, GFP_KERNEL); - if (!key) - goto bad; - - rc = next_entry(key, fp, len); + rc = str_read(&key, GFP_KERNEL, fp, len); if (rc) goto bad; - key[len] = '\0'; for (i = 0; i < nel; i++) { rc = perm_read(p, comdatum->permissions.table, fp); @@ -1321,25 +1329,14 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) ncons = le32_to_cpu(buf[5]); - rc = -ENOMEM; - key = kmalloc(len + 1, GFP_KERNEL); - if (!key) - goto bad; - - rc = next_entry(key, fp, len); + rc = str_read(&key, GFP_KERNEL, fp, len); if (rc) goto bad; - key[len] = '\0'; if (len2) { - rc = -ENOMEM; - cladatum->comkey = kmalloc(len2 + 1, GFP_KERNEL); - if (!cladatum->comkey) - goto bad; - rc = next_entry(cladatum->comkey, fp, len2); + rc = str_read(&cladatum->comkey, GFP_KERNEL, fp, len2); if (rc) goto bad; - cladatum->comkey[len2] = '\0'; rc = -EINVAL; cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey); @@ -1422,15 +1419,9 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) role->bounds = le32_to_cpu(buf[2]); - rc = -ENOMEM; - key = kmalloc(len + 1, GFP_KERNEL); - if (!key) - goto bad; - - rc = next_entry(key, fp, len); + rc = str_read(&key, GFP_KERNEL, fp, len); if (rc) goto bad; - key[len] = '\0'; rc = ebitmap_read(&role->dominates, fp); if (rc) @@ -1495,14 +1486,9 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp) typdatum->primary = le32_to_cpu(buf[2]); } - rc = -ENOMEM; - key = kmalloc(len + 1, GFP_KERNEL); - if (!key) - goto bad; - rc = next_entry(key, fp, len); + rc = str_read(&key, GFP_KERNEL, fp, len); if (rc) goto bad; - key[len] = '\0'; rc = hashtab_insert(h, key, typdatum); if (rc) @@ -1565,14 +1551,9 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp) if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) usrdatum->bounds = le32_to_cpu(buf[2]); - rc = -ENOMEM; - key = kmalloc(len + 1, GFP_KERNEL); - if (!key) - goto bad; - rc = next_entry(key, fp, len); + rc = str_read(&key, GFP_KERNEL, fp, len); if (rc) goto bad; - key[len] = '\0'; rc = ebitmap_read(&usrdatum->roles, fp); if (rc) @@ -1616,14 +1597,9 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp) len = le32_to_cpu(buf[0]); levdatum->isalias = le32_to_cpu(buf[1]); - rc = -ENOMEM; - key = kmalloc(len + 1, GFP_ATOMIC); - if (!key) - goto bad; - rc = next_entry(key, fp, len); + rc = str_read(&key, GFP_ATOMIC, fp, len); if (rc) goto bad; - key[len] = '\0'; rc = -ENOMEM; levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC); @@ -1664,14 +1640,9 @@ static int cat_read(struct policydb *p, struct hashtab *h, void *fp) catdatum->value = le32_to_cpu(buf[1]); catdatum->isalias = le32_to_cpu(buf[2]); - rc = -ENOMEM; - key = kmalloc(len + 1, GFP_ATOMIC); - if (!key) - goto bad; - rc = next_entry(key, fp, len); + rc = str_read(&key, GFP_ATOMIC, fp, len); if (rc) goto bad; - key[len] = '\0'; rc = hashtab_insert(h, key, catdatum); if (rc) @@ -1968,18 +1939,12 @@ static int filename_trans_read(struct policydb *p, void *fp) goto out; len = le32_to_cpu(buf[0]); - rc = -ENOMEM; - name = kmalloc(len + 1, GFP_KERNEL); - if (!name) - goto out; - - ft->name = name; - /* path component string */ - rc = next_entry(name, fp, len); + rc = str_read(&name, GFP_KERNEL, fp, len); if (rc) goto out; - name[len] = 0; + + ft->name = name; rc = next_entry(buf, fp, sizeof(u32) * 4); if (rc) @@ -2045,17 +2010,10 @@ static int genfs_read(struct policydb *p, void *fp) if (!newgenfs) goto out; - rc = -ENOMEM; - newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL); - if (!newgenfs->fstype) - goto out; - - rc = next_entry(newgenfs->fstype, fp, len); + rc = str_read(&newgenfs->fstype, GFP_KERNEL, fp, len); if (rc) goto out; - newgenfs->fstype[len] = 0; - for (genfs_p = NULL, genfs = p->genfs; genfs; genfs_p = genfs, genfs = genfs->next) { rc = -EINVAL; @@ -2091,15 +2049,9 @@ static int genfs_read(struct policydb *p, void *fp) if (!newc) goto out; - rc = -ENOMEM; - newc->u.name = kmalloc(len + 1, GFP_KERNEL); - if (!newc->u.name) - goto out; - - rc = next_entry(newc->u.name, fp, len); + rc = str_read(&newc->u.name, GFP_KERNEL, fp, len); if (rc) goto out; - newc->u.name[len] = 0; rc = next_entry(buf, fp, sizeof(u32)); if (rc) @@ -2189,16 +2141,10 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info, goto out; len = le32_to_cpu(buf[0]); - rc = -ENOMEM; - c->u.name = kmalloc(len + 1, GFP_KERNEL); - if (!c->u.name) - goto out; - - rc = next_entry(c->u.name, fp, len); + rc = str_read(&c->u.name, GFP_KERNEL, fp, len); if (rc) goto out; - c->u.name[len] = 0; rc = context_read_and_validate(&c->context[0], p, fp); if (rc) goto out; @@ -2240,16 +2186,11 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info, if (c->v.behavior > SECURITY_FS_USE_MAX) goto out; - rc = -ENOMEM; len = le32_to_cpu(buf[1]); - c->u.name = kmalloc(len + 1, GFP_KERNEL); - if (!c->u.name) - goto out; - - rc = next_entry(c->u.name, fp, len); + rc = str_read(&c->u.name, GFP_KERNEL, fp, len); if (rc) goto out; - c->u.name[len] = 0; + rc = context_read_and_validate(&c->context[0], p, fp); if (rc) goto out; @@ -2608,7 +2549,7 @@ static int mls_write_range_helper(struct mls_range *r, void *fp) if (!eq) buf[2] = cpu_to_le32(r->level[1].sens); - BUG_ON(items > (sizeof(buf)/sizeof(buf[0]))); + BUG_ON(items > ARRAY_SIZE(buf)); rc = put_entry(buf, sizeof(u32), items, fp); if (rc) @@ -2990,7 +2931,7 @@ static int role_write(void *vkey, void *datum, void *ptr) if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) buf[items++] = cpu_to_le32(role->bounds); - BUG_ON(items > (sizeof(buf)/sizeof(buf[0]))); + BUG_ON(items > ARRAY_SIZE(buf)); rc = put_entry(buf, sizeof(u32), items, fp); if (rc) @@ -3040,7 +2981,7 @@ static int type_write(void *vkey, void *datum, void *ptr) } else { buf[items++] = cpu_to_le32(typdatum->primary); } - BUG_ON(items > (sizeof(buf) / sizeof(buf[0]))); + BUG_ON(items > ARRAY_SIZE(buf)); rc = put_entry(buf, sizeof(u32), items, fp); if (rc) return rc; @@ -3069,7 +3010,7 @@ static int user_write(void *vkey, void *datum, void *ptr) buf[items++] = cpu_to_le32(usrdatum->value); if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) buf[items++] = cpu_to_le32(usrdatum->bounds); - BUG_ON(items > (sizeof(buf) / sizeof(buf[0]))); + BUG_ON(items > ARRAY_SIZE(buf)); rc = put_entry(buf, sizeof(u32), items, fp); if (rc) return rc; diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 4bca494..2aa9d17 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2277,7 +2277,7 @@ out: } /** - * security_genfs_sid - Obtain a SID for a file in a filesystem + * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem * @fstype: filesystem type * @path: path from root of mount * @sclass: file security class @@ -2286,11 +2286,13 @@ out: * Obtain a SID to use for a file in a filesystem that * cannot support xattr or use a fixed labeling behavior like * transition SIDs or task SIDs. + * + * The caller must acquire the policy_rwlock before calling this function. */ -int security_genfs_sid(const char *fstype, - char *path, - u16 orig_sclass, - u32 *sid) +static inline int __security_genfs_sid(const char *fstype, + char *path, + u16 orig_sclass, + u32 *sid) { int len; u16 sclass; @@ -2301,8 +2303,6 @@ int security_genfs_sid(const char *fstype, while (path[0] == '/' && path[1] == '/') path++; - read_lock(&policy_rwlock); - sclass = unmap_class(orig_sclass); *sid = SECINITSID_UNLABELED; @@ -2336,11 +2336,33 @@ int security_genfs_sid(const char *fstype, *sid = c->sid[0]; rc = 0; out: - read_unlock(&policy_rwlock); return rc; } /** + * security_genfs_sid - Obtain a SID for a file in a filesystem + * @fstype: filesystem type + * @path: path from root of mount + * @sclass: file security class + * @sid: SID for path + * + * Acquire policy_rwlock before calling __security_genfs_sid() and release + * it afterward. + */ +int security_genfs_sid(const char *fstype, + char *path, + u16 orig_sclass, + u32 *sid) +{ + int retval; + + read_lock(&policy_rwlock); + retval = __security_genfs_sid(fstype, path, orig_sclass, sid); + read_unlock(&policy_rwlock); + return retval; +} + +/** * security_fs_use - Determine how to handle labeling for a filesystem. * @sb: superblock in question */ @@ -2370,7 +2392,8 @@ int security_fs_use(struct super_block *sb) } sbsec->sid = c->sid[0]; } else { - rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, &sbsec->sid); + rc = __security_genfs_sid(fstype, "/", SECCLASS_DIR, + &sbsec->sid); if (rc) { sbsec->behavior = SECURITY_FS_USE_NONE; rc = 0; |