summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorJames Morris <james.morris@microsoft.com>2019-03-26 16:28:01 -0700
committerJames Morris <james.morris@microsoft.com>2019-03-26 16:28:01 -0700
commit9d7b7bfbafba5e6cad609f1188243a7f0cd0d293 (patch)
tree3bc87cf11ab44f10a2000bb8ab22ca361a944621 /security
parent468e91cecb3218afd684b8c422490dfebe0691bb (diff)
parent8c2ffd9174779014c3fe1f96d9dc3641d9175f00 (diff)
Merge tag 'v5.1-rc2' into next-general
Merge to Linux 5.1-rc2 for subsystems to work with.
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/apparmorfs.c1
-rw-r--r--security/apparmor/audit.c3
-rw-r--r--security/apparmor/domain.c5
-rw-r--r--security/apparmor/include/audit.h3
-rw-r--r--security/apparmor/lsm.c2
-rw-r--r--security/apparmor/policy_unpack.c1
-rw-r--r--security/commoncap.c2
-rw-r--r--security/integrity/digsig.c3
-rw-r--r--security/integrity/evm/evm_crypto.c3
-rw-r--r--security/integrity/evm/evm_main.c6
-rw-r--r--security/integrity/iint.c2
-rw-r--r--security/integrity/ima/ima.h4
-rw-r--r--security/integrity/ima/ima_crypto.c10
-rw-r--r--security/integrity/ima/ima_init.c4
-rw-r--r--security/integrity/ima/ima_main.c35
-rw-r--r--security/integrity/ima/ima_policy.c6
-rw-r--r--security/integrity/ima/ima_queue.c27
-rw-r--r--security/keys/encrypted-keys/encrypted.c4
-rw-r--r--security/keys/internal.h13
-rw-r--r--security/keys/key.c5
-rw-r--r--security/keys/keyctl.c1
-rw-r--r--security/keys/keyring.c4
-rw-r--r--security/keys/proc.c3
-rw-r--r--security/keys/process_keys.c1
-rw-r--r--security/keys/request_key.c73
-rw-r--r--security/keys/request_key_auth.c18
-rw-r--r--security/keys/trusted.c73
-rw-r--r--security/lsm_audit.c10
-rw-r--r--security/security.c16
-rw-r--r--security/selinux/avc.c199
-rw-r--r--security/selinux/hooks.c156
-rw-r--r--security/selinux/include/audit.h4
-rw-r--r--security/selinux/include/avc.h6
-rw-r--r--security/selinux/include/security.h13
-rw-r--r--security/selinux/ss/avtab.c40
-rw-r--r--security/selinux/ss/avtab.h4
-rw-r--r--security/selinux/ss/conditional.c6
-rw-r--r--security/selinux/ss/policydb.c123
-rw-r--r--security/selinux/ss/policydb.h12
-rw-r--r--security/selinux/ss/services.c62
-rw-r--r--security/smack/smack.h19
-rw-r--r--security/smack/smack_lsm.c96
42 files changed, 648 insertions, 430 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 3f80a684c232..fefee040bf79 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -356,6 +356,7 @@ static void aafs_remove(struct dentry *dentry)
simple_rmdir(dir, dentry);
else
simple_unlink(dir, dentry);
+ d_delete(dentry);
dput(dentry);
}
inode_unlock(dir);
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index eeaddfe0c0fb..5a8b9cded4f2 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -225,8 +225,7 @@ int aa_audit_rule_known(struct audit_krule *rule)
return 0;
}
-int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
- struct audit_context *actx)
+int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
{
struct aa_audit_rule *rule = vrule;
struct aa_label *label;
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index c7c619578095..ca2dccf5b445 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -1444,7 +1444,10 @@ check:
new = aa_label_merge(label, target, GFP_KERNEL);
if (IS_ERR_OR_NULL(new)) {
info = "failed to build target label";
- error = PTR_ERR(new);
+ if (!new)
+ error = -ENOMEM;
+ else
+ error = PTR_ERR(new);
new = NULL;
perms.allow = 0;
goto audit;
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index b8c8b1066b0a..ee559bc2acb8 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -192,7 +192,6 @@ static inline int complain_error(int error)
void aa_audit_rule_free(void *vrule);
int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule);
int aa_audit_rule_known(struct audit_krule *rule);
-int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
- struct audit_context *actx);
+int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule);
#endif /* __AA_AUDIT_H */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index bb5a02d2439f..49d664ddff44 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1597,12 +1597,14 @@ static unsigned int apparmor_ipv4_postroute(void *priv,
return apparmor_ip_postroute(priv, skb, state);
}
+#if IS_ENABLED(CONFIG_IPV6)
static unsigned int apparmor_ipv6_postroute(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
return apparmor_ip_postroute(priv, skb, state);
}
+#endif
static const struct nf_hook_ops apparmor_nf_ops[] = {
{
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 379682e2a8d5..f6c2bcb2ab14 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -579,6 +579,7 @@ fail:
kfree(profile->secmark[i].label);
kfree(profile->secmark);
profile->secmark_count = 0;
+ profile->secmark = NULL;
}
e->pos = pos;
diff --git a/security/commoncap.c b/security/commoncap.c
index f1d117c3d8ae..c477fb673701 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -642,6 +642,8 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
+ cpu_caps->rootid = rootkuid;
+
return 0;
}
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index f45d6edecf99..e19c2eb72c51 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -87,6 +87,9 @@ static int __integrity_init_keyring(const unsigned int id, key_perm_t perm,
pr_info("Can't allocate %s keyring (%d)\n",
keyring_name[id], err);
keyring[id] = NULL;
+ } else {
+ if (id == INTEGRITY_KEYRING_PLATFORM)
+ set_platform_trusted_keys(keyring[id]);
}
return err;
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 43e2dc3a60d0..c37d08118af5 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -173,8 +173,7 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
if ((evm_hmac_attrs & EVM_ATTR_FSUUID) &&
type != EVM_XATTR_PORTABLE_DIGSIG)
- crypto_shash_update(desc, &inode->i_sb->s_uuid.b[0],
- sizeof(inode->i_sb->s_uuid));
+ crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE);
crypto_shash_final(desc, digest);
}
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 5ecaa3d6fe0b..b6d9f14bc234 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -563,7 +563,6 @@ static int __init init_evm(void)
{
int error;
struct list_head *pos, *q;
- struct xattr_list *xattr;
evm_init_config();
@@ -580,11 +579,8 @@ static int __init init_evm(void)
error:
if (error != 0) {
if (!list_empty(&evm_config_xattrnames)) {
- list_for_each_safe(pos, q, &evm_config_xattrnames) {
- xattr = list_entry(pos, struct xattr_list,
- list);
+ list_for_each_safe(pos, q, &evm_config_xattrnames)
list_del(pos);
- }
}
}
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 88f04b3380d4..423876fca8b4 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -200,7 +200,7 @@ int integrity_kernel_read(struct file *file, loff_t offset,
return -EBADF;
old_fs = get_fs();
- set_fs(get_ds());
+ set_fs(KERNEL_DS);
ret = __vfs_read(file, buf, count, &offset);
set_fs(old_fs);
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index cc12f3449a72..d213e835c498 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -153,6 +153,7 @@ int ima_measurements_show(struct seq_file *m, void *v);
unsigned long ima_get_binary_runtime_size(void);
int ima_init_template(void);
void ima_init_template_list(void);
+int __init ima_init_digests(void);
/*
* used to protect h_table and sha_table
@@ -307,8 +308,7 @@ static inline int security_filter_rule_init(u32 field, u32 op, char *rulestr,
}
static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
- void *lsmrule,
- struct audit_context *actx)
+ void *lsmrule)
{
return -EINVAL;
}
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index acf2c7df7145..16a4f45863b1 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -643,12 +643,12 @@ int ima_calc_buffer_hash(const void *buf, loff_t len,
return calc_buffer_shash(buf, len, hash);
}
-static void __init ima_pcrread(u32 idx, u8 *pcr)
+static void __init ima_pcrread(u32 idx, struct tpm_digest *d)
{
if (!ima_tpm_chip)
return;
- if (tpm_pcr_read(ima_tpm_chip, idx, pcr) != 0)
+ if (tpm_pcr_read(ima_tpm_chip, idx, d) != 0)
pr_err("Error Communicating to TPM chip\n");
}
@@ -658,7 +658,7 @@ static void __init ima_pcrread(u32 idx, u8 *pcr)
static int __init ima_calc_boot_aggregate_tfm(char *digest,
struct crypto_shash *tfm)
{
- u8 pcr_i[TPM_DIGEST_SIZE];
+ struct tpm_digest d = { .alg_id = TPM_ALG_SHA1, .digest = {0} };
int rc;
u32 i;
SHASH_DESC_ON_STACK(shash, tfm);
@@ -672,9 +672,9 @@ static int __init ima_calc_boot_aggregate_tfm(char *digest,
/* cumulative sha1 over tpm registers 0-7 */
for (i = TPM_PCR0; i < TPM_PCR8; i++) {
- ima_pcrread(i, pcr_i);
+ ima_pcrread(i, &d);
/* now accumulate with current aggregate */
- rc = crypto_shash_update(shash, pcr_i, TPM_DIGEST_SIZE);
+ rc = crypto_shash_update(shash, d.digest, TPM_DIGEST_SIZE);
}
if (!rc)
crypto_shash_final(shash, digest);
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 6bb42a9c5e47..6c9295449751 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -123,8 +123,12 @@ int __init ima_init(void)
if (rc != 0)
return rc;
+ /* It can be called before ima_init_digests(), it does not use TPM. */
ima_load_kexec_buffer();
+ rc = ima_init_digests();
+ if (rc != 0)
+ return rc;
rc = ima_add_boot_aggregate(); /* boot aggregate must be first entry */
if (rc != 0)
return rc;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 4ffac4f5c647..357edd140c09 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -397,6 +397,33 @@ int ima_file_check(struct file *file, int mask)
EXPORT_SYMBOL_GPL(ima_file_check);
/**
+ * ima_post_create_tmpfile - mark newly created tmpfile as new
+ * @file : newly created tmpfile
+ *
+ * No measuring, appraising or auditing of newly created tmpfiles is needed.
+ * Skip calling process_measurement(), but indicate which newly, created
+ * tmpfiles are in policy.
+ */
+void ima_post_create_tmpfile(struct inode *inode)
+{
+ struct integrity_iint_cache *iint;
+ int must_appraise;
+
+ must_appraise = ima_must_appraise(inode, MAY_ACCESS, FILE_CHECK);
+ if (!must_appraise)
+ return;
+
+ /* Nothing to do if we can't allocate memory */
+ iint = integrity_inode_get(inode);
+ if (!iint)
+ return;
+
+ /* needed for writing the security xattrs */
+ set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags);
+ iint->ima_file_status = INTEGRITY_PASS;
+}
+
+/**
* ima_post_path_mknod - mark as a new inode
* @dentry: newly created dentry
*
@@ -413,9 +440,13 @@ void ima_post_path_mknod(struct dentry *dentry)
if (!must_appraise)
return;
+ /* Nothing to do if we can't allocate memory */
iint = integrity_inode_get(inode);
- if (iint)
- iint->flags |= IMA_NEW_FILE;
+ if (!iint)
+ return;
+
+ /* needed for re-opening empty files */
+ iint->flags |= IMA_NEW_FILE;
}
/**
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 122797023bdb..e0cc323f948f 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -340,8 +340,7 @@ retry:
rc = security_filter_rule_match(osid,
rule->lsm[i].type,
Audit_equal,
- rule->lsm[i].rule,
- NULL);
+ rule->lsm[i].rule);
break;
case LSM_SUBJ_USER:
case LSM_SUBJ_ROLE:
@@ -349,8 +348,7 @@ retry:
rc = security_filter_rule_match(secid,
rule->lsm[i].type,
Audit_equal,
- rule->lsm[i].rule,
- NULL);
+ rule->lsm[i].rule);
default:
break;
}
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index 0e41dc1df1d4..6b6d044e0440 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -27,6 +27,9 @@
#define AUDIT_CAUSE_LEN_MAX 32
+/* pre-allocated array of tpm_digest structures to extend a PCR */
+static struct tpm_digest *digests;
+
LIST_HEAD(ima_measurements); /* list of all measurements */
#ifdef CONFIG_IMA_KEXEC
static unsigned long binary_runtime_size;
@@ -140,11 +143,15 @@ unsigned long ima_get_binary_runtime_size(void)
static int ima_pcr_extend(const u8 *hash, int pcr)
{
int result = 0;
+ int i;
if (!ima_tpm_chip)
return result;
- result = tpm_pcr_extend(ima_tpm_chip, pcr, hash);
+ for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++)
+ memcpy(digests[i].digest, hash, TPM_DIGEST_SIZE);
+
+ result = tpm_pcr_extend(ima_tpm_chip, pcr, digests);
if (result != 0)
pr_err("Error Communicating to TPM chip, result: %d\n", result);
return result;
@@ -211,3 +218,21 @@ int ima_restore_measurement_entry(struct ima_template_entry *entry)
mutex_unlock(&ima_extend_list_mutex);
return result;
}
+
+int __init ima_init_digests(void)
+{
+ int i;
+
+ if (!ima_tpm_chip)
+ return 0;
+
+ digests = kcalloc(ima_tpm_chip->nr_allocated_banks, sizeof(*digests),
+ GFP_NOFS);
+ if (!digests)
+ return -ENOMEM;
+
+ for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++)
+ digests[i].alg_id = ima_tpm_chip->allocated_banks[i].alg_id;
+
+ return 0;
+}
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index 389a298274d3..347108f660a1 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -60,11 +60,11 @@ static int blksize;
static struct crypto_shash *hash_tfm;
enum {
- Opt_err = -1, Opt_new, Opt_load, Opt_update
+ Opt_new, Opt_load, Opt_update, Opt_err
};
enum {
- Opt_error = -1, Opt_default, Opt_ecryptfs, Opt_enc32
+ Opt_default, Opt_ecryptfs, Opt_enc32, Opt_error
};
static const match_table_t key_format_tokens = {
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 479909b858c7..8f533c81aa8d 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -186,20 +186,9 @@ static inline int key_permission(const key_ref_t key_ref, unsigned perm)
return key_task_permission(key_ref, current_cred(), perm);
}
-/*
- * Authorisation record for request_key().
- */
-struct request_key_auth {
- struct key *target_key;
- struct key *dest_keyring;
- const struct cred *cred;
- void *callout_info;
- size_t callout_len;
- pid_t pid;
-} __randomize_layout;
-
extern struct key_type key_type_request_key_auth;
extern struct key *request_key_auth_new(struct key *target,
+ const char *op,
const void *callout_info,
size_t callout_len,
struct key *dest_keyring);
diff --git a/security/keys/key.c b/security/keys/key.c
index 44a80d6741a1..696f1c092c50 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -265,8 +265,8 @@ struct key *key_alloc(struct key_type *type, const char *desc,
spin_lock(&user->lock);
if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
- if (user->qnkeys + 1 >= maxkeys ||
- user->qnbytes + quotalen >= maxbytes ||
+ if (user->qnkeys + 1 > maxkeys ||
+ user->qnbytes + quotalen > maxbytes ||
user->qnbytes + quotalen < user->qnbytes)
goto no_quota;
}
@@ -297,6 +297,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
key->gid = gid;
key->perm = perm;
key->restrict_link = restrict_link;
+ key->last_used_at = ktime_get_real_seconds();
if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
key->flags |= 1 << KEY_FLAG_IN_QUOTA;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 5efde255650b..3e4053a217c3 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -25,6 +25,7 @@
#include <linux/security.h>
#include <linux/uio.h>
#include <linux/uaccess.h>
+#include <keys/request_key_auth-type.h>
#include "internal.h"
#define KEY_MAX_DESC_SIZE 4096
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index b1ff07d9ce37..e14f09e3a4b0 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -662,9 +662,6 @@ static bool search_nested_keyrings(struct key *keyring,
BUG_ON((ctx->flags & STATE_CHECKS) == 0 ||
(ctx->flags & STATE_CHECKS) == STATE_CHECKS);
- if (ctx->index_key.description)
- ctx->index_key.desc_len = strlen(ctx->index_key.description);
-
/* Check to see if this top-level keyring is what we are looking for
* and whether it is valid or not.
*/
@@ -915,6 +912,7 @@ key_ref_t keyring_search(key_ref_t keyring,
struct keyring_search_context ctx = {
.index_key.type = type,
.index_key.description = description,
+ .index_key.desc_len = strlen(description),
.cred = current_cred(),
.match_data.cmp = key_default_cmp,
.match_data.raw_data = description,
diff --git a/security/keys/proc.c b/security/keys/proc.c
index d2b802072693..78ac305d715e 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -165,8 +165,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
int rc;
struct keyring_search_context ctx = {
- .index_key.type = key->type,
- .index_key.description = key->description,
+ .index_key = key->index_key,
.cred = m->file->f_cred,
.match_data.cmp = lookup_user_key_possessed,
.match_data.raw_data = key,
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 3308d738734c..9320424c4a46 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -19,6 +19,7 @@
#include <linux/security.h>
#include <linux/user_namespace.h>
#include <linux/uaccess.h>
+#include <keys/request_key_auth-type.h>
#include "internal.h"
/* Session keyring create vs join semaphore */
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index af8816ffb6ce..2f17d84d46f1 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -18,31 +18,30 @@
#include <linux/keyctl.h>
#include <linux/slab.h>
#include "internal.h"
+#include <keys/request_key_auth-type.h>
#define key_negative_timeout 60 /* default timeout on a negative key's existence */
/**
* complete_request_key - Complete the construction of a key.
- * @cons: The key construction record.
+ * @auth_key: The authorisation key.
* @error: The success or failute of the construction.
*
* Complete the attempt to construct a key. The key will be negated
* if an error is indicated. The authorisation key will be revoked
* unconditionally.
*/
-void complete_request_key(struct key_construction *cons, int error)
+void complete_request_key(struct key *authkey, int error)
{
- kenter("{%d,%d},%d", cons->key->serial, cons->authkey->serial, error);
+ struct request_key_auth *rka = get_request_key_auth(authkey);
+ struct key *key = rka->target_key;
+
+ kenter("%d{%d},%d", authkey->serial, key->serial, error);
if (error < 0)
- key_negate_and_link(cons->key, key_negative_timeout, NULL,
- cons->authkey);
+ key_negate_and_link(key, key_negative_timeout, NULL, authkey);
else
- key_revoke(cons->authkey);
-
- key_put(cons->key);
- key_put(cons->authkey);
- kfree(cons);
+ key_revoke(authkey);
}
EXPORT_SYMBOL(complete_request_key);
@@ -91,21 +90,19 @@ static int call_usermodehelper_keys(const char *path, char **argv, char **envp,
* Request userspace finish the construction of a key
* - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>"
*/
-static int call_sbin_request_key(struct key_construction *cons,
- const char *op,
- void *aux)
+static int call_sbin_request_key(struct key *authkey, void *aux)
{
static char const request_key[] = "/sbin/request-key";
+ struct request_key_auth *rka = get_request_key_auth(authkey);
const struct cred *cred = current_cred();
key_serial_t prkey, sskey;
- struct key *key = cons->key, *authkey = cons->authkey, *keyring,
- *session;
+ struct key *key = rka->target_key, *keyring, *session;
char *argv[9], *envp[3], uid_str[12], gid_str[12];
char key_str[12], keyring_str[3][12];
char desc[20];
int ret, i;
- kenter("{%d},{%d},%s", key->serial, authkey->serial, op);
+ kenter("{%d},{%d},%s", key->serial, authkey->serial, rka->op);
ret = install_user_keyrings();
if (ret < 0)
@@ -163,7 +160,7 @@ static int call_sbin_request_key(struct key_construction *cons,
/* set up the argument list */
i = 0;
argv[i++] = (char *)request_key;
- argv[i++] = (char *) op;
+ argv[i++] = (char *)rka->op;
argv[i++] = key_str;
argv[i++] = uid_str;
argv[i++] = gid_str;
@@ -191,7 +188,7 @@ error_link:
key_put(keyring);
error_alloc:
- complete_request_key(cons, ret);
+ complete_request_key(authkey, ret);
kleave(" = %d", ret);
return ret;
}
@@ -205,42 +202,31 @@ static int construct_key(struct key *key, const void *callout_info,
size_t callout_len, void *aux,
struct key *dest_keyring)
{
- struct key_construction *cons;
request_key_actor_t actor;
struct key *authkey;
int ret;
kenter("%d,%p,%zu,%p", key->serial, callout_info, callout_len, aux);
- cons = kmalloc(sizeof(*cons), GFP_KERNEL);
- if (!cons)
- return -ENOMEM;
-
/* allocate an authorisation key */
- authkey = request_key_auth_new(key, callout_info, callout_len,
+ authkey = request_key_auth_new(key, "create", callout_info, callout_len,
dest_keyring);
- if (IS_ERR(authkey)) {
- kfree(cons);
- ret = PTR_ERR(authkey);
- authkey = NULL;
- } else {
- cons->authkey = key_get(authkey);
- cons->key = key_get(key);
+ if (IS_ERR(authkey))
+ return PTR_ERR(authkey);
- /* make the call */
- actor = call_sbin_request_key;
- if (key->type->request_key)
- actor = key->type->request_key;
+ /* Make the call */
+ actor = call_sbin_request_key;
+ if (key->type->request_key)
+ actor = key->type->request_key;
- ret = actor(cons, "create", aux);
+ ret = actor(authkey, aux);
- /* check that the actor called complete_request_key() prior to
- * returning an error */
- WARN_ON(ret < 0 &&
- !test_bit(KEY_FLAG_REVOKED, &authkey->flags));
- key_put(authkey);
- }
+ /* check that the actor called complete_request_key() prior to
+ * returning an error */
+ WARN_ON(ret < 0 &&
+ !test_bit(KEY_FLAG_REVOKED, &authkey->flags));
+ key_put(authkey);
kleave(" = %d", ret);
return ret;
}
@@ -275,7 +261,7 @@ static int construct_get_dest_keyring(struct key **_dest_keyring)
if (cred->request_key_auth) {
authkey = cred->request_key_auth;
down_read(&authkey->sem);
- rka = authkey->payload.data[0];
+ rka = get_request_key_auth(authkey);
if (!test_bit(KEY_FLAG_REVOKED,
&authkey->flags))
dest_keyring =
@@ -549,6 +535,7 @@ struct key *request_key_and_link(struct key_type *type,
struct keyring_search_context ctx = {
.index_key.type = type,
.index_key.description = description,
+ .index_key.desc_len = strlen(description),
.cred = current_cred(),
.match_data.cmp = key_default_cmp,
.match_data.raw_data = description,
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index 87ea2f54dedc..bda6201c6c45 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -17,7 +17,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include "internal.h"
-#include <keys/user-type.h>
+#include <keys/request_key_auth-type.h>
static int request_key_auth_preparse(struct key_preparsed_payload *);
static void request_key_auth_free_preparse(struct key_preparsed_payload *);
@@ -68,7 +68,7 @@ static int request_key_auth_instantiate(struct key *key,
static void request_key_auth_describe(const struct key *key,
struct seq_file *m)
{
- struct request_key_auth *rka = key->payload.data[0];
+ struct request_key_auth *rka = get_request_key_auth(key);
seq_puts(m, "key:");
seq_puts(m, key->description);
@@ -83,7 +83,7 @@ static void request_key_auth_describe(const struct key *key,
static long request_key_auth_read(const struct key *key,
char __user *buffer, size_t buflen)
{
- struct request_key_auth *rka = key->payload.data[0];
+ struct request_key_auth *rka = get_request_key_auth(key);
size_t datalen;
long ret;
@@ -109,7 +109,7 @@ static long request_key_auth_read(const struct key *key,
*/
static void request_key_auth_revoke(struct key *key)
{
- struct request_key_auth *rka = key->payload.data[0];
+ struct request_key_auth *rka = get_request_key_auth(key);
kenter("{%d}", key->serial);
@@ -136,7 +136,7 @@ static void free_request_key_auth(struct request_key_auth *rka)
*/
static void request_key_auth_destroy(struct key *key)
{
- struct request_key_auth *rka = key->payload.data[0];
+ struct request_key_auth *rka = get_request_key_auth(key);
kenter("{%d}", key->serial);
@@ -147,8 +147,9 @@ static void request_key_auth_destroy(struct key *key)
* Create an authorisation token for /sbin/request-key or whoever to gain
* access to the caller's security data.
*/
-struct key *request_key_auth_new(struct key *target, const void *callout_info,
- size_t callout_len, struct key *dest_keyring)
+struct key *request_key_auth_new(struct key *target, const char *op,
+ const void *callout_info, size_t callout_len,
+ struct key *dest_keyring)
{
struct request_key_auth *rka, *irka;
const struct cred *cred = current->cred;
@@ -166,6 +167,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
if (!rka->callout_info)
goto error_free_rka;
rka->callout_len = callout_len;
+ strlcpy(rka->op, op, sizeof(rka->op));
/* see if the calling process is already servicing the key request of
* another process */
@@ -245,7 +247,7 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
struct key *authkey;
key_ref_t authkey_ref;
- sprintf(description, "%x", target_id);
+ ctx.index_key.desc_len = sprintf(description, "%x", target_id);
authkey_ref = search_process_keyrings(&ctx);
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 4d98f4f87236..bcc9c6ead7fd 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -34,6 +34,8 @@
static const char hmac_alg[] = "hmac(sha1)";
static const char hash_alg[] = "sha1";
+static struct tpm_chip *chip;
+static struct tpm_digest *digests;
struct sdesc {
struct shash_desc shash;
@@ -362,7 +364,7 @@ int trusted_tpm_send(unsigned char *cmd, size_t buflen)
int rc;
dump_tpm_buf(cmd);
- rc = tpm_send(NULL, cmd, buflen);
+ rc = tpm_send(chip, cmd, buflen);
dump_tpm_buf(cmd);
if (rc > 0)
/* Can't return positive return codes values to keyctl */
@@ -379,15 +381,10 @@ EXPORT_SYMBOL_GPL(trusted_tpm_send);
*/
static int pcrlock(const int pcrnum)
{
- unsigned char hash[SHA1_DIGEST_SIZE];
- int ret;
-
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- ret = tpm_get_random(NULL, hash, SHA1_DIGEST_SIZE);
- if (ret != SHA1_DIGEST_SIZE)
- return ret;
- return tpm_pcr_extend(NULL, pcrnum, hash) ? -EINVAL : 0;
+
+ return tpm_pcr_extend(chip, pcrnum, digests) ? -EINVAL : 0;
}
/*
@@ -400,7 +397,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
unsigned char ononce[TPM_NONCE_SIZE];
int ret;
- ret = tpm_get_random(NULL, ononce, TPM_NONCE_SIZE);
+ ret = tpm_get_random(chip, ononce, TPM_NONCE_SIZE);
if (ret != TPM_NONCE_SIZE)
return ret;
@@ -496,7 +493,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
if (ret < 0)
goto out;
- ret = tpm_get_random(NULL, td->nonceodd, TPM_NONCE_SIZE);
+ ret = tpm_get_random(chip, td->nonceodd, TPM_NONCE_SIZE);
if (ret != TPM_NONCE_SIZE)
goto out;
ordinal = htonl(TPM_ORD_SEAL);
@@ -606,7 +603,7 @@ static int tpm_unseal(struct tpm_buf *tb,
ordinal = htonl(TPM_ORD_UNSEAL);
keyhndl = htonl(SRKHANDLE);
- ret = tpm_get_random(NULL, nonceodd, TPM_NONCE_SIZE);
+ ret = tpm_get_random(chip, nonceodd, TPM_NONCE_SIZE);
if (ret != TPM_NONCE_SIZE) {
pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
return ret;
@@ -751,7 +748,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
int i;
int tpm2;
- tpm2 = tpm_is_tpm2(NULL);
+ tpm2 = tpm_is_tpm2(chip);
if (tpm2 < 0)
return tpm2;
@@ -920,7 +917,7 @@ static struct trusted_key_options *trusted_options_alloc(void)
struct trusted_key_options *options;
int tpm2;
- tpm2 = tpm_is_tpm2(NULL);
+ tpm2 = tpm_is_tpm2(chip);
if (tpm2 < 0)
return NULL;
@@ -970,7 +967,7 @@ static int trusted_instantiate(struct key *key,
size_t key_len;
int tpm2;
- tpm2 = tpm_is_tpm2(NULL);
+ tpm2 = tpm_is_tpm2(chip);
if (tpm2 < 0)
return tpm2;
@@ -1011,7 +1008,7 @@ static int trusted_instantiate(struct key *key,
switch (key_cmd) {
case Opt_load:
if (tpm2)
- ret = tpm_unseal_trusted(NULL, payload, options);
+ ret = tpm_unseal_trusted(chip, payload, options);
else
ret = key_unseal(payload, options);
dump_payload(payload);
@@ -1021,13 +1018,13 @@ static int trusted_instantiate(struct key *key,
break;
case Opt_new:
key_len = payload->key_len;
- ret = tpm_get_random(NULL, payload->key, key_len);
+ ret = tpm_get_random(chip, payload->key, key_len);
if (ret != key_len) {
pr_info("trusted_key: key_create failed (%d)\n", ret);
goto out;
}
if (tpm2)
- ret = tpm_seal_trusted(NULL, payload, options);
+ ret = tpm_seal_trusted(chip, payload, options);
else
ret = key_seal(payload, options);
if (ret < 0)
@@ -1221,21 +1218,59 @@ hashalg_fail:
return ret;
}
+static int __init init_digests(void)
+{
+ u8 digest[TPM_MAX_DIGEST_SIZE];
+ int ret;
+ int i;
+
+ ret = tpm_get_random(chip, digest, TPM_MAX_DIGEST_SIZE);
+ if (ret < 0)
+ return ret;
+ if (ret < TPM_MAX_DIGEST_SIZE)
+ return -EFAULT;
+
+ digests = kcalloc(chip->nr_allocated_banks, sizeof(*digests),
+ GFP_KERNEL);
+ if (!digests)
+ return -ENOMEM;
+
+ for (i = 0; i < chip->nr_allocated_banks; i++)
+ memcpy(digests[i].digest, digest, TPM_MAX_DIGEST_SIZE);
+
+ return 0;
+}
+
static int __init init_trusted(void)
{
int ret;
+ chip = tpm_default_chip();
+ if (!chip)
+ return -ENOENT;
+ ret = init_digests();
+ if (ret < 0)
+ goto err_put;
ret = trusted_shash_alloc();
if (ret < 0)
- return ret;
+ goto err_free;
ret = register_key_type(&key_type_trusted);
if (ret < 0)
- trusted_shash_release();
+ goto err_release;
+ return 0;
+err_release:
+ trusted_shash_release();
+err_free:
+ kfree(digests);
+err_put:
+ put_device(&chip->dev);
return ret;
}
static void __exit cleanup_trusted(void)
{
+ put_device(&chip->dev);
+ kfree(digests);
trusted_shash_release();
unregister_key_type(&key_type_trusted);
}
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
index f84001019356..33028c098ef3 100644
--- a/security/lsm_audit.c
+++ b/security/lsm_audit.c
@@ -321,6 +321,7 @@ static void dump_common_audit_data(struct audit_buffer *ab,
if (a->u.net->sk) {
struct sock *sk = a->u.net->sk;
struct unix_sock *u;
+ struct unix_address *addr;
int len = 0;
char *p = NULL;
@@ -351,14 +352,15 @@ static void dump_common_audit_data(struct audit_buffer *ab,
#endif
case AF_UNIX:
u = unix_sk(sk);
+ addr = smp_load_acquire(&u->addr);
+ if (!addr)
+ break;
if (u->path.dentry) {
audit_log_d_path(ab, " path=", &u->path);
break;
}
- if (!u->addr)
- break;
- len = u->addr->len-sizeof(short);
- p = &u->addr->name->sun_path[0];
+ len = addr->len-sizeof(short);
+ p = &addr->name->sun_path[0];
audit_log_format(ab, " path=");
if (*p)
audit_log_untrustedstring(ab, p);
diff --git a/security/security.c b/security/security.c
index ed9b8cbf21cf..23cbb1a295a3 100644
--- a/security/security.c
+++ b/security/security.c
@@ -764,6 +764,16 @@ void security_bprm_committed_creds(struct linux_binprm *bprm)
call_void_hook(bprm_committed_creds, bprm);
}
+int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
+{
+ return call_int_hook(fs_context_dup, 0, fc, src_fc);
+}
+
+int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param)
+{
+ return call_int_hook(fs_context_parse_param, -ENOPARAM, fc, param);
+}
+
int security_sb_alloc(struct super_block *sb)
{
return call_int_hook(sb_alloc_security, 0, sb);
@@ -2302,11 +2312,9 @@ void security_audit_rule_free(void *lsmrule)
call_void_hook(audit_rule_free, lsmrule);
}
-int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
- struct audit_context *actx)
+int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
{
- return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
- actx);
+ return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
}
#endif /* CONFIG_AUDIT */
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 635e5c1e3e48..8346a4f7c5d7 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -130,75 +130,6 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
}
/**
- * avc_dump_av - Display an access vector in human-readable form.
- * @tclass: target security class
- * @av: access vector
- */
-static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
-{
- const char **perms;
- int i, perm;
-
- if (av == 0) {
- audit_log_format(ab, " null");
- return;
- }
-
- BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map));
- perms = secclass_map[tclass-1].perms;
-
- audit_log_format(ab, " {");
- i = 0;
- perm = 1;
- while (i < (sizeof(av) * 8)) {
- if ((perm & av) && perms[i]) {
- audit_log_format(ab, " %s", perms[i]);
- av &= ~perm;
- }
- i++;
- perm <<= 1;
- }
-
- if (av)
- audit_log_format(ab, " 0x%x", av);
-
- audit_log_format(ab, " }");
-}
-
-/**
- * avc_dump_query - Display a SID pair and a class in human-readable form.
- * @ssid: source security identifier
- * @tsid: target security identifier
- * @tclass: target security class
- */
-static void avc_dump_query(struct audit_buffer *ab, struct selinux_state *state,
- u32 ssid, u32 tsid, u16 tclass)
-{
- int rc;
- char *scontext;
- u32 scontext_len;
-
- rc = security_sid_to_context(state, ssid, &scontext, &scontext_len);
- if (rc)
- audit_log_format(ab, "ssid=%d", ssid);
- else {
- audit_log_format(ab, "scontext=%s", scontext);
- kfree(scontext);
- }
-
- rc = security_sid_to_context(state, tsid, &scontext, &scontext_len);
- if (rc)
- audit_log_format(ab, " tsid=%d", tsid);
- else {
- audit_log_format(ab, " tcontext=%s", scontext);
- kfree(scontext);
- }
-
- BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map));
- audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name);
-}
-
-/**
* avc_init - Initialize the AVC.
*
* Initialize the access vector cache.
@@ -735,11 +666,36 @@ out:
static void avc_audit_pre_callback(struct audit_buffer *ab, void *a)
{
struct common_audit_data *ad = a;
- audit_log_format(ab, "avc: %s ",
- ad->selinux_audit_data->denied ? "denied" : "granted");
- avc_dump_av(ab, ad->selinux_audit_data->tclass,
- ad->selinux_audit_data->audited);
- audit_log_format(ab, " for ");
+ struct selinux_audit_data *sad = ad->selinux_audit_data;
+ u32 av = sad->audited;
+ const char **perms;
+ int i, perm;
+
+ audit_log_format(ab, "avc: %s ", sad->denied ? "denied" : "granted");
+
+ if (av == 0) {
+ audit_log_format(ab, " null");
+ return;
+ }
+
+ perms = secclass_map[sad->tclass-1].perms;
+
+ audit_log_format(ab, " {");
+ i = 0;
+ perm = 1;
+ while (i < (sizeof(av) * 8)) {
+ if ((perm & av) && perms[i]) {
+ audit_log_format(ab, " %s", perms[i]);
+ av &= ~perm;
+ }
+ i++;
+ perm <<= 1;
+ }
+
+ if (av)
+ audit_log_format(ab, " 0x%x", av);
+
+ audit_log_format(ab, " } for ");
}
/**
@@ -751,14 +707,47 @@ static void avc_audit_pre_callback(struct audit_buffer *ab, void *a)
static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
{
struct common_audit_data *ad = a;
- audit_log_format(ab, " ");
- avc_dump_query(ab, ad->selinux_audit_data->state,
- ad->selinux_audit_data->ssid,
- ad->selinux_audit_data->tsid,
- ad->selinux_audit_data->tclass);
- if (ad->selinux_audit_data->denied) {
- audit_log_format(ab, " permissive=%u",
- ad->selinux_audit_data->result ? 0 : 1);
+ struct selinux_audit_data *sad = ad->selinux_audit_data;
+ char *scontext;
+ u32 scontext_len;
+ int rc;
+
+ rc = security_sid_to_context(sad->state, sad->ssid, &scontext,
+ &scontext_len);
+ if (rc)
+ audit_log_format(ab, " ssid=%d", sad->ssid);
+ else {
+ audit_log_format(ab, " scontext=%s", scontext);
+ kfree(scontext);
+ }
+
+ rc = security_sid_to_context(sad->state, sad->tsid, &scontext,
+ &scontext_len);
+ if (rc)
+ audit_log_format(ab, " tsid=%d", sad->tsid);
+ else {
+ audit_log_format(ab, " tcontext=%s", scontext);
+ kfree(scontext);
+ }
+
+ audit_log_format(ab, " tclass=%s", secclass_map[sad->tclass-1].name);
+
+ if (sad->denied)
+ audit_log_format(ab, " permissive=%u", sad->result ? 0 : 1);
+
+ /* in case of invalid context report also the actual context string */
+ rc = security_sid_to_context_inval(sad->state, sad->ssid, &scontext,
+ &scontext_len);
+ if (!rc && scontext) {
+ audit_log_format(ab, " srawcon=%s", scontext);
+ kfree(scontext);
+ }
+
+ rc = security_sid_to_context_inval(sad->state, sad->tsid, &scontext,
+ &scontext_len);
+ if (!rc && scontext) {
+ audit_log_format(ab, " trawcon=%s", scontext);
+ kfree(scontext);
}
}
@@ -772,6 +761,9 @@ noinline int slow_avc_audit(struct selinux_state *state,
struct common_audit_data stack_data;
struct selinux_audit_data sad;
+ if (WARN_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map)))
+ return -EINVAL;
+
if (!a) {
a = &stack_data;
a->type = LSM_AUDIT_DATA_NONE;
@@ -838,6 +830,7 @@ out:
* @ssid,@tsid,@tclass : identifier of an AVC entry
* @seqno : sequence number when decision was made
* @xpd: extended_perms_decision to be added to the node
+ * @flags: the AVC_* flags, e.g. AVC_NONBLOCKING, AVC_EXTENDED_PERMS, or 0.
*
* if a valid AVC entry doesn't exist,this function returns -ENOENT.
* if kmalloc() called internal returns NULL, this function returns -ENOMEM.
@@ -856,6 +849,22 @@ static int avc_update_node(struct selinux_avc *avc,
struct hlist_head *head;
spinlock_t *lock;
+ /*
+ * If we are in a non-blocking code path, e.g. VFS RCU walk,
+ * then we must not add permissions to a cache entry
+ * because we cannot safely audit the denial. Otherwise,
+ * during the subsequent blocking retry (e.g. VFS ref walk), we
+ * will find the permissions already granted in the cache entry
+ * and won't audit anything at all, leading to silent denials in
+ * permissive mode that only appear when in enforcing mode.
+ *
+ * See the corresponding handling in slow_avc_audit(), and the
+ * logic in selinux_inode_permission for the MAY_NOT_BLOCK flag,
+ * which is transliterated into AVC_NONBLOCKING.
+ */
+ if (flags & AVC_NONBLOCKING)
+ return 0;
+
node = avc_alloc_node(avc);
if (!node) {
rc = -ENOMEM;
@@ -1050,7 +1059,8 @@ int avc_has_extended_perms(struct selinux_state *state,
int rc = 0, rc2;
xp_node = &local_xp_node;
- BUG_ON(!requested);
+ if (WARN_ON(!requested))
+ return -EACCES;
rcu_read_lock();
@@ -1115,7 +1125,7 @@ decision:
* @tsid: target security identifier
* @tclass: target security class
* @requested: requested permissions, interpreted based on @tclass
- * @flags: AVC_STRICT or 0
+ * @flags: AVC_STRICT, AVC_NONBLOCKING, or 0
* @avd: access vector decisions
*
* Check the AVC to determine whether the @requested permissions are granted
@@ -1140,7 +1150,8 @@ inline int avc_has_perm_noaudit(struct selinux_state *state,
int rc = 0;
u32 denied;
- BUG_ON(!requested);
+ if (WARN_ON(!requested))
+ return -EACCES;
rcu_read_lock();
@@ -1191,24 +1202,6 @@ int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass,
return rc;
}
-int avc_has_perm_flags(struct selinux_state *state,
- u32 ssid, u32 tsid, u16 tclass, u32 requested,
- struct common_audit_data *auditdata,
- int flags)
-{
- struct av_decision avd;
- int rc, rc2;
-
- rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0,
- &avd);
-
- rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc,
- auditdata, flags);
- if (rc2)
- return rc2;
- return rc;
-}
-
u32 avc_policy_seqno(struct selinux_state *state)
{
return state->avc->avc_cache.latest_notif;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 5d92167dbe05..1d0b37af2444 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -48,6 +48,8 @@
#include <linux/fdtable.h>
#include <linux/namei.h>
#include <linux/mount.h>
+#include <linux/fs_context.h>
+#include <linux/fs_parser.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <linux/tty.h>
@@ -410,11 +412,11 @@ static inline int inode_doinit(struct inode *inode)
enum {
Opt_error = -1,
- Opt_context = 1,
+ Opt_context = 0,
+ Opt_defcontext = 1,
Opt_fscontext = 2,
- Opt_defcontext = 3,
- Opt_rootcontext = 4,
- Opt_seclabel = 5,
+ Opt_rootcontext = 3,
+ Opt_seclabel = 4,
};
#define A(s, has_arg) {#s, sizeof(#s) - 1, Opt_##s, has_arg}
@@ -490,16 +492,10 @@ static int may_context_mount_inode_relabel(u32 sid,
return rc;
}
-static int selinux_is_sblabel_mnt(struct super_block *sb)
+static int selinux_is_genfs_special_handling(struct super_block *sb)
{
- struct superblock_security_struct *sbsec = sb->s_security;
-
- return sbsec->behavior == SECURITY_FS_USE_XATTR ||
- sbsec->behavior == SECURITY_FS_USE_TRANS ||
- sbsec->behavior == SECURITY_FS_USE_TASK ||
- sbsec->behavior == SECURITY_FS_USE_NATIVE ||
- /* Special handling. Genfs but also in-core setxattr handler */
- !strcmp(sb->s_type->name, "sysfs") ||
+ /* Special handling. Genfs but also in-core setxattr handler */
+ return !strcmp(sb->s_type->name, "sysfs") ||
!strcmp(sb->s_type->name, "pstore") ||
!strcmp(sb->s_type->name, "debugfs") ||
!strcmp(sb->s_type->name, "tracefs") ||
@@ -509,6 +505,34 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
!strcmp(sb->s_type->name, "cgroup2")));
}
+static int selinux_is_sblabel_mnt(struct super_block *sb)
+{
+ struct superblock_security_struct *sbsec = sb->s_security;
+
+ /*
+ * IMPORTANT: Double-check logic in this function when adding a new
+ * SECURITY_FS_USE_* definition!
+ */
+ BUILD_BUG_ON(SECURITY_FS_USE_MAX != 7);
+
+ switch (sbsec->behavior) {
+ case SECURITY_FS_USE_XATTR:
+ case SECURITY_FS_USE_TRANS:
+ case SECURITY_FS_USE_TASK:
+ case SECURITY_FS_USE_NATIVE:
+ return 1;
+
+ case SECURITY_FS_USE_GENFS:
+ return selinux_is_genfs_special_handling(sb);
+
+ /* Never allow relabeling on context mounts */
+ case SECURITY_FS_USE_MNTPOINT:
+ case SECURITY_FS_USE_NONE:
+ default:
+ return 0;
+ }
+}
+
static int sb_finish_set_opts(struct super_block *sb)
{
struct superblock_security_struct *sbsec = sb->s_security;
@@ -915,8 +939,11 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
/* if fs is reusing a sb, make sure that the contexts match */
- if (newsbsec->flags & SE_SBINITIALIZED)
+ if (newsbsec->flags & SE_SBINITIALIZED) {
+ if ((kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context)
+ *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
return selinux_cmp_sb_context(oldsb, newsb);
+ }
mutex_lock(&newsbsec->lock);
@@ -1045,6 +1072,7 @@ static int show_sid(struct seq_file *m, u32 sid)
if (!rc) {
bool has_comma = context && strchr(context, ',');
+ seq_putc(m, '=');
if (has_comma)
seq_putc(m, '\"');
seq_escape(m, context, "\"\n\\");
@@ -1098,7 +1126,7 @@ static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
}
if (sbsec->flags & SBLABEL_MNT) {
seq_putc(m, ',');
- seq_puts(m, LABELSUPP_STR);
+ seq_puts(m, SECLABEL_STR);
}
return 0;
}
@@ -2717,6 +2745,76 @@ static int selinux_umount(struct vfsmount *mnt, int flags)
FILESYSTEM__UNMOUNT, NULL);
}
+static int selinux_fs_context_dup(struct fs_context *fc,
+ struct fs_context *src_fc)
+{
+ const struct selinux_mnt_opts *src = src_fc->security;
+ struct selinux_mnt_opts *opts;
+
+ if (!src)
+ return 0;
+
+ fc->security = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
+ if (!fc->security)
+ return -ENOMEM;
+
+ opts = fc->security;
+
+ if (src->fscontext) {
+ opts->fscontext = kstrdup(src->fscontext, GFP_KERNEL);
+ if (!opts->fscontext)
+ return -ENOMEM;
+ }
+ if (src->context) {
+ opts->context = kstrdup(src->context, GFP_KERNEL);
+ if (!opts->context)
+ return -ENOMEM;
+ }
+ if (src->rootcontext) {
+ opts->rootcontext = kstrdup(src->rootcontext, GFP_KERNEL);
+ if (!opts->rootcontext)
+ return -ENOMEM;
+ }
+ if (src->defcontext) {
+ opts->defcontext = kstrdup(src->defcontext, GFP_KERNEL);
+ if (!opts->defcontext)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static const struct fs_parameter_spec selinux_param_specs[] = {
+ fsparam_string(CONTEXT_STR, Opt_context),
+ fsparam_string(DEFCONTEXT_STR, Opt_defcontext),
+ fsparam_string(FSCONTEXT_STR, Opt_fscontext),
+ fsparam_string(ROOTCONTEXT_STR, Opt_rootcontext),
+ fsparam_flag (SECLABEL_STR, Opt_seclabel),
+ {}
+};
+
+static const struct fs_parameter_description selinux_fs_parameters = {
+ .name = "SELinux",
+ .specs = selinux_param_specs,
+};
+
+static int selinux_fs_context_parse_param(struct fs_context *fc,
+ struct fs_parameter *param)
+{
+ struct fs_parse_result result;
+ int opt, rc;
+
+ opt = fs_parse(fc, &selinux_fs_parameters, param, &result);
+ if (opt < 0)
+ return opt;
+
+ rc = selinux_add_opt(opt, param->string, &fc->security);
+ if (!rc) {
+ param->string = NULL;
+ rc = 1;
+ }
+ return rc;
+}
+
/* inode security operations */
static int selinux_inode_alloc_security(struct inode *inode)
@@ -2881,9 +2979,8 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
if (IS_ERR(isec))
return PTR_ERR(isec);
- return avc_has_perm_flags(&selinux_state,
- sid, isec->sid, isec->sclass, FILE__READ, &ad,
- rcu ? MAY_NOT_BLOCK : 0);
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, isec->sclass, FILE__READ, &ad);
}
static noinline int audit_inode_permission(struct inode *inode,
@@ -2938,7 +3035,9 @@ static int selinux_inode_permission(struct inode *inode, int mask)
return PTR_ERR(isec);
rc = avc_has_perm_noaudit(&selinux_state,
- sid, isec->sid, isec->sclass, perms, 0, &avd);
+ sid, isec->sid, isec->sclass, perms,
+ (flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0,
+ &avd);
audited = avc_audit_required(perms, &avd, rc,
from_access ? FILE__AUDIT_ACCESS : 0,
&denied);
@@ -3197,12 +3296,16 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
struct inode_security_struct *isec = inode_security_novalidate(inode);
+ struct superblock_security_struct *sbsec = inode->i_sb->s_security;
u32 newsid;
int rc;
if (strcmp(name, XATTR_SELINUX_SUFFIX))
return -EOPNOTSUPP;
+ if (!(sbsec->flags & SBLABEL_MNT))
+ return -EOPNOTSUPP;
+
if (!value || !size)
return -EACCES;
@@ -4445,7 +4548,7 @@ err_af:
}
/* This supports connect(2) and SCTP connect services such as sctp_connectx(3)
- * and sctp_sendmsg(3) as described in Documentation/security/LSM-sctp.rst
+ * and sctp_sendmsg(3) as described in Documentation/security/SCTP.rst
*/
static int selinux_socket_connect_helper(struct socket *sock,
struct sockaddr *address, int addrlen)
@@ -5034,6 +5137,9 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname,
return -EINVAL;
}
+ if (walk_size + len > addrlen)
+ return -EINVAL;
+
err = -EINVAL;
switch (optname) {
/* Bind checks */
@@ -6236,7 +6342,10 @@ static void selinux_inode_invalidate_secctx(struct inode *inode)
*/
static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
{
- return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
+ int rc = selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX,
+ ctx, ctxlen, 0);
+ /* Do not return error when suppressing label (SBLABEL_MNT not set). */
+ return rc == -EOPNOTSUPP ? 0 : rc;
}
/*
@@ -6562,6 +6671,9 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
+ LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup),
+ LSM_HOOK_INIT(fs_context_parse_param, selinux_fs_context_parse_param),
+
LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts),
@@ -6807,6 +6919,8 @@ static __init int selinux_init(void)
else
pr_debug("SELinux: Starting in permissive mode\n");
+ fs_validate_description(&selinux_fs_parameters);
+
return 0;
}
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
index 36e1d44c0209..682e2b5de2a4 100644
--- a/security/selinux/include/audit.h
+++ b/security/selinux/include/audit.h
@@ -43,13 +43,11 @@ void selinux_audit_rule_free(void *rule);
* @field: the field this rule refers to
* @op: the operater the rule uses
* @rule: pointer to the audit rule to check against
- * @actx: the audit context (can be NULL) associated with the check
*
* Returns 1 if the context id matches the rule, 0 if it does not, and
* -errno on failure.
*/
-int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule,
- struct audit_context *actx);
+int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule);
/**
* selinux_audit_rule_known - check to see if rule contains selinux fields.
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index ef899bcfd2cb..7be0e1e90e8b 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -142,6 +142,7 @@ static inline int avc_audit(struct selinux_state *state,
#define AVC_STRICT 1 /* Ignore permissive mode. */
#define AVC_EXTENDED_PERMS 2 /* update extended permissions */
+#define AVC_NONBLOCKING 4 /* non blocking */
int avc_has_perm_noaudit(struct selinux_state *state,
u32 ssid, u32 tsid,
u16 tclass, u32 requested,
@@ -152,11 +153,6 @@ int avc_has_perm(struct selinux_state *state,
u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct common_audit_data *auditdata);
-int avc_has_perm_flags(struct selinux_state *state,
- u32 ssid, u32 tsid,
- u16 tclass, u32 requested,
- struct common_audit_data *auditdata,
- int flags);
int avc_has_extended_perms(struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass, u32 requested,
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index ba8eedf42b90..b5b7c5aade8c 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -59,11 +59,11 @@
#define SE_SBPROC 0x0200
#define SE_SBGENFS 0x0400
-#define CONTEXT_STR "context="
-#define FSCONTEXT_STR "fscontext="
-#define ROOTCONTEXT_STR "rootcontext="
-#define DEFCONTEXT_STR "defcontext="
-#define LABELSUPP_STR "seclabel"
+#define CONTEXT_STR "context"
+#define FSCONTEXT_STR "fscontext"
+#define ROOTCONTEXT_STR "rootcontext"
+#define DEFCONTEXT_STR "defcontext"
+#define SECLABEL_STR "seclabel"
struct netlbl_lsm_secattr;
@@ -255,6 +255,9 @@ int security_sid_to_context(struct selinux_state *state, u32 sid,
int security_sid_to_context_force(struct selinux_state *state,
u32 sid, char **scontext, u32 *scontext_len);
+int security_sid_to_context_inval(struct selinux_state *state,
+ u32 sid, char **scontext, u32 *scontext_len);
+
int security_context_to_sid(struct selinux_state *state,
const char *scontext, u32 scontext_len,
u32 *out_sid, gfp_t gfp);
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index c0417cf17fee..8c5800750fa8 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -93,12 +93,10 @@ avtab_insert_node(struct avtab *h, int hvalue,
newnode->next = prev->next;
prev->next = newnode;
} else {
- newnode->next = flex_array_get_ptr(h->htable, hvalue);
- if (flex_array_put_ptr(h->htable, hvalue, newnode,
- GFP_KERNEL|__GFP_ZERO)) {
- kmem_cache_free(avtab_node_cachep, newnode);
- return NULL;
- }
+ struct avtab_node **n = &h->htable[hvalue];
+
+ newnode->next = *n;
+ *n = newnode;
}
h->nel++;
@@ -111,11 +109,11 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat
struct avtab_node *prev, *cur, *newnode;
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
- if (!h || !h->htable)
+ if (!h)
return -EINVAL;
hvalue = avtab_hash(key, h->mask);
- for (prev = NULL, cur = flex_array_get_ptr(h->htable, hvalue);
+ for (prev = NULL, cur = h->htable[hvalue];
cur;
prev = cur, cur = cur->next) {
if (key->source_type == cur->key.source_type &&
@@ -156,10 +154,10 @@ avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datu
struct avtab_node *prev, *cur;
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
- if (!h || !h->htable)
+ if (!h)
return NULL;
hvalue = avtab_hash(key, h->mask);
- for (prev = NULL, cur = flex_array_get_ptr(h->htable, hvalue);
+ for (prev = NULL, cur = h->htable[hvalue];
cur;
prev = cur, cur = cur->next) {
if (key->source_type == cur->key.source_type &&
@@ -186,11 +184,11 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
struct avtab_node *cur;
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
- if (!h || !h->htable)
+ if (!h)
return NULL;
hvalue = avtab_hash(key, h->mask);
- for (cur = flex_array_get_ptr(h->htable, hvalue); cur;
+ for (cur = h->htable[hvalue]; cur;
cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
@@ -222,11 +220,11 @@ avtab_search_node(struct avtab *h, struct avtab_key *key)
struct avtab_node *cur;
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
- if (!h || !h->htable)
+ if (!h)
return NULL;
hvalue = avtab_hash(key, h->mask);
- for (cur = flex_array_get_ptr(h->htable, hvalue); cur;
+ for (cur = h->htable[hvalue]; cur;
cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
@@ -281,11 +279,11 @@ void avtab_destroy(struct avtab *h)
int i;
struct avtab_node *cur, *temp;
- if (!h || !h->htable)
+ if (!h)
return;
for (i = 0; i < h->nslot; i++) {
- cur = flex_array_get_ptr(h->htable, i);
+ cur = h->htable[i];
while (cur) {
temp = cur;
cur = cur->next;
@@ -295,7 +293,7 @@ void avtab_destroy(struct avtab *h)
kmem_cache_free(avtab_node_cachep, temp);
}
}
- flex_array_free(h->htable);
+ kvfree(h->htable);
h->htable = NULL;
h->nslot = 0;
h->mask = 0;
@@ -303,6 +301,7 @@ void avtab_destroy(struct avtab *h)
int avtab_init(struct avtab *h)
{
+ kvfree(h->htable);
h->htable = NULL;
h->nel = 0;
return 0;
@@ -329,8 +328,7 @@ int avtab_alloc(struct avtab *h, u32 nrules)
nslot = MAX_AVTAB_HASH_BUCKETS;
mask = nslot - 1;
- h->htable = flex_array_alloc(sizeof(struct avtab_node *), nslot,
- GFP_KERNEL | __GFP_ZERO);
+ h->htable = kvcalloc(nslot, sizeof(void *), GFP_KERNEL);
if (!h->htable)
return -ENOMEM;
@@ -353,7 +351,7 @@ void avtab_hash_eval(struct avtab *h, char *tag)
max_chain_len = 0;
chain2_len_sum = 0;
for (i = 0; i < h->nslot; i++) {
- cur = flex_array_get_ptr(h->htable, i);
+ cur = h->htable[i];
if (cur) {
slots_used++;
chain_len = 0;
@@ -646,7 +644,7 @@ int avtab_write(struct policydb *p, struct avtab *a, void *fp)
return rc;
for (i = 0; i < a->nslot; i++) {
- for (cur = flex_array_get_ptr(a->htable, i); cur;
+ for (cur = a->htable[i]; cur;
cur = cur->next) {
rc = avtab_write_item(p, cur, fp);
if (rc)
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
index 0d652fad5319..de16673b2314 100644
--- a/security/selinux/ss/avtab.h
+++ b/security/selinux/ss/avtab.h
@@ -24,7 +24,6 @@
#define _SS_AVTAB_H_
#include "security.h"
-#include <linux/flex_array.h>
struct avtab_key {
u16 source_type; /* source type */
@@ -84,11 +83,10 @@ struct avtab_node {
};
struct avtab {
- struct flex_array *htable;
+ struct avtab_node **htable;
u32 nel; /* number of elements */
u32 nslot; /* number of hash slots */
u32 mask; /* mask to compute hash func */
-
};
int avtab_init(struct avtab *);
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index f49e522e932d..3bbb60345209 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -195,7 +195,6 @@ int cond_index_bool(void *key, void *datum, void *datap)
{
struct policydb *p;
struct cond_bool_datum *booldatum;
- struct flex_array *fa;
booldatum = datum;
p = datap;
@@ -203,10 +202,7 @@ int cond_index_bool(void *key, void *datum, void *datap)
if (!booldatum->value || booldatum->value > p->p_bools.nprim)
return -EINVAL;
- fa = p->sym_val_to_name[SYM_BOOLS];
- if (flex_array_put_ptr(fa, booldatum->value - 1, key,
- GFP_KERNEL | __GFP_ZERO))
- BUG();
+ p->sym_val_to_name[SYM_BOOLS][booldatum->value - 1] = key;
p->bool_val_to_struct[booldatum->value - 1] = booldatum;
return 0;
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index c1c31e33657a..daecdfb15a9c 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -36,7 +36,6 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/audit.h>
-#include <linux/flex_array.h>
#include "security.h"
#include "policydb.h"
@@ -341,17 +340,14 @@ static int common_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct common_datum *comdatum;
- struct flex_array *fa;
comdatum = datum;
p = datap;
if (!comdatum->value || comdatum->value > p->p_commons.nprim)
return -EINVAL;
- fa = p->sym_val_to_name[SYM_COMMONS];
- if (flex_array_put_ptr(fa, comdatum->value - 1, key,
- GFP_KERNEL | __GFP_ZERO))
- BUG();
+ p->sym_val_to_name[SYM_COMMONS][comdatum->value - 1] = key;
+
return 0;
}
@@ -359,16 +355,13 @@ static int class_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct class_datum *cladatum;
- struct flex_array *fa;
cladatum = datum;
p = datap;
if (!cladatum->value || cladatum->value > p->p_classes.nprim)
return -EINVAL;
- fa = p->sym_val_to_name[SYM_CLASSES];
- if (flex_array_put_ptr(fa, cladatum->value - 1, key,
- GFP_KERNEL | __GFP_ZERO))
- BUG();
+
+ p->sym_val_to_name[SYM_CLASSES][cladatum->value - 1] = key;
p->class_val_to_struct[cladatum->value - 1] = cladatum;
return 0;
}
@@ -377,7 +370,6 @@ static int role_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct role_datum *role;
- struct flex_array *fa;
role = datum;
p = datap;
@@ -386,10 +378,7 @@ static int role_index(void *key, void *datum, void *datap)
|| role->bounds > p->p_roles.nprim)
return -EINVAL;
- fa = p->sym_val_to_name[SYM_ROLES];
- if (flex_array_put_ptr(fa, role->value - 1, key,
- GFP_KERNEL | __GFP_ZERO))
- BUG();
+ p->sym_val_to_name[SYM_ROLES][role->value - 1] = key;
p->role_val_to_struct[role->value - 1] = role;
return 0;
}
@@ -398,7 +387,6 @@ static int type_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct type_datum *typdatum;
- struct flex_array *fa;
typdatum = datum;
p = datap;
@@ -408,15 +396,8 @@ static int type_index(void *key, void *datum, void *datap)
|| typdatum->value > p->p_types.nprim
|| typdatum->bounds > p->p_types.nprim)
return -EINVAL;
- fa = p->sym_val_to_name[SYM_TYPES];
- if (flex_array_put_ptr(fa, typdatum->value - 1, key,
- GFP_KERNEL | __GFP_ZERO))
- BUG();
-
- fa = p->type_val_to_struct_array;
- if (flex_array_put_ptr(fa, typdatum->value - 1, typdatum,
- GFP_KERNEL | __GFP_ZERO))
- BUG();
+ p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key;
+ p->type_val_to_struct_array[typdatum->value - 1] = typdatum;
}
return 0;
@@ -426,7 +407,6 @@ static int user_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct user_datum *usrdatum;
- struct flex_array *fa;
usrdatum = datum;
p = datap;
@@ -435,10 +415,7 @@ static int user_index(void *key, void *datum, void *datap)
|| usrdatum->bounds > p->p_users.nprim)
return -EINVAL;
- fa = p->sym_val_to_name[SYM_USERS];
- if (flex_array_put_ptr(fa, usrdatum->value - 1, key,
- GFP_KERNEL | __GFP_ZERO))
- BUG();
+ p->sym_val_to_name[SYM_USERS][usrdatum->value - 1] = key;
p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
return 0;
}
@@ -447,7 +424,6 @@ static int sens_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct level_datum *levdatum;
- struct flex_array *fa;
levdatum = datum;
p = datap;
@@ -456,10 +432,8 @@ static int sens_index(void *key, void *datum, void *datap)
if (!levdatum->level->sens ||
levdatum->level->sens > p->p_levels.nprim)
return -EINVAL;
- fa = p->sym_val_to_name[SYM_LEVELS];
- if (flex_array_put_ptr(fa, levdatum->level->sens - 1, key,
- GFP_KERNEL | __GFP_ZERO))
- BUG();
+
+ p->sym_val_to_name[SYM_LEVELS][levdatum->level->sens - 1] = key;
}
return 0;
@@ -469,7 +443,6 @@ static int cat_index(void *key, void *datum, void *datap)
{
struct policydb *p;
struct cat_datum *catdatum;
- struct flex_array *fa;
catdatum = datum;
p = datap;
@@ -477,10 +450,8 @@ static int cat_index(void *key, void *datum, void *datap)
if (!catdatum->isalias) {
if (!catdatum->value || catdatum->value > p->p_cats.nprim)
return -EINVAL;
- fa = p->sym_val_to_name[SYM_CATS];
- if (flex_array_put_ptr(fa, catdatum->value - 1, key,
- GFP_KERNEL | __GFP_ZERO))
- BUG();
+
+ p->sym_val_to_name[SYM_CATS][catdatum->value - 1] = key;
}
return 0;
@@ -568,35 +539,23 @@ static int policydb_index(struct policydb *p)
if (!p->user_val_to_struct)
return -ENOMEM;
- /* Yes, I want the sizeof the pointer, not the structure */
- p->type_val_to_struct_array = flex_array_alloc(sizeof(struct type_datum *),
- p->p_types.nprim,
- GFP_KERNEL | __GFP_ZERO);
+ p->type_val_to_struct_array = kvcalloc(p->p_types.nprim,
+ sizeof(*p->type_val_to_struct_array),
+ GFP_KERNEL);
if (!p->type_val_to_struct_array)
return -ENOMEM;
- rc = flex_array_prealloc(p->type_val_to_struct_array, 0,
- p->p_types.nprim, GFP_KERNEL | __GFP_ZERO);
- if (rc)
- goto out;
-
rc = cond_init_bool_indexes(p);
if (rc)
goto out;
for (i = 0; i < SYM_NUM; i++) {
- p->sym_val_to_name[i] = flex_array_alloc(sizeof(char *),
- p->symtab[i].nprim,
- GFP_KERNEL | __GFP_ZERO);
+ p->sym_val_to_name[i] = kvcalloc(p->symtab[i].nprim,
+ sizeof(char *),
+ GFP_KERNEL);
if (!p->sym_val_to_name[i])
return -ENOMEM;
- rc = flex_array_prealloc(p->sym_val_to_name[i],
- 0, p->symtab[i].nprim,
- GFP_KERNEL | __GFP_ZERO);
- if (rc)
- goto out;
-
rc = hashtab_map(p->symtab[i].table, index_f[i], p);
if (rc)
goto out;
@@ -810,16 +769,13 @@ void policydb_destroy(struct policydb *p)
hashtab_destroy(p->symtab[i].table);
}
- for (i = 0; i < SYM_NUM; i++) {
- if (p->sym_val_to_name[i])
- flex_array_free(p->sym_val_to_name[i]);
- }
+ for (i = 0; i < SYM_NUM; i++)
+ kvfree(p->sym_val_to_name[i]);
kfree(p->class_val_to_struct);
kfree(p->role_val_to_struct);
kfree(p->user_val_to_struct);
- if (p->type_val_to_struct_array)
- flex_array_free(p->type_val_to_struct_array);
+ kvfree(p->type_val_to_struct_array);
avtab_destroy(&p->te_avtab);
@@ -873,15 +829,9 @@ void policydb_destroy(struct policydb *p)
hashtab_destroy(p->range_tr);
if (p->type_attr_map_array) {
- for (i = 0; i < p->p_types.nprim; i++) {
- struct ebitmap *e;
-
- e = flex_array_get(p->type_attr_map_array, i);
- if (!e)
- continue;
- ebitmap_destroy(e);
- }
- flex_array_free(p->type_attr_map_array);
+ for (i = 0; i < p->p_types.nprim; i++)
+ ebitmap_destroy(&p->type_attr_map_array[i]);
+ kvfree(p->type_attr_map_array);
}
ebitmap_destroy(&p->filename_trans_ttypes);
@@ -1770,8 +1720,7 @@ static int type_bounds_sanity_check(void *key, void *datum, void *datap)
return -EINVAL;
}
- upper = flex_array_get_ptr(p->type_val_to_struct_array,
- upper->bounds - 1);
+ upper = p->type_val_to_struct_array[upper->bounds - 1];
BUG_ON(!upper);
if (upper->attribute) {
@@ -2543,24 +2492,19 @@ int policydb_read(struct policydb *p, void *fp)
if (rc)
goto bad;
- rc = -ENOMEM;
- p->type_attr_map_array = flex_array_alloc(sizeof(struct ebitmap),
- p->p_types.nprim,
- GFP_KERNEL | __GFP_ZERO);
+ p->type_attr_map_array = kvcalloc(p->p_types.nprim,
+ sizeof(*p->type_attr_map_array),
+ GFP_KERNEL);
if (!p->type_attr_map_array)
goto bad;
- /* preallocate so we don't have to worry about the put ever failing */
- rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim,
- GFP_KERNEL | __GFP_ZERO);
- if (rc)
- goto bad;
+ /* just in case ebitmap_init() becomes more than just a memset(0): */
+ for (i = 0; i < p->p_types.nprim; i++)
+ ebitmap_init(&p->type_attr_map_array[i]);
for (i = 0; i < p->p_types.nprim; i++) {
- struct ebitmap *e = flex_array_get(p->type_attr_map_array, i);
+ struct ebitmap *e = &p->type_attr_map_array[i];
- BUG_ON(!e);
- ebitmap_init(e);
if (p->policyvers >= POLICYDB_VERSION_AVTAB) {
rc = ebitmap_read(e, fp);
if (rc)
@@ -3554,9 +3498,8 @@ int policydb_write(struct policydb *p, void *fp)
return rc;
for (i = 0; i < p->p_types.nprim; i++) {
- struct ebitmap *e = flex_array_get(p->type_attr_map_array, i);
+ struct ebitmap *e = &p->type_attr_map_array[i];
- BUG_ON(!e);
rc = ebitmap_write(e, fp);
if (rc)
return rc;
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index 215f8f30ac5a..27039149ff0a 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -24,8 +24,6 @@
#ifndef _SS_POLICYDB_H_
#define _SS_POLICYDB_H_
-#include <linux/flex_array.h>
-
#include "symtab.h"
#include "avtab.h"
#include "sidtab.h"
@@ -251,13 +249,13 @@ struct policydb {
#define p_cats symtab[SYM_CATS]
/* symbol names indexed by (value - 1) */
- struct flex_array *sym_val_to_name[SYM_NUM];
+ char **sym_val_to_name[SYM_NUM];
/* class, role, and user attributes indexed by (value - 1) */
struct class_datum **class_val_to_struct;
struct role_datum **role_val_to_struct;
struct user_datum **user_val_to_struct;
- struct flex_array *type_val_to_struct_array;
+ struct type_datum **type_val_to_struct_array;
/* type enforcement access vectors and transitions */
struct avtab te_avtab;
@@ -294,7 +292,7 @@ struct policydb {
struct hashtab *range_tr;
/* type -> attribute reverse mapping */
- struct flex_array *type_attr_map_array;
+ struct ebitmap *type_attr_map_array;
struct ebitmap policycaps;
@@ -369,9 +367,7 @@ static inline int put_entry(const void *buf, size_t bytes, int num, struct polic
static inline char *sym_name(struct policydb *p, unsigned int sym_num, unsigned int element_nr)
{
- struct flex_array *fa = p->sym_val_to_name[sym_num];
-
- return flex_array_get_ptr(fa, element_nr);
+ return p->sym_val_to_name[sym_num][element_nr];
}
extern u16 string_to_security_class(struct policydb *p, const char *name);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index d6e7b4856d93..ec62918521b1 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -49,7 +49,6 @@
#include <linux/sched.h>
#include <linux/audit.h>
#include <linux/mutex.h>
-#include <linux/flex_array.h>
#include <linux/vmalloc.h>
#include <net/netlabel.h>
@@ -545,15 +544,13 @@ static void type_attribute_bounds_av(struct policydb *policydb,
struct type_datum *target;
u32 masked = 0;
- source = flex_array_get_ptr(policydb->type_val_to_struct_array,
- scontext->type - 1);
+ source = policydb->type_val_to_struct_array[scontext->type - 1];
BUG_ON(!source);
if (!source->bounds)
return;
- target = flex_array_get_ptr(policydb->type_val_to_struct_array,
- tcontext->type - 1);
+ target = policydb->type_val_to_struct_array[tcontext->type - 1];
BUG_ON(!target);
memset(&lo_avd, 0, sizeof(lo_avd));
@@ -653,11 +650,9 @@ static void context_struct_compute_av(struct policydb *policydb,
*/
avkey.target_class = tclass;
avkey.specified = AVTAB_AV | AVTAB_XPERMS;
- sattr = flex_array_get(policydb->type_attr_map_array,
- scontext->type - 1);
+ sattr = &policydb->type_attr_map_array[scontext->type - 1];
BUG_ON(!sattr);
- tattr = flex_array_get(policydb->type_attr_map_array,
- tcontext->type - 1);
+ tattr = &policydb->type_attr_map_array[tcontext->type - 1];
BUG_ON(!tattr);
ebitmap_for_each_positive_bit(sattr, snode, i) {
ebitmap_for_each_positive_bit(tattr, tnode, j) {
@@ -900,8 +895,7 @@ int security_bounded_transition(struct selinux_state *state,
index = new_context->type;
while (true) {
- type = flex_array_get_ptr(policydb->type_val_to_struct_array,
- index - 1);
+ type = policydb->type_val_to_struct_array[index - 1];
BUG_ON(!type);
/* not bounded anymore */
@@ -1064,11 +1058,9 @@ void security_compute_xperms_decision(struct selinux_state *state,
avkey.target_class = tclass;
avkey.specified = AVTAB_XPERMS;
- sattr = flex_array_get(policydb->type_attr_map_array,
- scontext->type - 1);
+ sattr = &policydb->type_attr_map_array[scontext->type - 1];
BUG_ON(!sattr);
- tattr = flex_array_get(policydb->type_attr_map_array,
- tcontext->type - 1);
+ tattr = &policydb->type_attr_map_array[tcontext->type - 1];
BUG_ON(!tattr);
ebitmap_for_each_positive_bit(sattr, snode, i) {
ebitmap_for_each_positive_bit(tattr, tnode, j) {
@@ -1280,7 +1272,8 @@ const char *security_get_initial_sid_context(u32 sid)
static int security_sid_to_context_core(struct selinux_state *state,
u32 sid, char **scontext,
- u32 *scontext_len, int force)
+ u32 *scontext_len, int force,
+ int only_invalid)
{
struct policydb *policydb;
struct sidtab *sidtab;
@@ -1325,8 +1318,14 @@ static int security_sid_to_context_core(struct selinux_state *state,
rc = -EINVAL;
goto out_unlock;
}
- rc = context_struct_to_string(policydb, context, scontext,
- scontext_len);
+ if (only_invalid && !context->len) {
+ scontext = NULL;
+ scontext_len = 0;
+ rc = 0;
+ } else {
+ rc = context_struct_to_string(policydb, context, scontext,
+ scontext_len);
+ }
out_unlock:
read_unlock(&state->ss->policy_rwlock);
out:
@@ -1348,14 +1347,34 @@ int security_sid_to_context(struct selinux_state *state,
u32 sid, char **scontext, u32 *scontext_len)
{
return security_sid_to_context_core(state, sid, scontext,
- scontext_len, 0);
+ scontext_len, 0, 0);
}
int security_sid_to_context_force(struct selinux_state *state, u32 sid,
char **scontext, u32 *scontext_len)
{
return security_sid_to_context_core(state, sid, scontext,
- scontext_len, 1);
+ scontext_len, 1, 0);
+}
+
+/**
+ * security_sid_to_context_inval - Obtain a context for a given SID if it
+ * is invalid.
+ * @sid: security identifier, SID
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ *
+ * Write the string representation of the context associated with @sid
+ * into a dynamically allocated string of the correct size, but only if the
+ * context is invalid in the current policy. Set @scontext to point to
+ * this string (or NULL if the context is valid) and set @scontext_len to
+ * the length of the string (or 0 if the context is valid).
+ */
+int security_sid_to_context_inval(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len)
+{
+ return security_sid_to_context_core(state, sid, scontext,
+ scontext_len, 1, 1);
}
/*
@@ -3375,8 +3394,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
return 0;
}
-int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
- struct audit_context *actx)
+int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
{
struct selinux_state *state = &selinux_state;
struct context *ctxt;
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 9c7c95a5c497..cf52af77d15e 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -196,22 +196,13 @@ struct smack_known_list_elem {
enum {
Opt_error = -1,
- Opt_fsdefault = 1,
- Opt_fsfloor = 2,
- Opt_fshat = 3,
- Opt_fsroot = 4,
- Opt_fstransmute = 5,
+ Opt_fsdefault = 0,
+ Opt_fsfloor = 1,
+ Opt_fshat = 2,
+ Opt_fsroot = 3,
+ Opt_fstransmute = 4,
};
-/*
- * Mount options
- */
-#define SMK_FSDEFAULT "smackfsdef="
-#define SMK_FSFLOOR "smackfsfloor="
-#define SMK_FSHAT "smackfshat="
-#define SMK_FSROOT "smackfsroot="
-#define SMK_FSTRANS "smackfstransmute="
-
#define SMACK_DELETE_OPTION "-DELETE"
#define SMACK_CIPSO_OPTION "-CIPSO"
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 2309c696c6c8..5c1613519d5a 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -43,6 +43,8 @@
#include <linux/shm.h>
#include <linux/binfmts.h>
#include <linux/parser.h>
+#include <linux/fs_context.h>
+#include <linux/fs_parser.h>
#include "smack.h"
#define TRANS_TRUE "TRUE"
@@ -526,7 +528,6 @@ static int smack_syslog(int typefrom_file)
return rc;
}
-
/*
* Superblock Hooks.
*/
@@ -631,6 +632,92 @@ out_opt_err:
return -EINVAL;
}
+/**
+ * smack_fs_context_dup - Duplicate the security data on fs_context duplication
+ * @fc: The new filesystem context.
+ * @src_fc: The source filesystem context being duplicated.
+ *
+ * Returns 0 on success or -ENOMEM on error.
+ */
+static int smack_fs_context_dup(struct fs_context *fc,
+ struct fs_context *src_fc)
+{
+ struct smack_mnt_opts *dst, *src = src_fc->security;
+
+ if (!src)
+ return 0;
+
+ fc->security = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL);
+ if (!fc->security)
+ return -ENOMEM;
+ dst = fc->security;
+
+ if (src->fsdefault) {
+ dst->fsdefault = kstrdup(src->fsdefault, GFP_KERNEL);
+ if (!dst->fsdefault)
+ return -ENOMEM;
+ }
+ if (src->fsfloor) {
+ dst->fsfloor = kstrdup(src->fsfloor, GFP_KERNEL);
+ if (!dst->fsfloor)
+ return -ENOMEM;
+ }
+ if (src->fshat) {
+ dst->fshat = kstrdup(src->fshat, GFP_KERNEL);
+ if (!dst->fshat)
+ return -ENOMEM;
+ }
+ if (src->fsroot) {
+ dst->fsroot = kstrdup(src->fsroot, GFP_KERNEL);
+ if (!dst->fsroot)
+ return -ENOMEM;
+ }
+ if (src->fstransmute) {
+ dst->fstransmute = kstrdup(src->fstransmute, GFP_KERNEL);
+ if (!dst->fstransmute)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static const struct fs_parameter_spec smack_param_specs[] = {
+ fsparam_string("fsdefault", Opt_fsdefault),
+ fsparam_string("fsfloor", Opt_fsfloor),
+ fsparam_string("fshat", Opt_fshat),
+ fsparam_string("fsroot", Opt_fsroot),
+ fsparam_string("fstransmute", Opt_fstransmute),
+ {}
+};
+
+static const struct fs_parameter_description smack_fs_parameters = {
+ .name = "smack",
+ .specs = smack_param_specs,
+};
+
+/**
+ * smack_fs_context_parse_param - Parse a single mount parameter
+ * @fc: The new filesystem context being constructed.
+ * @param: The parameter.
+ *
+ * Returns 0 on success, -ENOPARAM to pass the parameter on or anything else on
+ * error.
+ */
+static int smack_fs_context_parse_param(struct fs_context *fc,
+ struct fs_parameter *param)
+{
+ struct fs_parse_result result;
+ int opt, rc;
+
+ opt = fs_parse(fc, &smack_fs_parameters, param, &result);
+ if (opt < 0)
+ return opt;
+
+ rc = smack_add_opt(opt, param->string, &fc->security);
+ if (!rc)
+ param->string = NULL;
+ return rc;
+}
+
static int smack_sb_eat_lsm_opts(char *options, void **mnt_opts)
{
char *from = options, *to = options;
@@ -4295,13 +4382,11 @@ static int smack_audit_rule_known(struct audit_krule *krule)
* @field: audit rule flags given from user-space
* @op: required testing operator
* @vrule: smack internal rule presentation
- * @actx: audit context associated with the check
*
* The core Audit hook. It's used to take the decision of
* whether to audit or not to audit a given object.
*/
-static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
- struct audit_context *actx)
+static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule)
{
struct smack_known *skp;
char *rule = vrule;
@@ -4497,6 +4582,9 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
LSM_HOOK_INIT(syslog, smack_syslog),
+ LSM_HOOK_INIT(fs_context_dup, smack_fs_context_dup),
+ LSM_HOOK_INIT(fs_context_parse_param, smack_fs_context_parse_param),
+
LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security),
LSM_HOOK_INIT(sb_free_security, smack_sb_free_security),
LSM_HOOK_INIT(sb_free_mnt_opts, smack_free_mnt_opts),