summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/Kconfig8
-rw-r--r--security/commoncap.c20
-rw-r--r--security/device_cgroup.c3
-rw-r--r--security/integrity/evm/evm_crypto.c2
-rw-r--r--security/integrity/evm/evm_main.c4
-rw-r--r--security/integrity/iint.c15
-rw-r--r--security/integrity/ima/ima_api.c40
-rw-r--r--security/integrity/ima/ima_main.c12
-rw-r--r--security/integrity/ima/ima_modsig.c3
-rw-r--r--security/integrity/ima/ima_policy.c3
-rw-r--r--security/integrity/platform_certs/load_powerpc.c40
-rw-r--r--security/keys/sysctl.c7
-rw-r--r--security/landlock/Kconfig2
-rw-r--r--security/lsm_audit.c2
-rw-r--r--security/safesetid/lsm.c2
-rw-r--r--security/security.c21
-rw-r--r--security/selinux/Makefile30
-rw-r--r--security/selinux/avc.c20
-rw-r--r--security/selinux/hooks.c78
-rw-r--r--security/selinux/ima.c2
-rw-r--r--security/selinux/include/audit.h2
-rw-r--r--security/selinux/include/avc.h3
-rw-r--r--security/selinux/include/ibpkey.h1
-rw-r--r--security/selinux/include/ima.h2
-rw-r--r--security/selinux/include/initial_sid_to_string.h3
-rw-r--r--security/selinux/include/security.h2
-rw-r--r--security/selinux/netlabel.c8
-rw-r--r--security/selinux/selinuxfs.c4
-rw-r--r--security/selinux/ss/avtab.c2
-rw-r--r--security/selinux/ss/avtab.h2
-rw-r--r--security/selinux/ss/conditional.c8
-rw-r--r--security/selinux/ss/conditional.h2
-rw-r--r--security/selinux/ss/context.h2
-rw-r--r--security/selinux/ss/policydb.c6
-rw-r--r--security/selinux/ss/policydb.h2
-rw-r--r--security/selinux/ss/services.c40
-rw-r--r--security/smack/smack.h1
-rw-r--r--security/smack/smack_lsm.c63
-rw-r--r--security/tomoyo/domain.c2
39 files changed, 286 insertions, 183 deletions
diff --git a/security/Kconfig b/security/Kconfig
index 97abeb9b9a19..52c9af08ad35 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -127,16 +127,8 @@ config LSM_MMAP_MIN_ADDR
this low address space will need the permission specific to the
systems running LSM.
-config HAVE_HARDENED_USERCOPY_ALLOCATOR
- bool
- help
- The heap allocator implements __check_heap_object() for
- validating memory ranges against heap object sizes in
- support of CONFIG_HARDENED_USERCOPY.
-
config HARDENED_USERCOPY
bool "Harden memory copies between kernel and userspace"
- depends on HAVE_HARDENED_USERCOPY_ALLOCATOR
imply STRICT_DEVMEM
help
This option checks for obviously wrong memory regions when
diff --git a/security/commoncap.c b/security/commoncap.c
index 0b3fc2f3afe7..ab5742ab4362 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -314,7 +314,7 @@ int cap_inode_need_killpriv(struct dentry *dentry)
* the vfsmount must be passed through @idmap. This function will then
* take care to map the inode according to @idmap before checking
* permissions. On non-idmapped mounts or if permission checking is to be
- * performed on the raw inode simply passs @nop_mnt_idmap.
+ * performed on the raw inode simply pass @nop_mnt_idmap.
*
* Return: 0 if successful, -ve on error.
*/
@@ -522,7 +522,7 @@ static bool validheader(size_t size, const struct vfs_cap_data *cap)
* the vfsmount must be passed through @idmap. This function will then
* take care to map the inode according to @idmap before checking
* permissions. On non-idmapped mounts or if permission checking is to be
- * performed on the raw inode simply passs @nop_mnt_idmap.
+ * performed on the raw inode simply pass @nop_mnt_idmap.
*
* Return: On success, return the new size; on error, return < 0.
*/
@@ -630,7 +630,7 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
* the vfsmount must be passed through @idmap. This function will then
* take care to map the inode according to @idmap before checking
* permissions. On non-idmapped mounts or if permission checking is to be
- * performed on the raw inode simply passs @nop_mnt_idmap.
+ * performed on the raw inode simply pass @nop_mnt_idmap.
*/
int get_vfs_caps_from_disk(struct mnt_idmap *idmap,
const struct dentry *dentry,
@@ -1133,7 +1133,7 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags)
break;
case LSM_SETID_FS:
- /* juggle the capabilties to follow FSUID changes, unless
+ /* juggle the capabilities to follow FSUID changes, unless
* otherwise suppressed
*
* FIXME - is fsuser used for all CAP_FS_MASK capabilities?
@@ -1184,10 +1184,10 @@ static int cap_safe_nice(struct task_struct *p)
}
/**
- * cap_task_setscheduler - Detemine if scheduler policy change is permitted
+ * cap_task_setscheduler - Determine if scheduler policy change is permitted
* @p: The task to affect
*
- * Detemine if the requested scheduler policy change is permitted for the
+ * Determine if the requested scheduler policy change is permitted for the
* specified task.
*
* Return: 0 if permission is granted, -ve if denied.
@@ -1198,11 +1198,11 @@ int cap_task_setscheduler(struct task_struct *p)
}
/**
- * cap_task_setioprio - Detemine if I/O priority change is permitted
+ * cap_task_setioprio - Determine if I/O priority change is permitted
* @p: The task to affect
* @ioprio: The I/O priority to set
*
- * Detemine if the requested I/O priority change is permitted for the specified
+ * Determine if the requested I/O priority change is permitted for the specified
* task.
*
* Return: 0 if permission is granted, -ve if denied.
@@ -1213,11 +1213,11 @@ int cap_task_setioprio(struct task_struct *p, int ioprio)
}
/**
- * cap_task_setnice - Detemine if task priority change is permitted
+ * cap_task_setnice - Determine if task priority change is permitted
* @p: The task to affect
* @nice: The nice value to set
*
- * Detemine if the requested task priority change is permitted for the
+ * Determine if the requested task priority change is permitted for the
* specified task.
*
* Return: 0 if permission is granted, -ve if denied.
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index 7507d14eacc7..dc4df7475081 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -421,7 +421,7 @@ static bool verify_new_ex(struct dev_cgroup *dev_cgroup,
} else {
/*
* new exception in the child will add more devices
- * that can be acessed, so it can't match any of
+ * that can be accessed, so it can't match any of
* parent's exceptions, even slightly
*/
match = match_exception_partial(&dev_cgroup->exceptions,
@@ -822,7 +822,6 @@ struct cgroup_subsys devices_cgrp_subsys = {
/**
* devcgroup_legacy_check_permission - checks if an inode operation is permitted
- * @dev_cgroup: the dev cgroup to be tested against
* @type: device type
* @major: device major number
* @minor: device minor number
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 033804f5a5f2..0dae649f3740 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -40,7 +40,7 @@ static const char evm_hmac[] = "hmac(sha1)";
/**
* evm_set_key() - set EVM HMAC key from the kernel
* @key: pointer to a buffer with the key data
- * @size: length of the key data
+ * @keylen: length of the key data
*
* This function allows setting the EVM HMAC key from the kernel
* without using the "encrypted" key subsystem keys. It can be used
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index cf24c5255583..c9b6e2a43478 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -318,7 +318,6 @@ int evm_protected_xattr_if_enabled(const char *req_xattr_name)
/**
* evm_read_protected_xattrs - read EVM protected xattr names, lengths, values
* @dentry: dentry of the read xattrs
- * @inode: inode of the read xattrs
* @buffer: buffer xattr names, lengths or values are copied to
* @buffer_size: size of buffer
* @type: n: names, l: lengths, v: values
@@ -390,6 +389,7 @@ int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
* @xattr_name: requested xattr
* @xattr_value: requested xattr value
* @xattr_value_len: requested xattr value length
+ * @iint: inode integrity metadata
*
* Calculate the HMAC for the given dentry and verify it against the stored
* security.evm xattr. For performance, use the xattr value and length
@@ -795,7 +795,9 @@ static int evm_attr_change(struct mnt_idmap *idmap,
/**
* evm_inode_setattr - prevent updating an invalid EVM extended attribute
+ * @idmap: idmap of the mount
* @dentry: pointer to the affected dentry
+ * @attr: iattr structure containing the new file attributes
*
* Permit update of file attributes when files have a valid EVM signature,
* except in the case of them having an immutable portable signature.
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index c73858e8c6d5..a462df827de2 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -43,12 +43,10 @@ static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode)
else if (inode > iint->inode)
n = n->rb_right;
else
- break;
+ return iint;
}
- if (!n)
- return NULL;
- return iint;
+ return NULL;
}
/*
@@ -113,10 +111,15 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode)
parent = *p;
test_iint = rb_entry(parent, struct integrity_iint_cache,
rb_node);
- if (inode < test_iint->inode)
+ if (inode < test_iint->inode) {
p = &(*p)->rb_left;
- else
+ } else if (inode > test_iint->inode) {
p = &(*p)->rb_right;
+ } else {
+ write_unlock(&integrity_iint_lock);
+ kmem_cache_free(iint_cache, iint);
+ return test_iint;
+ }
}
iint->inode = inode;
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index d3662f4acadc..452e80b541e5 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -13,7 +13,6 @@
#include <linux/fs.h>
#include <linux/xattr.h>
#include <linux/evm.h>
-#include <linux/iversion.h>
#include <linux/fsverity.h>
#include "ima.h"
@@ -202,19 +201,19 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode,
allowed_algos);
}
-static int ima_get_verity_digest(struct integrity_iint_cache *iint,
- struct ima_max_digest_data *hash)
+static bool ima_get_verity_digest(struct integrity_iint_cache *iint,
+ struct ima_max_digest_data *hash)
{
- enum hash_algo verity_alg;
- int ret;
+ enum hash_algo alg;
+ int digest_len;
/*
* On failure, 'measure' policy rules will result in a file data
* hash containing 0's.
*/
- ret = fsverity_get_digest(iint->inode, hash->digest, &verity_alg);
- if (ret)
- return ret;
+ digest_len = fsverity_get_digest(iint->inode, hash->digest, NULL, &alg);
+ if (digest_len == 0)
+ return false;
/*
* Unlike in the case of actually calculating the file hash, in
@@ -223,9 +222,9 @@ static int ima_get_verity_digest(struct integrity_iint_cache *iint,
* mismatch between the verity algorithm and the xattr signature
* algorithm, if one exists, will be detected later.
*/
- hash->hdr.algo = verity_alg;
- hash->hdr.length = hash_digest_size[verity_alg];
- return 0;
+ hash->hdr.algo = alg;
+ hash->hdr.length = digest_len;
+ return true;
}
/*
@@ -246,10 +245,11 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
struct inode *inode = file_inode(file);
const char *filename = file->f_path.dentry->d_name.name;
struct ima_max_digest_data hash;
+ struct kstat stat;
int result = 0;
int length;
void *tmpbuf;
- u64 i_version;
+ u64 i_version = 0;
/*
* Always collect the modsig, because IMA might have already collected
@@ -268,7 +268,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
* to an initial measurement/appraisal/audit, but was modified to
* assume the file changed.
*/
- i_version = inode_query_iversion(inode);
+ result = vfs_getattr_nosec(&file->f_path, &stat, STATX_CHANGE_COOKIE,
+ AT_STATX_SYNC_AS_STAT);
+ if (!result && (stat.result_mask & STATX_CHANGE_COOKIE))
+ i_version = stat.change_cookie;
hash.hdr.algo = algo;
hash.hdr.length = hash_digest_size[algo];
@@ -276,16 +279,9 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
memset(&hash.digest, 0, sizeof(hash.digest));
if (iint->flags & IMA_VERITY_REQUIRED) {
- result = ima_get_verity_digest(iint, &hash);
- switch (result) {
- case 0:
- break;
- case -ENODATA:
+ if (!ima_get_verity_digest(iint, &hash)) {
audit_cause = "no-verity-digest";
- break;
- default:
- audit_cause = "invalid-verity-digest";
- break;
+ result = -ENODATA;
}
} else if (buf) {
result = ima_calc_buffer_hash(buf, size, &hash.hdr);
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index d66a0a36415e..365db0e43d7c 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -24,7 +24,6 @@
#include <linux/slab.h>
#include <linux/xattr.h>
#include <linux/ima.h>
-#include <linux/iversion.h>
#include <linux/fs.h>
#include "ima.h"
@@ -164,11 +163,16 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
mutex_lock(&iint->mutex);
if (atomic_read(&inode->i_writecount) == 1) {
+ struct kstat stat;
+
update = test_and_clear_bit(IMA_UPDATE_XATTR,
&iint->atomic_flags);
- if (!IS_I_VERSION(inode) ||
- !inode_eq_iversion(inode, iint->version) ||
- (iint->flags & IMA_NEW_FILE)) {
+ if ((iint->flags & IMA_NEW_FILE) ||
+ vfs_getattr_nosec(&file->f_path, &stat,
+ STATX_CHANGE_COOKIE,
+ AT_STATX_SYNC_AS_STAT) ||
+ !(stat.result_mask & STATX_CHANGE_COOKIE) ||
+ stat.change_cookie != iint->version) {
iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
iint->measured_pcrs = 0;
if (update)
diff --git a/security/integrity/ima/ima_modsig.c b/security/integrity/ima/ima_modsig.c
index fb25723c65bc..3e7bee30080f 100644
--- a/security/integrity/ima/ima_modsig.c
+++ b/security/integrity/ima/ima_modsig.c
@@ -89,6 +89,9 @@ int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
/**
* ima_collect_modsig - Calculate the file hash without the appended signature.
+ * @modsig: parsed module signature
+ * @buf: data to verify the signature on
+ * @size: data size
*
* Since the modsig is part of the file contents, the hash used in its signature
* isn't the same one ordinarily calculated by IMA. Therefore PKCS7 code
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 3ca8b7348c2e..c9b3bd8f1bb9 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -721,6 +721,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func)
* @secid: LSM secid of the task to be validated
* @func: IMA hook identifier
* @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC)
+ * @flags: IMA actions to consider (e.g. IMA_MEASURE | IMA_APPRAISE)
* @pcr: set the pcr to extend
* @template_desc: the template that should be used for this rule
* @func_data: func specific data, may be NULL
@@ -1915,7 +1916,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
/**
* ima_parse_add_rule - add a rule to ima_policy_rules
- * @rule - ima measurement policy rule
+ * @rule: ima measurement policy rule
*
* Avoid locking by allowing just one writer at a time in ima_write_policy()
* Returns the length of the rule parsed, an error code on failure
diff --git a/security/integrity/platform_certs/load_powerpc.c b/security/integrity/platform_certs/load_powerpc.c
index b9de70b90826..170789dc63d2 100644
--- a/security/integrity/platform_certs/load_powerpc.c
+++ b/security/integrity/platform_certs/load_powerpc.c
@@ -15,6 +15,9 @@
#include "keyring_handler.h"
#include "../integrity.h"
+#define extract_esl(db, data, size, offset) \
+ do { db = data + offset; size = size - offset; } while (0)
+
/*
* Get a certificate list blob from the named secure variable.
*
@@ -55,8 +58,9 @@ static __init void *get_cert_list(u8 *key, unsigned long keylen, u64 *size)
*/
static int __init load_powerpc_certs(void)
{
- void *db = NULL, *dbx = NULL;
- u64 dbsize = 0, dbxsize = 0;
+ void *db = NULL, *dbx = NULL, *data = NULL;
+ u64 dsize = 0;
+ u64 offset = 0;
int rc = 0;
ssize_t len;
char buf[32];
@@ -74,38 +78,46 @@ static int __init load_powerpc_certs(void)
return -ENODEV;
}
+ if (strcmp("ibm,plpks-sb-v1", buf) == 0)
+ /* PLPKS authenticated variables ESL data is prefixed with 8 bytes of timestamp */
+ offset = 8;
+
/*
* Get db, and dbx. They might not exist, so it isn't an error if we
* can't get them.
*/
- db = get_cert_list("db", 3, &dbsize);
- if (!db) {
+ data = get_cert_list("db", 3, &dsize);
+ if (!data) {
pr_info("Couldn't get db list from firmware\n");
- } else if (IS_ERR(db)) {
- rc = PTR_ERR(db);
+ } else if (IS_ERR(data)) {
+ rc = PTR_ERR(data);
pr_err("Error reading db from firmware: %d\n", rc);
return rc;
} else {
- rc = parse_efi_signature_list("powerpc:db", db, dbsize,
+ extract_esl(db, data, dsize, offset);
+
+ rc = parse_efi_signature_list("powerpc:db", db, dsize,
get_handler_for_db);
if (rc)
pr_err("Couldn't parse db signatures: %d\n", rc);
- kfree(db);
+ kfree(data);
}
- dbx = get_cert_list("dbx", 4, &dbxsize);
- if (!dbx) {
+ data = get_cert_list("dbx", 4, &dsize);
+ if (!data) {
pr_info("Couldn't get dbx list from firmware\n");
- } else if (IS_ERR(dbx)) {
- rc = PTR_ERR(dbx);
+ } else if (IS_ERR(data)) {
+ rc = PTR_ERR(data);
pr_err("Error reading dbx from firmware: %d\n", rc);
return rc;
} else {
- rc = parse_efi_signature_list("powerpc:dbx", dbx, dbxsize,
+ extract_esl(dbx, data, dsize, offset);
+
+ rc = parse_efi_signature_list("powerpc:dbx", dbx, dsize,
get_handler_for_dbx);
if (rc)
pr_err("Couldn't parse dbx signatures: %d\n", rc);
- kfree(dbx);
+ kfree(data);
}
return rc;
diff --git a/security/keys/sysctl.c b/security/keys/sysctl.c
index b46b651b3c4c..b72b82bb20c6 100644
--- a/security/keys/sysctl.c
+++ b/security/keys/sysctl.c
@@ -68,3 +68,10 @@ struct ctl_table key_sysctls[] = {
#endif
{ }
};
+
+static int __init init_security_keys_sysctls(void)
+{
+ register_sysctl_init("kernel/keys", key_sysctls);
+ return 0;
+}
+early_initcall(init_security_keys_sysctls);
diff --git a/security/landlock/Kconfig b/security/landlock/Kconfig
index 8e33c4e8ffb8..c1e862a38410 100644
--- a/security/landlock/Kconfig
+++ b/security/landlock/Kconfig
@@ -2,7 +2,7 @@
config SECURITY_LANDLOCK
bool "Landlock support"
- depends on SECURITY && !ARCH_EPHEMERAL_INODES
+ depends on SECURITY
select SECURITY_PATH
help
Landlock is a sandboxing mechanism that enables processes to restrict
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
index 368e77ca43c4..849e832719e2 100644
--- a/security/lsm_audit.c
+++ b/security/lsm_audit.c
@@ -200,7 +200,7 @@ static void dump_common_audit_data(struct audit_buffer *ab,
char comm[sizeof(current->comm)];
/*
- * To keep stack sizes in check force programers to notice if they
+ * To keep stack sizes in check force programmers to notice if they
* start making this union too large! See struct lsm_network_audit
* as an example of how to deal with large data.
*/
diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
index e806739f7868..5be5894aa0ea 100644
--- a/security/safesetid/lsm.c
+++ b/security/safesetid/lsm.c
@@ -131,7 +131,7 @@ static int safesetid_security_capable(const struct cred *cred,
* set*gid() (e.g. setting up userns gid mappings).
*/
pr_warn("Operation requires CAP_SETGID, which is not available to GID %u for operations besides approved set*gid transitions\n",
- __kuid_val(cred->uid));
+ __kgid_val(cred->gid));
return -EPERM;
default:
/* Error, the only capabilities were checking for is CAP_SETUID/GID */
diff --git a/security/security.c b/security/security.c
index d5ff7ff45b77..b720424ca37d 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2491,7 +2491,7 @@ int security_inode_copy_up_xattr(const char *name)
/*
* The implementation can return 0 (accept the xattr), 1 (discard the
* xattr), -EOPNOTSUPP if it does not know anything about the xattr or
- * any other error code incase of an error.
+ * any other error code in case of an error.
*/
hlist_for_each_entry(hp,
&security_hook_heads.inode_copy_up_xattr, list) {
@@ -4667,6 +4667,23 @@ int security_sctp_assoc_established(struct sctp_association *asoc,
}
EXPORT_SYMBOL(security_sctp_assoc_established);
+/**
+ * security_mptcp_add_subflow() - Inherit the LSM label from the MPTCP socket
+ * @sk: the owning MPTCP socket
+ * @ssk: the new subflow
+ *
+ * Update the labeling for the given MPTCP subflow, to match the one of the
+ * owning MPTCP socket. This hook has to be called after the socket creation and
+ * initialization via the security_socket_create() and
+ * security_socket_post_create() LSM hooks.
+ *
+ * Return: Returns 0 on success or a negative error code on failure.
+ */
+int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
+{
+ return call_int_hook(mptcp_add_subflow, 0, sk, ssk);
+}
+
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_INFINIBAND
@@ -4676,7 +4693,7 @@ EXPORT_SYMBOL(security_sctp_assoc_established);
* @subnet_prefix: subnet prefix of the port
* @pkey: IB pkey
*
- * Check permission to access a pkey when modifing a QP.
+ * Check permission to access a pkey when modifying a QP.
*
* Return: Returns 0 if permission is granted.
*/
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index 8b21520bd4b9..836379639058 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -3,32 +3,38 @@
# Makefile for building the SELinux module as part of the kernel tree.
#
+# NOTE: There are a number of improvements that can be made to this Makefile
+# once the kernel requires make v4.3 or greater; the most important feature
+# lacking in older versions of make is support for grouped targets. These
+# improvements are noted inline in the Makefile below ...
+
obj-$(CONFIG_SECURITY_SELINUX) := selinux.o
+ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
+
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
netnode.o netport.o status.o \
ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/context.o
selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
-
selinux-$(CONFIG_NETLABEL) += netlabel.o
-
selinux-$(CONFIG_SECURITY_INFINIBAND) += ibpkey.o
-
selinux-$(CONFIG_IMA) += ima.o
-ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
+genhdrs := flask.h av_permissions.h
+# see the note above, replace the dependency rule with the one below:
+# $(addprefix $(obj)/,$(selinux-y)): $(addprefix $(obj)/,$(genhdrs))
$(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h
-quiet_cmd_flask = GEN $(obj)/flask.h $(obj)/av_permissions.h
- cmd_flask = $< $(obj)/flask.h $(obj)/av_permissions.h
+quiet_cmd_genhdrs = GEN $(addprefix $(obj)/,$(genhdrs))
+ cmd_genhdrs = $< $(addprefix $(obj)/,$(genhdrs))
-targets += flask.h av_permissions.h
-# once make >= 4.3 is required, we can use grouped targets in the rule below,
-# which basically involves adding both headers and a '&' before the colon, see
-# the example below:
-# $(obj)/flask.h $(obj)/av_permissions.h &: scripts/selinux/...
+# see the note above, replace the $targets and 'flask.h' rule with the lines
+# below:
+# targets += $(genhdrs)
+# $(addprefix $(obj)/,$(genhdrs)) &: scripts/selinux/...
+targets += flask.h
$(obj)/flask.h: scripts/selinux/genheaders/genheaders FORCE
- $(call if_changed,flask)
+ $(call if_changed,genhdrs)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index eaed5c2da02b..1074db66e5ff 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -642,7 +642,6 @@ static void avc_insert(u32 ssid, u32 tsid, u16 tclass,
hlist_add_head_rcu(&node->list, head);
found:
spin_unlock_irqrestore(lock, flag);
- return;
}
/**
@@ -1203,22 +1202,3 @@ u32 avc_policy_seqno(void)
{
return selinux_avc.avc_cache.latest_notif;
}
-
-void avc_disable(void)
-{
- /*
- * If you are looking at this because you have realized that we are
- * not destroying the avc_node_cachep it might be easy to fix, but
- * I don't know the memory barrier semantics well enough to know. It's
- * possible that some other task dereferenced security_ops when
- * it still pointed to selinux operations. If that is the case it's
- * possible that it is about to use the avc and is about to need the
- * avc_node_cachep. I know I could wrap the security.c security_ops call
- * in an rcu_lock, but seriously, it's not worth it. Instead I just flush
- * the cache and get that memory back.
- */
- if (avc_node_cachep) {
- avc_flush();
- /* kmem_cache_destroy(avc_node_cachep); */
- }
-}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 79b4890e9936..d06e350fedee 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -357,7 +357,7 @@ enum {
};
#define A(s, has_arg) {#s, sizeof(#s) - 1, Opt_##s, has_arg}
-static struct {
+static const struct {
const char *name;
int len;
int opt;
@@ -605,6 +605,13 @@ static int selinux_set_mnt_opts(struct super_block *sb,
u32 defcontext_sid = 0;
int rc = 0;
+ /*
+ * Specifying internal flags without providing a place to
+ * place the results is not allowed
+ */
+ if (kern_flags && !set_kern_flags)
+ return -EINVAL;
+
mutex_lock(&sbsec->lock);
if (!selinux_initialized()) {
@@ -612,6 +619,10 @@ static int selinux_set_mnt_opts(struct super_block *sb,
/* Defer initialization until selinux_complete_init,
after the initial policy is loaded and the security
server is ready to handle calls. */
+ if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
+ sbsec->flags |= SE_SBNATIVE;
+ *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
+ }
goto out;
}
rc = -EINVAL;
@@ -619,12 +630,6 @@ static int selinux_set_mnt_opts(struct super_block *sb,
"before the security server is initialized\n");
goto out;
}
- if (kern_flags && !set_kern_flags) {
- /* Specifying internal flags without providing a place to
- * place the results is not allowed */
- rc = -EINVAL;
- goto out;
- }
/*
* Binary mount data FS will come through this function twice. Once
@@ -757,7 +762,17 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* sets the label used on all file below the mountpoint, and will set
* the superblock context if not already set.
*/
- if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
+ if (sbsec->flags & SE_SBNATIVE) {
+ /*
+ * This means we are initializing a superblock that has been
+ * mounted before the SELinux was initialized and the
+ * filesystem requested native labeling. We had already
+ * returned SECURITY_LSM_NATIVE_LABELS in *set_kern_flags
+ * in the original mount attempt, so now we just need to set
+ * the SECURITY_FS_USE_NATIVE behavior.
+ */
+ sbsec->behavior = SECURITY_FS_USE_NATIVE;
+ } else if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
sbsec->behavior = SECURITY_FS_USE_NATIVE;
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
}
@@ -869,31 +884,37 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
/*
- * if the parent was able to be mounted it clearly had no special lsm
- * mount options. thus we can safely deal with this superblock later
- */
- if (!selinux_initialized())
- return 0;
-
- /*
* Specifying internal flags without providing a place to
* place the results is not allowed.
*/
if (kern_flags && !set_kern_flags)
return -EINVAL;
+ mutex_lock(&newsbsec->lock);
+
+ /*
+ * if the parent was able to be mounted it clearly had no special lsm
+ * mount options. thus we can safely deal with this superblock later
+ */
+ if (!selinux_initialized()) {
+ if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
+ newsbsec->flags |= SE_SBNATIVE;
+ *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
+ }
+ goto out;
+ }
+
/* how can we clone if the old one wasn't set up?? */
BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
/* if fs is reusing a sb, make sure that the contexts match */
if (newsbsec->flags & SE_SBINITIALIZED) {
+ mutex_unlock(&newsbsec->lock);
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);
-
newsbsec->flags = oldsbsec->flags;
newsbsec->sid = oldsbsec->sid;
@@ -937,7 +958,7 @@ out:
}
/*
- * NOTE: the caller is resposible for freeing the memory even if on error.
+ * NOTE: the caller is responsible for freeing the memory even if on error.
*/
static int selinux_add_opt(int token, const char *s, void **mnt_opts)
{
@@ -1394,8 +1415,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
spin_unlock(&isec->lock);
switch (sbsec->behavior) {
+ /*
+ * In case of SECURITY_FS_USE_NATIVE we need to re-fetch the labels
+ * via xattr when called from delayed_superblock_init().
+ */
case SECURITY_FS_USE_NATIVE:
- break;
case SECURITY_FS_USE_XATTR:
if (!(inode->i_opflags & IOP_XATTR)) {
sid = sbsec->def_sid;
@@ -5379,6 +5403,21 @@ static void selinux_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk
selinux_netlbl_sctp_sk_clone(sk, newsk);
}
+static int selinux_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
+{
+ struct sk_security_struct *ssksec = ssk->sk_security;
+ struct sk_security_struct *sksec = sk->sk_security;
+
+ ssksec->sclass = sksec->sclass;
+ ssksec->sid = sksec->sid;
+
+ /* replace the existing subflow label deleting the existing one
+ * and re-recreating a new label using the updated context
+ */
+ selinux_netlbl_sk_security_free(ssksec);
+ return selinux_netlbl_socket_post_create(ssk, ssk->sk_family);
+}
+
static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
struct request_sock *req)
{
@@ -7074,6 +7113,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone),
LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect),
LSM_HOOK_INIT(sctp_assoc_established, selinux_sctp_assoc_established),
+ LSM_HOOK_INIT(mptcp_add_subflow, selinux_mptcp_add_subflow),
LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established),
diff --git a/security/selinux/ima.c b/security/selinux/ima.c
index 7daf59667f59..aa34da9b0aeb 100644
--- a/security/selinux/ima.c
+++ b/security/selinux/ima.c
@@ -4,7 +4,7 @@
*
* Author: Lakshmi Ramasubramanian (nramas@linux.microsoft.com)
*
- * Measure critical data structures maintainted by SELinux
+ * Measure critical data structures maintained by SELinux
* using IMA subsystem.
*/
#include <linux/vmalloc.h>
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
index 406bceb90c6c..d5495134a5b9 100644
--- a/security/selinux/include/audit.h
+++ b/security/selinux/include/audit.h
@@ -41,7 +41,7 @@ void selinux_audit_rule_free(void *rule);
* selinux_audit_rule_match - determine if a context ID matches a rule.
* @sid: the context ID to check
* @field: the field this rule refers to
- * @op: the operater the rule uses
+ * @op: the operator the rule uses
* @rule: pointer to the audit rule to check against
*
* Returns 1 if the context id matches the rule, 0 if it does not, and
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 9301222c8e55..9e055f74daf6 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -168,9 +168,6 @@ int avc_get_hash_stats(char *page);
unsigned int avc_get_cache_threshold(void);
void avc_set_cache_threshold(unsigned int cache_threshold);
-/* Attempt to free avc node cache */
-void avc_disable(void);
-
#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats);
#endif
diff --git a/security/selinux/include/ibpkey.h b/security/selinux/include/ibpkey.h
index c992f83b0aae..875b055849e1 100644
--- a/security/selinux/include/ibpkey.h
+++ b/security/selinux/include/ibpkey.h
@@ -15,6 +15,7 @@
#define _SELINUX_IB_PKEY_H
#include <linux/types.h>
+#include "flask.h"
#ifdef CONFIG_SECURITY_INFINIBAND
void sel_ib_pkey_flush(void);
diff --git a/security/selinux/include/ima.h b/security/selinux/include/ima.h
index 05e04172c86d..93c05e97eb7f 100644
--- a/security/selinux/include/ima.h
+++ b/security/selinux/include/ima.h
@@ -4,7 +4,7 @@
*
* Author: Lakshmi Ramasubramanian (nramas@linux.microsoft.com)
*
- * Measure critical data structures maintainted by SELinux
+ * Measure critical data structures maintained by SELinux
* using IMA subsystem.
*/
diff --git a/security/selinux/include/initial_sid_to_string.h b/security/selinux/include/initial_sid_to_string.h
index 60820517aa43..ecc6e74fa09b 100644
--- a/security/selinux/include/initial_sid_to_string.h
+++ b/security/selinux/include/initial_sid_to_string.h
@@ -1,4 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/stddef.h>
+
static const char *const initial_sid_to_string[] = {
NULL,
"kernel",
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 8746fafeb778..3b605f39e040 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -65,6 +65,7 @@
#define SE_SBPROC 0x0200
#define SE_SBGENFS 0x0400
#define SE_SBGENFS_XATTR 0x0800
+#define SE_SBNATIVE 0x1000
#define CONTEXT_STR "context"
#define FSCONTEXT_STR "fscontext"
@@ -384,7 +385,6 @@ struct selinux_kernel_status {
extern void selinux_status_update_setenforce(int enforcing);
extern void selinux_status_update_policyload(int seqno);
extern void selinux_complete_init(void);
-extern void exit_sel_fs(void);
extern struct path selinux_null;
extern void selnl_notify_setenforce(int val);
extern void selnl_notify_policyload(u32 seqno);
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 767c670d33ea..528f5186e912 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -154,8 +154,12 @@ void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway)
*/
void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec)
{
- if (sksec->nlbl_secattr != NULL)
- netlbl_secattr_free(sksec->nlbl_secattr);
+ if (!sksec->nlbl_secattr)
+ return;
+
+ netlbl_secattr_free(sksec->nlbl_secattr);
+ sksec->nlbl_secattr = NULL;
+ sksec->nlbl_state = NLBL_UNSET;
}
/**
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 69a583b91fc5..bad1f6b685fd 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -951,7 +951,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
* either whitespace or multibyte characters, they shall be
* encoded based on the percentage-encoding rule.
* If not encoded, the sscanf logic picks up only left-half
- * of the supplied name; splitted by a whitespace unexpectedly.
+ * of the supplied name; split by a whitespace unexpectedly.
*/
char *r, *w;
int c1, c2;
@@ -1649,7 +1649,7 @@ static int sel_make_ss_files(struct dentry *dir)
struct super_block *sb = dir->d_sb;
struct selinux_fs_info *fsi = sb->s_fs_info;
int i;
- static struct tree_descr files[] = {
+ static const struct tree_descr files[] = {
{ "sidtab_hash_stats", &sel_sidtab_hash_stats_ops, S_IRUGO },
};
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index 8480ec6c6e75..6766edc0fe68 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -354,7 +354,7 @@ int avtab_alloc_dup(struct avtab *new, const struct avtab *orig)
return avtab_alloc_common(new, orig->nslot);
}
-void avtab_hash_eval(struct avtab *h, char *tag)
+void avtab_hash_eval(struct avtab *h, const char *tag)
{
int i, chain_len, slots_used, max_chain_len;
unsigned long long chain2_len_sum;
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
index d3ebea8d146f..d6742fd9c560 100644
--- a/security/selinux/ss/avtab.h
+++ b/security/selinux/ss/avtab.h
@@ -92,7 +92,7 @@ int avtab_alloc(struct avtab *, u32);
int avtab_alloc_dup(struct avtab *new, const struct avtab *orig);
struct avtab_datum *avtab_search(struct avtab *h, const struct avtab_key *k);
void avtab_destroy(struct avtab *h);
-void avtab_hash_eval(struct avtab *h, char *tag);
+void avtab_hash_eval(struct avtab *h, const char *tag);
struct policydb;
int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index e11219fdf9f7..b156c181c3c1 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -38,7 +38,7 @@ static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
if (sp == (COND_EXPR_MAXDEPTH - 1))
return -1;
sp++;
- s[sp] = p->bool_val_to_struct[node->bool - 1]->state;
+ s[sp] = p->bool_val_to_struct[node->boolean - 1]->state;
break;
case COND_NOT:
if (sp < 0)
@@ -366,7 +366,7 @@ static int expr_node_isvalid(struct policydb *p, struct cond_expr_node *expr)
return 0;
}
- if (expr->bool > p->p_bools.nprim) {
+ if (expr->boolean > p->p_bools.nprim) {
pr_err("SELinux: conditional expressions uses unknown bool.\n");
return 0;
}
@@ -401,7 +401,7 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
return rc;
expr->expr_type = le32_to_cpu(buf[0]);
- expr->bool = le32_to_cpu(buf[1]);
+ expr->boolean = le32_to_cpu(buf[1]);
if (!expr_node_isvalid(p, expr))
return -EINVAL;
@@ -518,7 +518,7 @@ static int cond_write_node(struct policydb *p, struct cond_node *node,
for (i = 0; i < node->expr.len; i++) {
buf[0] = cpu_to_le32(node->expr.nodes[i].expr_type);
- buf[1] = cpu_to_le32(node->expr.nodes[i].bool);
+ buf[1] = cpu_to_le32(node->expr.nodes[i].boolean);
rc = put_entry(buf, sizeof(u32), 2, fp);
if (rc)
return rc;
diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h
index e47ec6ddeaf6..5a7b51278dc6 100644
--- a/security/selinux/ss/conditional.h
+++ b/security/selinux/ss/conditional.h
@@ -29,7 +29,7 @@ struct cond_expr_node {
#define COND_NEQ 7 /* bool != bool */
#define COND_LAST COND_NEQ
u32 expr_type;
- u32 bool;
+ u32 boolean;
};
struct cond_expr {
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h
index eda32c3d4c0a..aed704b8c642 100644
--- a/security/selinux/ss/context.h
+++ b/security/selinux/ss/context.h
@@ -167,6 +167,8 @@ static inline int context_cpy(struct context *dst, const struct context *src)
rc = mls_context_cpy(dst, src);
if (rc) {
kfree(dst->str);
+ dst->str = NULL;
+ dst->len = 0;
return rc;
}
return 0;
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index adcfb63b3550..31b08b34c722 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -42,7 +42,7 @@
#include "services.h"
#ifdef DEBUG_HASHES
-static const char *symtab_name[SYM_NUM] = {
+static const char *const symtab_name[SYM_NUM] = {
"common prefixes",
"classes",
"roles",
@@ -2257,6 +2257,10 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info *
if (rc)
goto out;
+ if (i == OCON_FS)
+ pr_warn("SELinux: void and deprecated fs ocon %s\n",
+ c->u.name);
+
rc = context_read_and_validate(&c->context[0], p, fp);
if (rc)
goto out;
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index ffc4e7bad205..74b63ed1173f 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -225,7 +225,7 @@ struct genfs {
/* object context array indices */
#define OCON_ISID 0 /* initial SIDs */
-#define OCON_FS 1 /* unlabeled file systems */
+#define OCON_FS 1 /* unlabeled file systems (deprecated) */
#define OCON_PORT 2 /* TCP and UDP port numbers */
#define OCON_NETIF 3 /* network interfaces */
#define OCON_NODE 4 /* nodes */
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index f14d1ffe54c5..78946b71c1c1 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -583,7 +583,7 @@ static void type_attribute_bounds_av(struct policydb *policydb,
/*
* flag which drivers have permissions
- * only looking for ioctl based extended permssions
+ * only looking for ioctl based extended permissions
*/
void services_compute_xperms_drivers(
struct extended_perms *xperms,
@@ -3541,38 +3541,38 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
if (!tmprule)
return -ENOMEM;
-
context_init(&tmprule->au_ctxt);
rcu_read_lock();
policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
-
tmprule->au_seqno = policy->latest_granting;
-
switch (field) {
case AUDIT_SUBJ_USER:
case AUDIT_OBJ_USER:
- rc = -EINVAL;
userdatum = symtab_search(&policydb->p_users, rulestr);
- if (!userdatum)
- goto out;
+ if (!userdatum) {
+ rc = -EINVAL;
+ goto err;
+ }
tmprule->au_ctxt.user = userdatum->value;
break;
case AUDIT_SUBJ_ROLE:
case AUDIT_OBJ_ROLE:
- rc = -EINVAL;
roledatum = symtab_search(&policydb->p_roles, rulestr);
- if (!roledatum)
- goto out;
+ if (!roledatum) {
+ rc = -EINVAL;
+ goto err;
+ }
tmprule->au_ctxt.role = roledatum->value;
break;
case AUDIT_SUBJ_TYPE:
case AUDIT_OBJ_TYPE:
- rc = -EINVAL;
typedatum = symtab_search(&policydb->p_types, rulestr);
- if (!typedatum)
- goto out;
+ if (!typedatum) {
+ rc = -EINVAL;
+ goto err;
+ }
tmprule->au_ctxt.type = typedatum->value;
break;
case AUDIT_SUBJ_SEN:
@@ -3582,20 +3582,18 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt,
GFP_ATOMIC);
if (rc)
- goto out;
+ goto err;
break;
}
- rc = 0;
-out:
rcu_read_unlock();
- if (rc) {
- selinux_audit_rule_free(tmprule);
- tmprule = NULL;
- }
-
*rule = tmprule;
+ return 0;
+err:
+ rcu_read_unlock();
+ selinux_audit_rule_free(tmprule);
+ *rule = NULL;
return rc;
}
diff --git a/security/smack/smack.h b/security/smack/smack.h
index e2239be7bd60..aa15ff56ed6e 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -120,6 +120,7 @@ struct inode_smack {
struct task_smack {
struct smack_known *smk_task; /* label for access control */
struct smack_known *smk_forked; /* label when forked */
+ struct smack_known *smk_transmuted;/* label when transmuted */
struct list_head smk_rules; /* per task access rules */
struct mutex smk_rules_lock; /* lock for the rules */
struct list_head smk_relabel; /* transit allowed labels */
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 7a3e9ab137d8..6e270cf3fd30 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -933,8 +933,9 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, const char **name,
void **value, size_t *len)
{
+ struct task_smack *tsp = smack_cred(current_cred());
struct inode_smack *issp = smack_inode(inode);
- struct smack_known *skp = smk_of_current();
+ struct smack_known *skp = smk_of_task(tsp);
struct smack_known *isp = smk_of_inode(inode);
struct smack_known *dsp = smk_of_inode(dir);
int may;
@@ -943,20 +944,34 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
*name = XATTR_SMACK_SUFFIX;
if (value && len) {
- rcu_read_lock();
- may = smk_access_entry(skp->smk_known, dsp->smk_known,
- &skp->smk_rules);
- rcu_read_unlock();
+ /*
+ * If equal, transmuting already occurred in
+ * smack_dentry_create_files_as(). No need to check again.
+ */
+ if (tsp->smk_task != tsp->smk_transmuted) {
+ rcu_read_lock();
+ may = smk_access_entry(skp->smk_known, dsp->smk_known,
+ &skp->smk_rules);
+ rcu_read_unlock();
+ }
/*
- * If the access rule allows transmutation and
- * the directory requests transmutation then
- * by all means transmute.
+ * In addition to having smk_task equal to smk_transmuted,
+ * if the access rule allows transmutation and the directory
+ * requests transmutation then by all means transmute.
* Mark the inode as changed.
*/
- if (may > 0 && ((may & MAY_TRANSMUTE) != 0) &&
- smk_inode_transmutable(dir)) {
- isp = dsp;
+ if ((tsp->smk_task == tsp->smk_transmuted) ||
+ (may > 0 && ((may & MAY_TRANSMUTE) != 0) &&
+ smk_inode_transmutable(dir))) {
+ /*
+ * The caller of smack_dentry_create_files_as()
+ * should have overridden the current cred, so the
+ * inode label was already set correctly in
+ * smack_inode_alloc_security().
+ */
+ if (tsp->smk_task != tsp->smk_transmuted)
+ isp = dsp;
issp->smk_flags |= SMK_INODE_CHANGED;
}
@@ -1463,10 +1478,19 @@ static int smack_inode_getsecurity(struct mnt_idmap *idmap,
struct super_block *sbp;
struct inode *ip = inode;
struct smack_known *isp;
+ struct inode_smack *ispp;
+ size_t label_len;
+ char *label = NULL;
- if (strcmp(name, XATTR_SMACK_SUFFIX) == 0)
+ if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
isp = smk_of_inode(inode);
- else {
+ } else if (strcmp(name, XATTR_SMACK_TRANSMUTE) == 0) {
+ ispp = smack_inode(inode);
+ if (ispp->smk_flags & SMK_INODE_TRANSMUTE)
+ label = TRANS_TRUE;
+ else
+ label = "";
+ } else {
/*
* The rest of the Smack xattrs are only on sockets.
*/
@@ -1488,13 +1512,18 @@ static int smack_inode_getsecurity(struct mnt_idmap *idmap,
return -EOPNOTSUPP;
}
+ if (!label)
+ label = isp->smk_known;
+
+ label_len = strlen(label);
+
if (alloc) {
- *buffer = kstrdup(isp->smk_known, GFP_KERNEL);
+ *buffer = kstrdup(label, GFP_KERNEL);
if (*buffer == NULL)
return -ENOMEM;
}
- return strlen(isp->smk_known);
+ return label_len;
}
@@ -4753,8 +4782,10 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
* providing access is transmuting use the containing
* directory label instead of the process label.
*/
- if (may > 0 && (may & MAY_TRANSMUTE))
+ if (may > 0 && (may & MAY_TRANSMUTE)) {
ntsp->smk_task = isp->smk_inode;
+ ntsp->smk_transmuted = ntsp->smk_task;
+ }
}
return 0;
}
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index 31af29f669d2..ac20c0bdff9d 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -916,7 +916,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
*/
mmap_read_lock(bprm->mm);
ret = get_user_pages_remote(bprm->mm, pos, 1,
- FOLL_FORCE, &page, NULL, NULL);
+ FOLL_FORCE, &page, NULL);
mmap_read_unlock(bprm->mm);
if (ret <= 0)
return false;