Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/torvalds/linux.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/Kconfig11
-rw-r--r--security/integrity/evm/evm_crypto.c7
-rw-r--r--security/integrity/evm/evm_main.c12
-rw-r--r--security/integrity/ima/ima_appraise.c3
-rw-r--r--security/integrity/ima/ima_crypto.c1
-rw-r--r--security/integrity/ima/ima_efi.c2
-rw-r--r--security/integrity/ima/ima_kexec.c2
-rw-r--r--security/integrity/ima/ima_policy.c4
-rw-r--r--security/integrity/ima/ima_template_lib.c6
-rw-r--r--security/loadpin/Kconfig16
-rw-r--r--security/loadpin/loadpin.c167
-rw-r--r--security/security.c5
-rw-r--r--security/selinux/hooks.c17
-rw-r--r--security/selinux/include/audit.h2
-rw-r--r--security/selinux/include/avc.h2
-rw-r--r--security/selinux/ss/policydb.h2
-rw-r--r--security/selinux/ss/services.c9
-rw-r--r--security/smack/smack_access.c7
-rw-r--r--security/smack/smack_lsm.c7
19 files changed, 228 insertions, 54 deletions
diff --git a/security/Kconfig b/security/Kconfig
index f29e4c656983..e6db09a779b7 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -54,17 +54,6 @@ config SECURITY_NETWORK
implement socket and networking access controls.
If you are unsure how to answer this question, answer N.
-config PAGE_TABLE_ISOLATION
- bool "Remove the kernel mapping in user mode"
- default y
- depends on (X86_64 || X86_PAE) && !UML
- help
- This feature reduces the number of hardware side channels by
- ensuring that the majority of kernel addresses are not mapped
- into userspace.
-
- See Documentation/x86/pti.rst for more details.
-
config SECURITY_INFINIBAND
bool "Infiniband Security Hooks"
depends on SECURITY && INFINIBAND
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index a733aff02006..708de9656bbd 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -75,7 +75,7 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo)
{
long rc;
const char *algo;
- struct crypto_shash **tfm, *tmp_tfm = NULL;
+ struct crypto_shash **tfm, *tmp_tfm;
struct shash_desc *desc;
if (type == EVM_XATTR_HMAC) {
@@ -120,16 +120,13 @@ unlock:
alloc:
desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(*tfm),
GFP_KERNEL);
- if (!desc) {
- crypto_free_shash(tmp_tfm);
+ if (!desc)
return ERR_PTR(-ENOMEM);
- }
desc->tfm = *tfm;
rc = crypto_shash_init(desc);
if (rc) {
- crypto_free_shash(tmp_tfm);
kfree(desc);
return ERR_PTR(rc);
}
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index cc88f02c7562..93e8bc047a73 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -755,13 +755,14 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
}
-static int evm_attr_change(struct dentry *dentry, struct iattr *attr)
+static int evm_attr_change(struct user_namespace *mnt_userns,
+ struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = d_backing_inode(dentry);
unsigned int ia_valid = attr->ia_valid;
- if ((!(ia_valid & ATTR_UID) || uid_eq(attr->ia_uid, inode->i_uid)) &&
- (!(ia_valid & ATTR_GID) || gid_eq(attr->ia_gid, inode->i_gid)) &&
+ if (!i_uid_needs_update(mnt_userns, attr, inode) &&
+ !i_gid_needs_update(mnt_userns, attr, inode) &&
(!(ia_valid & ATTR_MODE) || attr->ia_mode == inode->i_mode))
return 0;
@@ -775,7 +776,8 @@ static int evm_attr_change(struct dentry *dentry, struct iattr *attr)
* Permit update of file attributes when files have a valid EVM signature,
* except in the case of them having an immutable portable signature.
*/
-int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
+int evm_inode_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
+ struct iattr *attr)
{
unsigned int ia_valid = attr->ia_valid;
enum integrity_status evm_status;
@@ -801,7 +803,7 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
return 0;
if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
- !evm_attr_change(dentry, attr))
+ !evm_attr_change(mnt_userns, dentry, attr))
return 0;
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index cdb84dccd24e..bde74fcecee3 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -514,7 +514,8 @@ int ima_appraise_measurement(enum ima_hooks func,
goto out;
}
- status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint);
+ status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value,
+ rc < 0 ? 0 : rc, iint);
switch (status) {
case INTEGRITY_PASS:
case INTEGRITY_PASS_IMMUTABLE:
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index a7206cc1d7d1..64499056648a 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -205,6 +205,7 @@ out_array:
crypto_free_shash(ima_algo_array[i].tfm);
}
+ kfree(ima_algo_array);
out:
crypto_free_shash(ima_shash_tfm);
return rc;
diff --git a/security/integrity/ima/ima_efi.c b/security/integrity/ima/ima_efi.c
index 71786d01946f..9db66fe310d4 100644
--- a/security/integrity/ima/ima_efi.c
+++ b/security/integrity/ima/ima_efi.c
@@ -67,6 +67,8 @@ const char * const *arch_get_ima_policy(void)
if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_ima_get_secureboot()) {
if (IS_ENABLED(CONFIG_MODULE_SIG))
set_module_sig_enforced();
+ if (IS_ENABLED(CONFIG_KEXEC_SIG))
+ set_kexec_sig_enforced();
return sb_arch_rules;
}
return NULL;
diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
index 13753136f03f..419dc405c831 100644
--- a/security/integrity/ima/ima_kexec.c
+++ b/security/integrity/ima/ima_kexec.c
@@ -137,7 +137,7 @@ void ima_add_kexec_buffer(struct kimage *image)
/*
* Restore the measurement list from the previous kernel.
*/
-void ima_load_kexec_buffer(void)
+void __init ima_load_kexec_buffer(void)
{
void *kexec_buffer = NULL;
size_t kexec_buffer_size = 0;
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 73917413365b..a8802b8da946 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -2247,6 +2247,10 @@ bool ima_appraise_signature(enum kernel_read_file_id id)
if (id >= READING_MAX_ID)
return false;
+ if (id == READING_KEXEC_IMAGE && !(ima_appraise & IMA_APPRAISE_ENFORCE)
+ && security_locked_down(LOCKDOWN_KEXEC))
+ return false;
+
func = read_idmap[id] ?: FILE_CHECK;
rcu_read_lock();
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index c877f01a5471..7bf9b1507220 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -323,10 +323,10 @@ static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
else
/*
* If digest is NULL, the event being recorded is a violation.
- * Make room for the digest by increasing the offset of
- * IMA_DIGEST_SIZE.
+ * Make room for the digest by increasing the offset by the
+ * hash algorithm digest size.
*/
- offset += IMA_DIGEST_SIZE;
+ offset += hash_digest_size[hash_algo];
return ima_write_template_field_data(buffer, offset + digestsize,
fmt, field_data);
diff --git a/security/loadpin/Kconfig b/security/loadpin/Kconfig
index 91be65dec2ab..70e7985b2561 100644
--- a/security/loadpin/Kconfig
+++ b/security/loadpin/Kconfig
@@ -18,3 +18,19 @@ config SECURITY_LOADPIN_ENFORCE
If selected, LoadPin will enforce pinning at boot. If not
selected, it can be enabled at boot with the kernel parameter
"loadpin.enforce=1".
+
+config SECURITY_LOADPIN_VERITY
+ bool "Allow reading files from certain other filesystems that use dm-verity"
+ depends on SECURITY_LOADPIN && DM_VERITY=y && SECURITYFS
+ help
+ If selected LoadPin can allow reading files from filesystems
+ that use dm-verity. LoadPin maintains a list of verity root
+ digests it considers trusted. A verity backed filesystem is
+ considered trusted if its root digest is found in the list
+ of trusted digests.
+
+ The list of trusted verity can be populated through an ioctl
+ on the LoadPin securityfs entry 'dm-verity'. The ioctl
+ expects a file descriptor of a file with verity digests as
+ parameter. The file must be located on the pinned root and
+ contain a comma separated list of digests.
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index ad4e6756c038..6ab5f2bbf41f 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -18,6 +18,8 @@
#include <linux/path.h>
#include <linux/sched.h> /* current */
#include <linux/string_helpers.h>
+#include <linux/dm-verity-loadpin.h>
+#include <uapi/linux/loadpin.h>
static void report_load(const char *origin, struct file *file, char *operation)
{
@@ -43,6 +45,9 @@ static char *exclude_read_files[READING_MAX_ID];
static int ignore_read_file_id[READING_MAX_ID] __ro_after_init;
static struct super_block *pinned_root;
static DEFINE_SPINLOCK(pinned_root_spinlock);
+#ifdef CONFIG_SECURITY_LOADPIN_VERITY
+static bool deny_reading_verity_digests;
+#endif
#ifdef CONFIG_SYSCTL
@@ -171,7 +176,8 @@ static int loadpin_read_file(struct file *file, enum kernel_read_file_id id,
spin_unlock(&pinned_root_spinlock);
}
- if (IS_ERR_OR_NULL(pinned_root) || load_root != pinned_root) {
+ if (IS_ERR_OR_NULL(pinned_root) ||
+ ((load_root != pinned_root) && !dm_verity_loadpin_is_bdev_trusted(load_root->s_bdev))) {
if (unlikely(!enforce)) {
report_load(origin, file, "pinning-ignored");
return 0;
@@ -237,6 +243,7 @@ static int __init loadpin_init(void)
enforce ? "" : "not ");
parse_exclude();
security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
+
return 0;
}
@@ -245,6 +252,164 @@ DEFINE_LSM(loadpin) = {
.init = loadpin_init,
};
+#ifdef CONFIG_SECURITY_LOADPIN_VERITY
+
+enum loadpin_securityfs_interface_index {
+ LOADPIN_DM_VERITY,
+};
+
+static int read_trusted_verity_root_digests(unsigned int fd)
+{
+ struct fd f;
+ void *data;
+ int rc;
+ char *p, *d;
+
+ if (deny_reading_verity_digests)
+ return -EPERM;
+
+ /* The list of trusted root digests can only be set up once */
+ if (!list_empty(&dm_verity_loadpin_trusted_root_digests))
+ return -EPERM;
+
+ f = fdget(fd);
+ if (!f.file)
+ return -EINVAL;
+
+ data = kzalloc(SZ_4K, GFP_KERNEL);
+ if (!data) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ rc = kernel_read_file(f.file, 0, (void **)&data, SZ_4K - 1, NULL, READING_POLICY);
+ if (rc < 0)
+ goto err;
+
+ p = data;
+ p[rc] = '\0';
+ p = strim(p);
+
+ p = strim(data);
+ while ((d = strsep(&p, "\n")) != NULL) {
+ int len = strlen(d);
+ struct dm_verity_loadpin_trusted_root_digest *trd;
+
+ if (len % 2) {
+ rc = -EPROTO;
+ goto err;
+ }
+
+ len /= 2;
+
+ trd = kzalloc(struct_size(trd, data, len), GFP_KERNEL);
+ if (!trd) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ if (hex2bin(trd->data, d, len)) {
+ kfree(trd);
+ rc = -EPROTO;
+ goto err;
+ }
+
+ trd->len = len;
+
+ list_add_tail(&trd->node, &dm_verity_loadpin_trusted_root_digests);
+ }
+
+ if (list_empty(&dm_verity_loadpin_trusted_root_digests)) {
+ rc = -EPROTO;
+ goto err;
+ }
+
+ kfree(data);
+ fdput(f);
+
+ return 0;
+
+err:
+ kfree(data);
+
+ /* any failure in loading/parsing invalidates the entire list */
+ {
+ struct dm_verity_loadpin_trusted_root_digest *trd, *tmp;
+
+ list_for_each_entry_safe(trd, tmp, &dm_verity_loadpin_trusted_root_digests, node) {
+ list_del(&trd->node);
+ kfree(trd);
+ }
+ }
+
+ /* disallow further attempts after reading a corrupt/invalid file */
+ deny_reading_verity_digests = true;
+
+ fdput(f);
+
+ return rc;
+}
+
+/******************************** securityfs ********************************/
+
+static long dm_verity_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ void __user *uarg = (void __user *)arg;
+ unsigned int fd;
+ int rc;
+
+ switch (cmd) {
+ case LOADPIN_IOC_SET_TRUSTED_VERITY_DIGESTS:
+ rc = copy_from_user(&fd, uarg, sizeof(fd));
+ if (rc)
+ return rc;
+
+ return read_trusted_verity_root_digests(fd);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct file_operations loadpin_dm_verity_ops = {
+ .unlocked_ioctl = dm_verity_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
+};
+
+/**
+ * init_loadpin_securityfs - create the securityfs directory for LoadPin
+ *
+ * We can not put this method normally under the loadpin_init() code path since
+ * the security subsystem gets initialized before the vfs caches.
+ *
+ * Returns 0 if the securityfs directory creation was successful.
+ */
+static int __init init_loadpin_securityfs(void)
+{
+ struct dentry *loadpin_dir, *dentry;
+
+ loadpin_dir = securityfs_create_dir("loadpin", NULL);
+ if (IS_ERR(loadpin_dir)) {
+ pr_err("LoadPin: could not create securityfs dir: %ld\n",
+ PTR_ERR(loadpin_dir));
+ return PTR_ERR(loadpin_dir);
+ }
+
+ dentry = securityfs_create_file("dm-verity", 0600, loadpin_dir,
+ (void *)LOADPIN_DM_VERITY, &loadpin_dm_verity_ops);
+ if (IS_ERR(dentry)) {
+ pr_err("LoadPin: could not create securityfs entry 'dm-verity': %ld\n",
+ PTR_ERR(dentry));
+ return PTR_ERR(dentry);
+ }
+
+ return 0;
+}
+
+fs_initcall(init_loadpin_securityfs);
+
+#endif /* CONFIG_SECURITY_LOADPIN_VERITY */
+
/* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
module_param(enforce, int, 0);
MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
diff --git a/security/security.c b/security/security.c
index 15c686145ad6..14d30fec8a00 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1324,7 +1324,8 @@ int security_inode_permission(struct inode *inode, int mask)
return call_int_hook(inode_permission, 0, inode, mask);
}
-int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
+int security_inode_setattr(struct user_namespace *mnt_userns,
+ struct dentry *dentry, struct iattr *attr)
{
int ret;
@@ -1333,7 +1334,7 @@ int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
ret = call_int_hook(inode_setattr, 0, dentry, attr);
if (ret)
return ret;
- return evm_inode_setattr(dentry, attr);
+ return evm_inode_setattr(mnt_userns, dentry, attr);
}
EXPORT_SYMBOL_GPL(security_inode_setattr);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1bbd53321d13..79573504783b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -640,7 +640,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* we need to skip the double mount verification.
*
* This does open a hole in which we will not notice if the first
- * mount using this sb set explict options and a second mount using
+ * mount using this sb set explicit options and a second mount using
* this sb does not set any security options. (The first options
* will be used for both mounts)
*/
@@ -944,10 +944,12 @@ out:
return rc;
}
+/*
+ * NOTE: the caller is resposible for freeing the memory even if on error.
+ */
static int selinux_add_opt(int token, const char *s, void **mnt_opts)
{
struct selinux_mnt_opts *opts = *mnt_opts;
- bool is_alloc_opts = false;
u32 *dst_sid;
int rc;
@@ -955,7 +957,7 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
/* eaten and completely ignored */
return 0;
if (!s)
- return -ENOMEM;
+ return -EINVAL;
if (!selinux_initialized(&selinux_state)) {
pr_warn("SELinux: Unable to set superblock options before the security server is initialized\n");
@@ -967,7 +969,6 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
if (!opts)
return -ENOMEM;
*mnt_opts = opts;
- is_alloc_opts = true;
}
switch (token) {
@@ -1002,10 +1003,6 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
return rc;
err:
- if (is_alloc_opts) {
- kfree(opts);
- *mnt_opts = NULL;
- }
pr_warn(SEL_MOUNT_FAIL_MSG);
return -EINVAL;
}
@@ -1019,7 +1016,7 @@ static int show_sid(struct seq_file *m, u32 sid)
rc = security_sid_to_context(&selinux_state, sid,
&context, &len);
if (!rc) {
- bool has_comma = context && strchr(context, ',');
+ bool has_comma = strchr(context, ',');
seq_putc(m, '=');
if (has_comma)
@@ -6792,7 +6789,7 @@ static u32 bpf_map_fmode_to_av(fmode_t fmode)
}
/* This function will check the file pass through unix socket or binder to see
- * if it is a bpf related object. And apply correspinding checks on the bpf
+ * if it is a bpf related object. And apply corresponding checks on the bpf
* object based on the type. The bpf maps and programs, not like other files and
* socket, are using a shared anonymous inode inside the kernel as their inode.
* So checking that inode cannot identify if the process have privilege to
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
index 1cba83d17f41..406bceb90c6c 100644
--- a/security/selinux/include/audit.h
+++ b/security/selinux/include/audit.h
@@ -18,7 +18,7 @@
/**
* selinux_audit_rule_init - alloc/init an selinux audit rule structure.
* @field: the field this rule refers to
- * @op: the operater the rule uses
+ * @op: the operator the rule uses
* @rulestr: the text "target" of the rule
* @rule: pointer to the new rule structure returned via this
*
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 2b372f98f2d7..5525b94fd266 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -53,7 +53,7 @@ struct selinux_audit_data {
u32 denied;
int result;
struct selinux_state *state;
-};
+} __randomize_layout;
/*
* AVC operations
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index c24d4e1063ea..ffc4e7bad205 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -370,6 +370,8 @@ static inline int put_entry(const void *buf, size_t bytes, int num, struct polic
{
size_t len = bytes * num;
+ if (len > fp->len)
+ return -EINVAL;
memcpy(fp->data, buf, len);
fp->data += len;
fp->len -= len;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 69b2734311a6..fe5fcf571c56 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -4048,6 +4048,7 @@ int security_read_policy(struct selinux_state *state,
int security_read_state_kernel(struct selinux_state *state,
void **data, size_t *len)
{
+ int err;
struct selinux_policy *policy;
policy = rcu_dereference_protected(
@@ -4060,5 +4061,11 @@ int security_read_state_kernel(struct selinux_state *state,
if (!*data)
return -ENOMEM;
- return __security_read_policy(policy, *data, len);
+ err = __security_read_policy(policy, *data, len);
+ if (err) {
+ vfree(*data);
+ *data = NULL;
+ *len = 0;
+ }
+ return err;
}
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index d2186e2757be..585e5e35710b 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -465,12 +465,9 @@ char *smk_parse_smack(const char *string, int len)
if (i == 0 || i >= SMK_LONGLABEL)
return ERR_PTR(-EINVAL);
- smack = kzalloc(i + 1, GFP_NOFS);
- if (smack == NULL)
+ smack = kstrndup(string, i, GFP_NOFS);
+ if (!smack)
return ERR_PTR(-ENOMEM);
-
- strncpy(smack, string, i);
-
return smack;
}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 6207762dbdb1..001831458fa2 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -766,13 +766,6 @@ static int smack_set_mnt_opts(struct super_block *sb,
if (sp->smk_flags & SMK_SB_INITIALIZED)
return 0;
- if (inode->i_security == NULL) {
- int rc = lsm_inode_alloc(inode);
-
- if (rc)
- return rc;
- }
-
if (!smack_privileged(CAP_MAC_ADMIN)) {
/*
* Unprivileged mounts don't get to specify Smack values.