summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/crypto.c32
-rw-r--r--security/apparmor/include/lib.h2
-rw-r--r--security/apparmor/lib.c4
-rw-r--r--security/apparmor/lsm.c51
-rw-r--r--security/apparmor/policy.c6
-rw-r--r--security/integrity/digsig.c9
-rw-r--r--security/integrity/ima/ima_mok.c11
-rw-r--r--security/keys/Kconfig2
-rw-r--r--security/keys/Makefile3
-rw-r--r--security/keys/compat.c9
-rw-r--r--security/keys/compat_dh.c38
-rw-r--r--security/keys/dh.c220
-rw-r--r--security/keys/gc.c13
-rw-r--r--security/keys/internal.h32
-rw-r--r--security/keys/key.c58
-rw-r--r--security/keys/keyctl.c60
-rw-r--r--security/keys/keyring.c187
-rw-r--r--security/keys/proc.c4
-rw-r--r--security/keys/process_keys.c2
-rw-r--r--security/keys/request_key_auth.c2
-rw-r--r--security/selinux/hooks.c8
-rw-r--r--security/selinux/nlmsgtab.c10
-rw-r--r--security/selinux/selinuxfs.c8
-rw-r--r--security/selinux/ss/conditional.c14
-rw-r--r--security/selinux/ss/hashtab.c10
-rw-r--r--security/selinux/ss/policydb.c59
-rw-r--r--security/selinux/ss/services.c2
-rw-r--r--security/selinux/ss/sidtab.c6
-rw-r--r--security/tomoyo/file.c12
-rw-r--r--security/tomoyo/tomoyo.c20
30 files changed, 702 insertions, 192 deletions
diff --git a/security/apparmor/crypto.c b/security/apparmor/crypto.c
index de8dc78b61442..136f2a0478367 100644
--- a/security/apparmor/crypto.c
+++ b/security/apparmor/crypto.c
@@ -31,10 +31,7 @@ unsigned int aa_hash_size(void)
char *aa_calc_hash(void *data, size_t len)
{
- struct {
- struct shash_desc shash;
- char ctx[crypto_shash_descsize(apparmor_tfm)];
- } desc;
+ SHASH_DESC_ON_STACK(desc, apparmor_tfm);
char *hash = NULL;
int error = -ENOMEM;
@@ -45,16 +42,16 @@ char *aa_calc_hash(void *data, size_t len)
if (!hash)
goto fail;
- desc.shash.tfm = apparmor_tfm;
- desc.shash.flags = 0;
+ desc->tfm = apparmor_tfm;
+ desc->flags = 0;
- error = crypto_shash_init(&desc.shash);
+ error = crypto_shash_init(desc);
if (error)
goto fail;
- error = crypto_shash_update(&desc.shash, (u8 *) data, len);
+ error = crypto_shash_update(desc, (u8 *) data, len);
if (error)
goto fail;
- error = crypto_shash_final(&desc.shash, hash);
+ error = crypto_shash_final(desc, hash);
if (error)
goto fail;
@@ -69,10 +66,7 @@ fail:
int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
size_t len)
{
- struct {
- struct shash_desc shash;
- char ctx[crypto_shash_descsize(apparmor_tfm)];
- } desc;
+ SHASH_DESC_ON_STACK(desc, apparmor_tfm);
int error = -ENOMEM;
__le32 le32_version = cpu_to_le32(version);
@@ -86,19 +80,19 @@ int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start,
if (!profile->hash)
goto fail;
- desc.shash.tfm = apparmor_tfm;
- desc.shash.flags = 0;
+ desc->tfm = apparmor_tfm;
+ desc->flags = 0;
- error = crypto_shash_init(&desc.shash);
+ error = crypto_shash_init(desc);
if (error)
goto fail;
- error = crypto_shash_update(&desc.shash, (u8 *) &le32_version, 4);
+ error = crypto_shash_update(desc, (u8 *) &le32_version, 4);
if (error)
goto fail;
- error = crypto_shash_update(&desc.shash, (u8 *) start, len);
+ error = crypto_shash_update(desc, (u8 *) start, len);
if (error)
goto fail;
- error = crypto_shash_final(&desc.shash, profile->hash);
+ error = crypto_shash_final(desc, profile->hash);
if (error)
goto fail;
diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h
index 65ff492a98079..0291ff3902f90 100644
--- a/security/apparmor/include/lib.h
+++ b/security/apparmor/include/lib.h
@@ -57,7 +57,7 @@
pr_err_ratelimited("AppArmor: " fmt, ##args)
/* Flag indicating whether initialization completed */
-extern int apparmor_initialized __initdata;
+extern int apparmor_initialized;
/* fn's in lib */
char *aa_split_fqname(char *args, char **ns_name);
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
index 66475bda6f722..32cafc12593ef 100644
--- a/security/apparmor/lib.c
+++ b/security/apparmor/lib.c
@@ -180,13 +180,13 @@ bool aa_policy_init(struct aa_policy *policy, const char *prefix,
} else
policy->hname = kstrdup(name, gfp);
if (!policy->hname)
- return 0;
+ return false;
/* base.name is a substring of fqname */
policy->name = basename(policy->hname);
INIT_LIST_HEAD(&policy->list);
INIT_LIST_HEAD(&policy->profiles);
- return 1;
+ return true;
}
/**
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index e287b691a30e4..8f3c0f7aca5a2 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -39,7 +39,7 @@
#include "include/procattr.h"
/* Flag indicating whether initialization completed */
-int apparmor_initialized __initdata;
+int apparmor_initialized;
DEFINE_PER_CPU(struct aa_buffers, aa_buffers);
@@ -681,7 +681,7 @@ module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR);
#endif
/* Debug mode */
-bool aa_g_debug = IS_ENABLED(CONFIG_SECURITY_DEBUG_MESSAGES);
+bool aa_g_debug = IS_ENABLED(CONFIG_SECURITY_APPARMOR_DEBUG_MESSAGES);
module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR);
/* Audit mode */
@@ -710,7 +710,7 @@ module_param_named(logsyscall, aa_g_logsyscall, aabool, S_IRUSR | S_IWUSR);
/* Maximum pathname length before accesses will start getting rejected */
unsigned int aa_g_path_max = 2 * PATH_MAX;
-module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR | S_IWUSR);
+module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR);
/* Determines how paranoid loading of policy is and how much verification
* on the loaded policy is done.
@@ -738,78 +738,77 @@ __setup("apparmor=", apparmor_enabled_setup);
/* set global flag turning off the ability to load policy */
static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp)
{
- if (!policy_admin_capable(NULL))
+ if (!apparmor_enabled)
+ return -EINVAL;
+ if (apparmor_initialized && !policy_admin_capable(NULL))
return -EPERM;
return param_set_bool(val, kp);
}
static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp)
{
- if (!policy_view_capable(NULL))
- return -EPERM;
if (!apparmor_enabled)
return -EINVAL;
+ if (apparmor_initialized && !policy_view_capable(NULL))
+ return -EPERM;
return param_get_bool(buffer, kp);
}
static int param_set_aabool(const char *val, const struct kernel_param *kp)
{
- if (!policy_admin_capable(NULL))
- return -EPERM;
if (!apparmor_enabled)
return -EINVAL;
+ if (apparmor_initialized && !policy_admin_capable(NULL))
+ return -EPERM;
return param_set_bool(val, kp);
}
static int param_get_aabool(char *buffer, const struct kernel_param *kp)
{
- if (!policy_view_capable(NULL))
- return -EPERM;
if (!apparmor_enabled)
return -EINVAL;
+ if (apparmor_initialized && !policy_view_capable(NULL))
+ return -EPERM;
return param_get_bool(buffer, kp);
}
static int param_set_aauint(const char *val, const struct kernel_param *kp)
{
- if (!policy_admin_capable(NULL))
- return -EPERM;
if (!apparmor_enabled)
return -EINVAL;
+ if (apparmor_initialized && !policy_admin_capable(NULL))
+ return -EPERM;
return param_set_uint(val, kp);
}
static int param_get_aauint(char *buffer, const struct kernel_param *kp)
{
- if (!policy_view_capable(NULL))
- return -EPERM;
if (!apparmor_enabled)
return -EINVAL;
+ if (apparmor_initialized && !policy_view_capable(NULL))
+ return -EPERM;
return param_get_uint(buffer, kp);
}
static int param_get_audit(char *buffer, struct kernel_param *kp)
{
- if (!policy_view_capable(NULL))
- return -EPERM;
-
if (!apparmor_enabled)
return -EINVAL;
-
+ if (apparmor_initialized && !policy_view_capable(NULL))
+ return -EPERM;
return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]);
}
static int param_set_audit(const char *val, struct kernel_param *kp)
{
int i;
- if (!policy_admin_capable(NULL))
- return -EPERM;
if (!apparmor_enabled)
return -EINVAL;
-
if (!val)
return -EINVAL;
+ if (apparmor_initialized && !policy_admin_capable(NULL))
+ return -EPERM;
for (i = 0; i < AUDIT_MAX_INDEX; i++) {
if (strcmp(val, audit_mode_names[i]) == 0) {
@@ -823,11 +822,10 @@ static int param_set_audit(const char *val, struct kernel_param *kp)
static int param_get_mode(char *buffer, struct kernel_param *kp)
{
- if (!policy_view_capable(NULL))
- return -EPERM;
-
if (!apparmor_enabled)
return -EINVAL;
+ if (apparmor_initialized && !policy_view_capable(NULL))
+ return -EPERM;
return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]);
}
@@ -835,14 +833,13 @@ static int param_get_mode(char *buffer, struct kernel_param *kp)
static int param_set_mode(const char *val, struct kernel_param *kp)
{
int i;
- if (!policy_admin_capable(NULL))
- return -EPERM;
if (!apparmor_enabled)
return -EINVAL;
-
if (!val)
return -EINVAL;
+ if (apparmor_initialized && !policy_admin_capable(NULL))
+ return -EPERM;
for (i = 0; i < APPARMOR_MODE_NAMES_MAX_INDEX; i++) {
if (strcmp(val, aa_profile_mode_names[i]) == 0) {
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index def1fbd6bdfd8..cf9d670dca945 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -876,9 +876,11 @@ ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile,
if (ns_name) {
ns = aa_prepare_ns(view, ns_name);
if (IS_ERR(ns)) {
+ op = OP_PROF_LOAD;
info = "failed to prepare namespace";
error = PTR_ERR(ns);
ns = NULL;
+ ent = NULL;
goto fail;
}
} else
@@ -1013,7 +1015,7 @@ fail_lock:
/* audit cause of failure */
op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
fail:
- audit_policy(profile, op, ns_name, ent->new->base.hname,
+ audit_policy(profile, op, ns_name, ent ? ent->new->base.hname : NULL,
info, error);
/* audit status that rest of profiles in the atomic set failed too */
info = "valid profile in failed atomic policy load";
@@ -1023,7 +1025,7 @@ fail:
/* skip entry that caused failure */
continue;
}
- op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
+ op = (!tmp->old) ? OP_PROF_LOAD : OP_PROF_REPL;
audit_policy(profile, op, ns_name,
tmp->new->base.hname, info, error);
}
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 106e855e2d9d1..06554c448dce8 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -81,18 +81,25 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
int __init integrity_init_keyring(const unsigned int id)
{
const struct cred *cred = current_cred();
+ struct key_restriction *restriction;
int err = 0;
if (!init_keyring)
return 0;
+ restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
+ if (!restriction)
+ return -ENOMEM;
+
+ restriction->check = restrict_link_to_ima;
+
keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
KGIDT_INIT(0), cred,
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH),
KEY_ALLOC_NOT_IN_QUOTA,
- restrict_link_to_ima, NULL);
+ restriction, NULL);
if (IS_ERR(keyring[id])) {
err = PTR_ERR(keyring[id]);
pr_info("Can't allocate %s keyring (%d)\n",
diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
index 74a2799574642..073ddc9bce5ba 100644
--- a/security/integrity/ima/ima_mok.c
+++ b/security/integrity/ima/ima_mok.c
@@ -17,6 +17,7 @@
#include <linux/cred.h>
#include <linux/err.h>
#include <linux/init.h>
+#include <linux/slab.h>
#include <keys/system_keyring.h>
@@ -27,15 +28,23 @@ struct key *ima_blacklist_keyring;
*/
__init int ima_mok_init(void)
{
+ struct key_restriction *restriction;
+
pr_notice("Allocating IMA blacklist keyring.\n");
+ restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
+ if (!restriction)
+ panic("Can't allocate IMA blacklist restriction.");
+
+ restriction->check = restrict_link_by_builtin_trusted;
+
ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH,
KEY_ALLOC_NOT_IN_QUOTA,
- restrict_link_by_builtin_trusted, NULL);
+ restriction, NULL);
if (IS_ERR(ima_blacklist_keyring))
panic("Can't allocate IMA blacklist keyring.");
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index d942c7c2bc0aa..6fd95f76bfaea 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -90,6 +90,8 @@ config KEY_DH_OPERATIONS
bool "Diffie-Hellman operations on retained keys"
depends on KEYS
select MPILIB
+ select CRYPTO
+ select CRYPTO_HASH
help
This option provides support for calculating Diffie-Hellman
public keys and shared secrets using values stored as keys
diff --git a/security/keys/Makefile b/security/keys/Makefile
index 1fd4a16e6dafb..57dff0c158090 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -15,7 +15,8 @@ obj-y := \
request_key.o \
request_key_auth.o \
user_defined.o
-obj-$(CONFIG_KEYS_COMPAT) += compat.o
+compat-obj-$(CONFIG_KEY_DH_OPERATIONS) += compat_dh.o
+obj-$(CONFIG_KEYS_COMPAT) += compat.o $(compat-obj-y)
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSCTL) += sysctl.o
obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o
diff --git a/security/keys/compat.c b/security/keys/compat.c
index 36c80bf5b89c6..e87c89c0177c1 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -133,8 +133,13 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
return keyctl_get_persistent(arg2, arg3);
case KEYCTL_DH_COMPUTE:
- return keyctl_dh_compute(compat_ptr(arg2), compat_ptr(arg3),
- arg4, compat_ptr(arg5));
+ return compat_keyctl_dh_compute(compat_ptr(arg2),
+ compat_ptr(arg3),
+ arg4, compat_ptr(arg5));
+
+ case KEYCTL_RESTRICT_KEYRING:
+ return keyctl_restrict_keyring(arg2, compat_ptr(arg3),
+ compat_ptr(arg4));
default:
return -EOPNOTSUPP;
diff --git a/security/keys/compat_dh.c b/security/keys/compat_dh.c
new file mode 100644
index 0000000000000..a6a659b6bcb6d
--- /dev/null
+++ b/security/keys/compat_dh.c
@@ -0,0 +1,38 @@
+/* 32-bit compatibility syscall for 64-bit systems for DH operations
+ *
+ * Copyright (C) 2016 Stephan Mueller <smueller@chronox.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/uaccess.h>
+
+#include "internal.h"
+
+/*
+ * Perform the DH computation or DH based key derivation.
+ *
+ * If successful, 0 will be returned.
+ */
+long compat_keyctl_dh_compute(struct keyctl_dh_params __user *params,
+ char __user *buffer, size_t buflen,
+ struct compat_keyctl_kdf_params __user *kdf)
+{
+ struct keyctl_kdf_params kdfcopy;
+ struct compat_keyctl_kdf_params compat_kdfcopy;
+
+ if (!kdf)
+ return __keyctl_dh_compute(params, buffer, buflen, NULL);
+
+ if (copy_from_user(&compat_kdfcopy, kdf, sizeof(compat_kdfcopy)) != 0)
+ return -EFAULT;
+
+ kdfcopy.hashname = compat_ptr(compat_kdfcopy.hashname);
+ kdfcopy.otherinfo = compat_ptr(compat_kdfcopy.otherinfo);
+ kdfcopy.otherinfolen = compat_kdfcopy.otherinfolen;
+
+ return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy);
+}
diff --git a/security/keys/dh.c b/security/keys/dh.c
index 893af4c450382..e603bd912e4c2 100644
--- a/security/keys/dh.c
+++ b/security/keys/dh.c
@@ -11,6 +11,8 @@
#include <linux/mpi.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
+#include <linux/crypto.h>
+#include <crypto/hash.h>
#include <keys/user-type.h>
#include "internal.h"
@@ -77,9 +79,146 @@ error:
return ret;
}
-long keyctl_dh_compute(struct keyctl_dh_params __user *params,
- char __user *buffer, size_t buflen,
- void __user *reserved)
+struct kdf_sdesc {
+ struct shash_desc shash;
+ char ctx[];
+};
+
+static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname)
+{
+ struct crypto_shash *tfm;
+ struct kdf_sdesc *sdesc;
+ int size;
+
+ /* allocate synchronous hash */
+ tfm = crypto_alloc_shash(hashname, 0, 0);
+ if (IS_ERR(tfm)) {
+ pr_info("could not allocate digest TFM handle %s\n", hashname);
+ return PTR_ERR(tfm);
+ }
+
+ size = sizeof(struct shash_desc) + crypto_shash_descsize(tfm);
+ sdesc = kmalloc(size, GFP_KERNEL);
+ if (!sdesc)
+ return -ENOMEM;
+ sdesc->shash.tfm = tfm;
+ sdesc->shash.flags = 0x0;
+
+ *sdesc_ret = sdesc;
+
+ return 0;
+}
+
+static void kdf_dealloc(struct kdf_sdesc *sdesc)
+{
+ if (!sdesc)
+ return;
+
+ if (sdesc->shash.tfm)
+ crypto_free_shash(sdesc->shash.tfm);
+
+ kzfree(sdesc);
+}
+
+/* convert 32 bit integer into its string representation */
+static inline void crypto_kw_cpu_to_be32(u32 val, u8 *buf)
+{
+ __be32 *a = (__be32 *)buf;
+
+ *a = cpu_to_be32(val);
+}
+
+/*
+ * Implementation of the KDF in counter mode according to SP800-108 section 5.1
+ * as well as SP800-56A section 5.8.1 (Single-step KDF).
+ *
+ * SP800-56A:
+ * The src pointer is defined as Z || other info where Z is the shared secret
+ * from DH and other info is an arbitrary string (see SP800-56A section
+ * 5.8.1.2).
+ */
+static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int dlen)
+{
+ struct shash_desc *desc = &sdesc->shash;
+ unsigned int h = crypto_shash_digestsize(desc->tfm);
+ int err = 0;
+ u8 *dst_orig = dst;
+ u32 i = 1;
+ u8 iteration[sizeof(u32)];
+
+ while (dlen) {
+ err = crypto_shash_init(desc);
+ if (err)
+ goto err;
+
+ crypto_kw_cpu_to_be32(i, iteration);
+ err = crypto_shash_update(desc, iteration, sizeof(u32));
+ if (err)
+ goto err;
+
+ if (src && slen) {
+ err = crypto_shash_update(desc, src, slen);
+ if (err)
+ goto err;
+ }
+
+ if (dlen < h) {
+ u8 tmpbuffer[h];
+
+ err = crypto_shash_final(desc, tmpbuffer);
+ if (err)
+ goto err;
+ memcpy(dst, tmpbuffer, dlen);
+ memzero_explicit(tmpbuffer, h);
+ return 0;
+ } else {
+ err = crypto_shash_final(desc, dst);
+ if (err)
+ goto err;
+
+ dlen -= h;
+ dst += h;
+ i++;
+ }
+ }
+
+ return 0;
+
+err:
+ memzero_explicit(dst_orig, dlen);
+ return err;
+}
+
+static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc,
+ char __user *buffer, size_t buflen,
+ uint8_t *kbuf, size_t kbuflen)
+{
+ uint8_t *outbuf = NULL;
+ int ret;
+
+ outbuf = kmalloc(buflen, GFP_KERNEL);
+ if (!outbuf) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, buflen);
+ if (ret)
+ goto err;
+
+ ret = buflen;
+ if (copy_to_user(buffer, outbuf, buflen) != 0)
+ ret = -EFAULT;
+
+err:
+ kzfree(outbuf);
+ return ret;
+}
+
+long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
+ char __user *buffer, size_t buflen,
+ struct keyctl_kdf_params *kdfcopy)
{
long ret;
MPI base, private, prime, result;
@@ -88,6 +227,7 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
uint8_t *kbuf;
ssize_t keylen;
size_t resultlen;
+ struct kdf_sdesc *sdesc = NULL;
if (!params || (!buffer && buflen)) {
ret = -EINVAL;
@@ -98,12 +238,34 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
goto out;
}
- if (reserved) {
- ret = -EINVAL;
- goto out;
+ if (kdfcopy) {
+ char *hashname;
+
+ if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN ||
+ kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) {
+ ret = -EMSGSIZE;
+ goto out;
+ }
+
+ /* get KDF name string */
+ hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME);
+ if (IS_ERR(hashname)) {
+ ret = PTR_ERR(hashname);
+ goto out;
+ }
+
+ /* allocate KDF from the kernel crypto API */
+ ret = kdf_alloc(&sdesc, hashname);
+ kfree(hashname);
+ if (ret)
+ goto out;
}
- keylen = mpi_from_key(pcopy.prime, buflen, &prime);
+ /*
+ * If the caller requests postprocessing with a KDF, allow an
+ * arbitrary output buffer size since the KDF ensures proper truncation.
+ */
+ keylen = mpi_from_key(pcopy.prime, kdfcopy ? SIZE_MAX : buflen, &prime);
if (keylen < 0 || !prime) {
/* buflen == 0 may be used to query the required buffer size,
* which is the prime key length.
@@ -133,12 +295,25 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
goto error3;
}
- kbuf = kmalloc(resultlen, GFP_KERNEL);
+ /* allocate space for DH shared secret and SP800-56A otherinfo */
+ kbuf = kmalloc(kdfcopy ? (resultlen + kdfcopy->otherinfolen) : resultlen,
+ GFP_KERNEL);
if (!kbuf) {
ret = -ENOMEM;
goto error4;
}
+ /*
+ * Concatenate SP800-56A otherinfo past DH shared secret -- the
+ * input to the KDF is (DH shared secret || otherinfo)
+ */
+ if (kdfcopy && kdfcopy->otherinfo &&
+ copy_from_user(kbuf + resultlen, kdfcopy->otherinfo,
+ kdfcopy->otherinfolen) != 0) {
+ ret = -EFAULT;
+ goto error5;
+ }
+
ret = do_dh(result, base, private, prime);
if (ret)
goto error5;
@@ -147,12 +322,17 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
if (ret != 0)
goto error5;
- ret = nbytes;
- if (copy_to_user(buffer, kbuf, nbytes) != 0)
- ret = -EFAULT;
+ if (kdfcopy) {
+ ret = keyctl_dh_compute_kdf(sdesc, buffer, buflen, kbuf,
+ resultlen + kdfcopy->otherinfolen);
+ } else {
+ ret = nbytes;
+ if (copy_to_user(buffer, kbuf, nbytes) != 0)
+ ret = -EFAULT;
+ }
error5:
- kfree(kbuf);
+ kzfree(kbuf);
error4:
mpi_free(result);
error3:
@@ -162,5 +342,21 @@ error2:
error1:
mpi_free(prime);
out:
+ kdf_dealloc(sdesc);
return ret;
}
+
+long keyctl_dh_compute(struct keyctl_dh_params __user *params,
+ char __user *buffer, size_t buflen,
+ struct keyctl_kdf_params __user *kdf)
+{
+ struct keyctl_kdf_params kdfcopy;
+
+ if (!kdf)
+ return __keyctl_dh_compute(params, buffer, buflen, NULL);
+
+ if (copy_from_user(&kdfcopy, kdf, sizeof(kdfcopy)) != 0)
+ return -EFAULT;
+
+ return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy);
+}
diff --git a/security/keys/gc.c b/security/keys/gc.c
index addf060399e09..15b9ddf510e4e 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -220,7 +220,7 @@ continue_scanning:
key = rb_entry(cursor, struct key, serial_node);
cursor = rb_next(cursor);
- if (atomic_read(&key->usage) == 0)
+ if (refcount_read(&key->usage) == 0)
goto found_unreferenced_key;
if (unlikely(gc_state & KEY_GC_REAPING_DEAD_1)) {
@@ -229,6 +229,9 @@ continue_scanning:
set_bit(KEY_FLAG_DEAD, &key->flags);
key->perm = 0;
goto skip_dead_key;
+ } else if (key->type == &key_type_keyring &&
+ key->restrict_link) {
+ goto found_restricted_keyring;
}
}
@@ -334,6 +337,14 @@ found_unreferenced_key:
gc_state |= KEY_GC_REAP_AGAIN;
goto maybe_resched;
+ /* We found a restricted keyring and need to update the restriction if
+ * it is associated with the dead key type.
+ */
+found_restricted_keyring:
+ spin_unlock(&key_serial_lock);
+ keyring_restriction_gc(key, key_gc_dead_keytype);
+ goto maybe_resched;
+
/* We found a keyring and we need to check the payload for links to
* dead or expired keys. We don't flag another reap immediately as we
* have to wait for the old payload to be destroyed by RCU before we
diff --git a/security/keys/internal.h b/security/keys/internal.h
index a2f4c0abb8d84..c0f8682eba69a 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -17,6 +17,8 @@
#include <linux/key-type.h>
#include <linux/task_work.h>
#include <linux/keyctl.h>
+#include <linux/refcount.h>
+#include <linux/compat.h>
struct iovec;
@@ -53,7 +55,7 @@ struct key_user {
struct rb_node node;
struct mutex cons_lock; /* construction initiation lock */
spinlock_t lock;
- atomic_t usage; /* for accessing qnkeys & qnbytes */
+ refcount_t usage; /* for accessing qnkeys & qnbytes */
atomic_t nkeys; /* number of keys */
atomic_t nikeys; /* number of instantiated keys */
kuid_t uid;
@@ -167,6 +169,8 @@ extern void key_change_session_keyring(struct callback_head *twork);
extern struct work_struct key_gc_work;
extern unsigned key_gc_delay;
extern void keyring_gc(struct key *keyring, time_t limit);
+extern void keyring_restriction_gc(struct key *keyring,
+ struct key_type *dead_type);
extern void key_schedule_gc(time_t gc_at);
extern void key_schedule_gc_links(void);
extern void key_gc_keytype(struct key_type *ktype);
@@ -249,6 +253,9 @@ struct iov_iter;
extern long keyctl_instantiate_key_common(key_serial_t,
struct iov_iter *,
key_serial_t);
+extern long keyctl_restrict_keyring(key_serial_t id,
+ const char __user *_type,
+ const char __user *_restriction);
#ifdef CONFIG_PERSISTENT_KEYRINGS
extern long keyctl_get_persistent(uid_t, key_serial_t);
extern unsigned persistent_keyring_expiry;
@@ -261,15 +268,34 @@ static inline long keyctl_get_persistent(uid_t uid, key_serial_t destring)
#ifdef CONFIG_KEY_DH_OPERATIONS
extern long keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *,
- size_t, void __user *);
+ size_t, struct keyctl_kdf_params __user *);
+extern long __keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *,
+ size_t, struct keyctl_kdf_params *);
+#ifdef CONFIG_KEYS_COMPAT
+extern long compat_keyctl_dh_compute(struct keyctl_dh_params __user *params,
+ char __user *buffer, size_t buflen,
+ struct compat_keyctl_kdf_params __user *kdf);
+#endif
+#define KEYCTL_KDF_MAX_OUTPUT_LEN 1024 /* max length of KDF output */
+#define KEYCTL_KDF_MAX_OI_LEN 64 /* max length of otherinfo */
#else
static inline long keyctl_dh_compute(struct keyctl_dh_params __user *params,
char __user *buffer, size_t buflen,
- void __user *reserved)
+ struct keyctl_kdf_params __user *kdf)
+{
+ return -EOPNOTSUPP;
+}
+
+#ifdef CONFIG_KEYS_COMPAT
+static inline long compat_keyctl_dh_compute(
+ struct keyctl_dh_params __user *params,
+ char __user *buffer, size_t buflen,
+ struct keyctl_kdf_params __user *kdf)
{
return -EOPNOTSUPP;
}
#endif
+#endif
/*
* Debugging key validation
diff --git a/security/keys/key.c b/security/keys/key.c
index 346fbf201c22e..455c04d80bbbf 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -93,7 +93,7 @@ try_again:
/* if we get here, then the user record still hadn't appeared on the
* second pass - so we use the candidate record */
- atomic_set(&candidate->usage, 1);
+ refcount_set(&candidate->usage, 1);
atomic_set(&candidate->nkeys, 0);
atomic_set(&candidate->nikeys, 0);
candidate->uid = uid;
@@ -110,7 +110,7 @@ try_again:
/* okay - we found a user record for this UID */
found:
- atomic_inc(&user->usage);
+ refcount_inc(&user->usage);
spin_unlock(&key_user_lock);
kfree(candidate);
out:
@@ -122,7 +122,7 @@ out:
*/
void key_user_put(struct key_user *user)
{
- if (atomic_dec_and_lock(&user->usage, &key_user_lock)) {
+ if (refcount_dec_and_lock(&user->usage, &key_user_lock)) {
rb_erase(&user->node, &key_user_tree);
spin_unlock(&key_user_lock);
@@ -201,12 +201,15 @@ serial_exists:
* @cred: The credentials specifying UID namespace.
* @perm: The permissions mask of the new key.
* @flags: Flags specifying quota properties.
- * @restrict_link: Optional link restriction method for new keyrings.
+ * @restrict_link: Optional link restriction for new keyrings.
*
* Allocate a key of the specified type with the attributes given. The key is
* returned in an uninstantiated state and the caller needs to instantiate the
* key before returning.
*
+ * The restrict_link structure (if not NULL) will be freed when the
+ * keyring is destroyed, so it must be dynamically allocated.
+ *
* The user's key count quota is updated to reflect the creation of the key and
* the user's key data quota has the default for the key type reserved. The
* instantiation function should amend this as necessary. If insufficient
@@ -225,9 +228,7 @@ serial_exists:
struct key *key_alloc(struct key_type *type, const char *desc,
kuid_t uid, kgid_t gid, const struct cred *cred,
key_perm_t perm, unsigned long flags,
- int (*restrict_link)(struct key *,
- const struct key_type *,
- const union key_payload *))
+ struct key_restriction *restrict_link)
{
struct key_user *user = NULL;
struct key *key;
@@ -285,7 +286,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
if (!key->index_key.description)
goto no_memory_3;
- atomic_set(&key->usage, 1);
+ refcount_set(&key->usage, 1);
init_rwsem(&key->sem);
lockdep_set_class(&key->sem, &type->lock_class);
key->index_key.type = type;
@@ -499,19 +500,23 @@ int key_instantiate_and_link(struct key *key,
}
if (keyring) {
- if (keyring->restrict_link) {
- ret = keyring->restrict_link(keyring, key->type,
- &prep.payload);
- if (ret < 0)
- goto error;
- }
ret = __key_link_begin(keyring, &key->index_key, &edit);
if (ret < 0)
goto error;
+
+ if (keyring->restrict_link && keyring->restrict_link->check) {
+ struct key_restriction *keyres = keyring->restrict_link;
+
+ ret = keyres->check(keyring, key->type, &prep.payload,
+ keyres->key);
+ if (ret < 0)
+ goto error_link_end;
+ }
}
ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit);
+error_link_end:
if (keyring)
__key_link_end(keyring, &key->index_key, edit);
@@ -621,7 +626,7 @@ void key_put(struct key *key)
if (key) {
key_check(key);
- if (atomic_dec_and_test(&key->usage))
+ if (refcount_dec_and_test(&key->usage))
schedule_work(&key_gc_work);
}
}
@@ -656,7 +661,7 @@ not_found:
found:
/* pretend it doesn't exist if it is awaiting deletion */
- if (atomic_read(&key->usage) == 0)
+ if (refcount_read(&key->usage) == 0)
goto not_found;
/* this races with key_put(), but that doesn't matter since key_put()
@@ -806,9 +811,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
struct key *keyring, *key = NULL;
key_ref_t key_ref;
int ret;
- int (*restrict_link)(struct key *,
- const struct key_type *,
- const union key_payload *) = NULL;
+ struct key_restriction *restrict_link = NULL;
/* look up the key type to see if it's one of the registered kernel
* types */
@@ -854,20 +857,21 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
}
index_key.desc_len = strlen(index_key.description);
- if (restrict_link) {
- ret = restrict_link(keyring, index_key.type, &prep.payload);
- if (ret < 0) {
- key_ref = ERR_PTR(ret);
- goto error_free_prep;
- }
- }
-
ret = __key_link_begin(keyring, &index_key, &edit);
if (ret < 0) {
key_ref = ERR_PTR(ret);
goto error_free_prep;
}
+ if (restrict_link && restrict_link->check) {
+ ret = restrict_link->check(keyring, index_key.type,
+ &prep.payload, restrict_link->key);
+ if (ret < 0) {
+ key_ref = ERR_PTR(ret);
+ goto error_link_end;
+ }
+ }
+
/* if we're going to allocate a new key, we're going to have
* to modify the keyring */
ret = key_permission(keyring_ref, KEY_NEED_WRITE);
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 52c34532c7856..10fcea154c0f6 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1583,6 +1583,59 @@ error_keyring:
}
/*
+ * Apply a restriction to a given keyring.
+ *
+ * The caller must have Setattr permission to change keyring restrictions.
+ *
+ * The requested type name may be a NULL pointer to reject all attempts
+ * to link to the keyring. If _type is non-NULL, _restriction can be
+ * NULL or a pointer to a string describing the restriction. If _type is
+ * NULL, _restriction must also be NULL.
+ *
+ * Returns 0 if successful.
+ */
+long keyctl_restrict_keyring(key_serial_t id, const char __user *_type,
+ const char __user *_restriction)
+{
+ key_ref_t key_ref;
+ bool link_reject = !_type;
+ char type[32];
+ char *restriction = NULL;
+ long ret;
+
+ key_ref = lookup_user_key(id, 0, KEY_NEED_SETATTR);
+ if (IS_ERR(key_ref))
+ return PTR_ERR(key_ref);
+
+ if (_type) {
+ ret = key_get_type_from_user(type, _type, sizeof(type));
+ if (ret < 0)
+ goto error;
+ }
+
+ if (_restriction) {
+ if (!_type) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ restriction = strndup_user(_restriction, PAGE_SIZE);
+ if (IS_ERR(restriction)) {
+ ret = PTR_ERR(restriction);
+ goto error;
+ }
+ }
+
+ ret = keyring_restrict(key_ref, link_reject ? NULL : type, restriction);
+ kfree(restriction);
+
+error:
+ key_ref_put(key_ref);
+
+ return ret;
+}
+
+/*
* The key control system call
*/
SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
@@ -1691,7 +1744,12 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
case KEYCTL_DH_COMPUTE:
return keyctl_dh_compute((struct keyctl_dh_params __user *) arg2,
(char __user *) arg3, (size_t) arg4,
- (void __user *) arg5);
+ (struct keyctl_kdf_params __user *) arg5);
+
+ case KEYCTL_RESTRICT_KEYRING:
+ return keyctl_restrict_keyring((key_serial_t) arg2,
+ (const char __user *) arg3,
+ (const char __user *) arg4);
default:
return -EOPNOTSUPP;
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index c91e4e0cea08b..4d1678e4586f6 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -394,6 +394,13 @@ static void keyring_destroy(struct key *keyring)
write_unlock(&keyring_name_lock);
}
+ if (keyring->restrict_link) {
+ struct key_restriction *keyres = keyring->restrict_link;
+
+ key_put(keyres->key);
+ kfree(keyres);
+ }
+
assoc_array_destroy(&keyring->keys, &keyring_assoc_array_ops);
}
@@ -492,9 +499,7 @@ static long keyring_read(const struct key *keyring,
struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
const struct cred *cred, key_perm_t perm,
unsigned long flags,
- int (*restrict_link)(struct key *,
- const struct key_type *,
- const union key_payload *),
+ struct key_restriction *restrict_link,
struct key *dest)
{
struct key *keyring;
@@ -519,17 +524,19 @@ EXPORT_SYMBOL(keyring_alloc);
* @keyring: The keyring being added to.
* @type: The type of key being added.
* @payload: The payload of the key intended to be added.
+ * @data: Additional data for evaluating restriction.
*
* Reject the addition of any links to a keyring. It can be overridden by
* passing KEY_ALLOC_BYPASS_RESTRICTION to key_instantiate_and_link() when
* adding a key to a keyring.
*
- * This is meant to be passed as the restrict_link parameter to
- * keyring_alloc().
+ * This is meant to be stored in a key_restriction structure which is passed
+ * in the restrict_link parameter to keyring_alloc().
*/
int restrict_link_reject(struct key *keyring,
const struct key_type *type,
- const union key_payload *payload)
+ const union key_payload *payload,
+ struct key *restriction_key)
{
return -EPERM;
}
@@ -940,6 +947,111 @@ key_ref_t keyring_search(key_ref_t keyring,
}
EXPORT_SYMBOL(keyring_search);
+static struct key_restriction *keyring_restriction_alloc(
+ key_restrict_link_func_t check)
+{
+ struct key_restriction *keyres =
+ kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
+
+ if (!keyres)
+ return ERR_PTR(-ENOMEM);
+
+ keyres->check = check;
+
+ return keyres;
+}
+
+/*
+ * Semaphore to serialise restriction setup to prevent reference count
+ * cycles through restriction key pointers.
+ */
+static DECLARE_RWSEM(keyring_serialise_restrict_sem);
+
+/*
+ * Check for restriction cycles that would prevent keyring garbage collection.
+ * keyring_serialise_restrict_sem must be held.
+ */
+static bool keyring_detect_restriction_cycle(const struct key *dest_keyring,
+ struct key_restriction *keyres)
+{
+ while (keyres && keyres->key &&
+ keyres->key->type == &key_type_keyring) {
+ if (keyres->key == dest_keyring)
+ return true;
+
+ keyres = keyres->key->restrict_link;
+ }
+
+ return false;
+}
+
+/**
+ * keyring_restrict - Look up and apply a restriction to a keyring
+ *
+ * @keyring: The keyring to be restricted
+ * @restriction: The restriction options to apply to the keyring
+ */
+int keyring_restrict(key_ref_t keyring_ref, const char *type,
+ const char *restriction)
+{
+ struct key *keyring;
+ struct key_type *restrict_type = NULL;
+ struct key_restriction *restrict_link;
+ int ret = 0;
+
+ keyring = key_ref_to_ptr(keyring_ref);
+ key_check(keyring);
+
+ if (keyring->type != &key_type_keyring)
+ return -ENOTDIR;
+
+ if (!type) {
+ restrict_link = keyring_restriction_alloc(restrict_link_reject);
+ } else {
+ restrict_type = key_type_lookup(type);
+
+ if (IS_ERR(restrict_type))
+ return PTR_ERR(restrict_type);
+
+ if (!restrict_type->lookup_restriction) {
+ ret = -ENOENT;
+ goto error;
+ }
+
+ restrict_link = restrict_type->lookup_restriction(restriction);
+ }
+
+ if (IS_ERR(restrict_link)) {
+ ret = PTR_ERR(restrict_link);
+ goto error;
+ }
+
+ down_write(&keyring->sem);
+ down_write(&keyring_serialise_restrict_sem);
+
+ if (keyring->restrict_link)
+ ret = -EEXIST;
+ else if (keyring_detect_restriction_cycle(keyring, restrict_link))
+ ret = -EDEADLK;
+ else
+ keyring->restrict_link = restrict_link;
+
+ up_write(&keyring_serialise_restrict_sem);
+ up_write(&keyring->sem);
+
+ if (ret < 0) {
+ key_put(restrict_link->key);
+ kfree(restrict_link);
+ }
+
+error:
+ if (restrict_type)
+ key_type_put(restrict_type);
+
+ return ret;
+}
+EXPORT_SYMBOL(keyring_restrict);
+
/*
* Search the given keyring for a key that might be updated.
*
@@ -1033,7 +1145,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
/* we've got a match but we might end up racing with
* key_cleanup() if the keyring is currently 'dead'
* (ie. it has a zero usage count) */
- if (!atomic_inc_not_zero(&keyring->usage))
+ if (!refcount_inc_not_zero(&keyring->usage))
continue;
keyring->last_used_at = current_kernel_time().tv_sec;
goto out;
@@ -1220,9 +1332,10 @@ void __key_link_end(struct key *keyring,
*/
static int __key_link_check_restriction(struct key *keyring, struct key *key)
{
- if (!keyring->restrict_link)
+ if (!keyring->restrict_link || !keyring->restrict_link->check)
return 0;
- return keyring->restrict_link(keyring, key->type, &key->payload);
+ return keyring->restrict_link->check(keyring, key->type, &key->payload,
+ keyring->restrict_link->key);
}
/**
@@ -1250,14 +1363,14 @@ int key_link(struct key *keyring, struct key *key)
struct assoc_array_edit *edit;
int ret;
- kenter("{%d,%d}", keyring->serial, atomic_read(&keyring->usage));
+ kenter("{%d,%d}", keyring->serial, refcount_read(&keyring->usage));
key_check(keyring);
key_check(key);
ret = __key_link_begin(keyring, &key->index_key, &edit);
if (ret == 0) {
- kdebug("begun {%d,%d}", keyring->serial, atomic_read(&keyring->usage));
+ kdebug("begun {%d,%d}", keyring->serial, refcount_read(&keyring->usage));
ret = __key_link_check_restriction(keyring, key);
if (ret == 0)
ret = __key_link_check_live_key(keyring, key);
@@ -1266,7 +1379,7 @@ int key_link(struct key *keyring, struct key *key)
__key_link_end(keyring, &key->index_key, edit);
}
- kleave(" = %d {%d,%d}", ret, keyring->serial, atomic_read(&keyring->usage));
+ kleave(" = %d {%d,%d}", ret, keyring->serial, refcount_read(&keyring->usage));
return ret;
}
EXPORT_SYMBOL(key_link);
@@ -1426,3 +1539,53 @@ do_gc:
up_write(&keyring->sem);
kleave(" [gc]");
}
+
+/*
+ * Garbage collect restriction pointers from a keyring.
+ *
+ * Keyring restrictions are associated with a key type, and must be cleaned
+ * up if the key type is unregistered. The restriction is altered to always
+ * reject additional keys so a keyring cannot be opened up by unregistering
+ * a key type.
+ *
+ * Not called with any keyring locks held. The keyring's key struct will not
+ * be deallocated under us as only our caller may deallocate it.
+ *
+ * The caller is required to hold key_types_sem and dead_type->sem. This is
+ * fulfilled by key_gc_keytype() holding the locks on behalf of
+ * key_garbage_collector(), which it invokes on a workqueue.
+ */
+void keyring_restriction_gc(struct key *keyring, struct key_type *dead_type)
+{
+ struct key_restriction *keyres;
+
+ kenter("%x{%s}", keyring->serial, keyring->description ?: "");
+
+ /*
+ * keyring->restrict_link is only assigned at key allocation time
+ * or with the key type locked, so the only values that could be
+ * concurrently assigned to keyring->restrict_link are for key
+ * types other than dead_type. Given this, it's ok to check
+ * the key type before acquiring keyring->sem.
+ */
+ if (!dead_type || !keyring->restrict_link ||
+ keyring->restrict_link->keytype != dead_type) {
+ kleave(" [no restriction gc]");
+ return;
+ }
+
+ /* Lock the keyring to ensure that a link is not in progress */
+ down_write(&keyring->sem);
+
+ keyres = keyring->restrict_link;
+
+ keyres->check = restrict_link_reject;
+
+ key_put(keyres->key);
+ keyres->key = NULL;
+ keyres->keytype = NULL;
+
+ up_write(&keyring->sem);
+
+ kleave(" [restriction gc]");
+}
diff --git a/security/keys/proc.c b/security/keys/proc.c
index b9f531c9e4fa7..bf08d02b6646a 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -252,7 +252,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT),
showflag(key, 'N', KEY_FLAG_NEGATIVE),
showflag(key, 'i', KEY_FLAG_INVALIDATED),
- atomic_read(&key->usage),
+ refcount_read(&key->usage),
xbuf,
key->perm,
from_kuid_munged(seq_user_ns(m), key->uid),
@@ -340,7 +340,7 @@ static int proc_key_users_show(struct seq_file *m, void *v)
seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n",
from_kuid_munged(seq_user_ns(m), user->uid),
- atomic_read(&user->usage),
+ refcount_read(&user->usage),
atomic_read(&user->nkeys),
atomic_read(&user->nikeys),
user->qnkeys,
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index b6fdd22205b16..44451af828c0d 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -30,7 +30,7 @@ static DEFINE_MUTEX(key_user_keyring_mutex);
/* The root user's tracking struct */
struct key_user root_key_user = {
- .usage = ATOMIC_INIT(3),
+ .usage = REFCOUNT_INIT(3),
.cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock),
.lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock),
.nkeys = ATOMIC_INIT(2),
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index 6bbe2f535f080..0f062156dfb24 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -213,7 +213,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
if (ret < 0)
goto error_inst;
- kleave(" = {%d,%d}", authkey->serial, atomic_read(&authkey->usage));
+ kleave(" = {%d,%d}", authkey->serial, refcount_read(&authkey->usage));
return authkey;
auth_key_revoked:
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d37a72316e9d1..e67a526d1f301 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4367,10 +4367,18 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
u32 sid, node_perm;
if (family == PF_INET) {
+ if (addrlen < sizeof(struct sockaddr_in)) {
+ err = -EINVAL;
+ goto out;
+ }
addr4 = (struct sockaddr_in *)address;
snum = ntohs(addr4->sin_port);
addrp = (char *)&addr4->sin_addr.s_addr;
} else {
+ if (addrlen < SIN6_LEN_RFC2133) {
+ err = -EINVAL;
+ goto out;
+ }
addr6 = (struct sockaddr_in6 *)address;
snum = ntohs(addr6->sin6_port);
addrp = (char *)&addr6->sin6_addr.s6_addr;
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index 2ca9cde939d44..57e2596bdd8a0 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -28,7 +28,7 @@ struct nlmsg_perm {
u32 perm;
};
-static struct nlmsg_perm nlmsg_route_perms[] =
+static const struct nlmsg_perm nlmsg_route_perms[] =
{
{ RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
@@ -80,7 +80,7 @@ static struct nlmsg_perm nlmsg_route_perms[] =
{ RTM_GETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ },
};
-static struct nlmsg_perm nlmsg_tcpdiag_perms[] =
+static const struct nlmsg_perm nlmsg_tcpdiag_perms[] =
{
{ TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
{ DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
@@ -88,7 +88,7 @@ static struct nlmsg_perm nlmsg_tcpdiag_perms[] =
{ SOCK_DESTROY, NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE },
};
-static struct nlmsg_perm nlmsg_xfrm_perms[] =
+static const struct nlmsg_perm nlmsg_xfrm_perms[] =
{
{ XFRM_MSG_NEWSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
{ XFRM_MSG_DELSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
@@ -115,7 +115,7 @@ static struct nlmsg_perm nlmsg_xfrm_perms[] =
{ XFRM_MSG_MAPPING, NETLINK_XFRM_SOCKET__NLMSG_READ },
};
-static struct nlmsg_perm nlmsg_audit_perms[] =
+static const struct nlmsg_perm nlmsg_audit_perms[] =
{
{ AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ },
{ AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
@@ -136,7 +136,7 @@ static struct nlmsg_perm nlmsg_audit_perms[] =
};
-static int nlmsg_perm(u16 nlmsg_type, u32 *perm, struct nlmsg_perm *tab, size_t tabsize)
+static int nlmsg_perm(u16 nlmsg_type, u32 *perm, const struct nlmsg_perm *tab, size_t tabsize)
{
int i, err = -EINVAL;
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index cb3fd98fb05ae..ce71718842231 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1456,10 +1456,10 @@ static int sel_avc_stats_seq_show(struct seq_file *seq, void *v)
{
struct avc_cache_stats *st = v;
- if (v == SEQ_START_TOKEN)
- seq_printf(seq, "lookups hits misses allocations reclaims "
- "frees\n");
- else {
+ if (v == SEQ_START_TOKEN) {
+ seq_puts(seq,
+ "lookups hits misses allocations reclaims frees\n");
+ } else {
unsigned int lookups = st->lookups;
unsigned int misses = st->misses;
unsigned int hits = lookups - misses;
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index 34afeadd9e73a..771c96afe1d53 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -176,8 +176,9 @@ void cond_policydb_destroy(struct policydb *p)
int cond_init_bool_indexes(struct policydb *p)
{
kfree(p->bool_val_to_struct);
- p->bool_val_to_struct =
- kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL);
+ p->bool_val_to_struct = kmalloc_array(p->p_bools.nprim,
+ sizeof(*p->bool_val_to_struct),
+ GFP_KERNEL);
if (!p->bool_val_to_struct)
return -ENOMEM;
return 0;
@@ -226,7 +227,7 @@ int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
u32 len;
int rc;
- booldatum = kzalloc(sizeof(struct cond_bool_datum), GFP_KERNEL);
+ booldatum = kzalloc(sizeof(*booldatum), GFP_KERNEL);
if (!booldatum)
return -ENOMEM;
@@ -331,7 +332,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
goto err;
}
- list = kzalloc(sizeof(struct cond_av_list), GFP_KERNEL);
+ list = kzalloc(sizeof(*list), GFP_KERNEL);
if (!list) {
rc = -ENOMEM;
goto err;
@@ -420,7 +421,7 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
goto err;
rc = -ENOMEM;
- expr = kzalloc(sizeof(struct cond_expr), GFP_KERNEL);
+ expr = kzalloc(sizeof(*expr), GFP_KERNEL);
if (!expr)
goto err;
@@ -471,7 +472,7 @@ int cond_read_list(struct policydb *p, void *fp)
for (i = 0; i < len; i++) {
rc = -ENOMEM;
- node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node)
goto err;
@@ -663,5 +664,4 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
(node->key.specified & AVTAB_XPERMS))
services_compute_xperms_drivers(xperms, node);
}
- return;
}
diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c
index 2cc4961498428..3858706a29fbb 100644
--- a/security/selinux/ss/hashtab.c
+++ b/security/selinux/ss/hashtab.c
@@ -17,15 +17,15 @@ struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *
u32 i;
p = kzalloc(sizeof(*p), GFP_KERNEL);
- if (p == NULL)
+ if (!p)
return p;
p->size = size;
p->nel = 0;
p->hash_value = hash_value;
p->keycmp = keycmp;
- p->htable = kmalloc(sizeof(*(p->htable)) * size, GFP_KERNEL);
- if (p->htable == NULL) {
+ p->htable = kmalloc_array(size, sizeof(*p->htable), GFP_KERNEL);
+ if (!p->htable) {
kfree(p);
return NULL;
}
@@ -58,7 +58,7 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum)
return -EEXIST;
newnode = kzalloc(sizeof(*newnode), GFP_KERNEL);
- if (newnode == NULL)
+ if (!newnode)
return -ENOMEM;
newnode->key = key;
newnode->datum = datum;
@@ -87,7 +87,7 @@ void *hashtab_search(struct hashtab *h, const void *key)
while (cur && h->keycmp(h, key, cur->key) > 0)
cur = cur->next;
- if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
+ if (!cur || (h->keycmp(h, key, cur->key) != 0))
return NULL;
return cur->datum;
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 9c92f29a38ea4..0080122760ad4 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -178,10 +178,9 @@ static int roles_init(struct policydb *p)
int rc;
struct role_datum *role;
- rc = -ENOMEM;
role = kzalloc(sizeof(*role), GFP_KERNEL);
if (!role)
- goto out;
+ return -ENOMEM;
rc = -EINVAL;
role->value = ++p->p_roles.nprim;
@@ -540,23 +539,23 @@ static int policydb_index(struct policydb *p)
#endif
rc = -ENOMEM;
- p->class_val_to_struct =
- kzalloc(p->p_classes.nprim * sizeof(*(p->class_val_to_struct)),
- GFP_KERNEL);
+ p->class_val_to_struct = kcalloc(p->p_classes.nprim,
+ sizeof(*p->class_val_to_struct),
+ GFP_KERNEL);
if (!p->class_val_to_struct)
goto out;
rc = -ENOMEM;
- p->role_val_to_struct =
- kzalloc(p->p_roles.nprim * sizeof(*(p->role_val_to_struct)),
- GFP_KERNEL);
+ p->role_val_to_struct = kcalloc(p->p_roles.nprim,
+ sizeof(*p->role_val_to_struct),
+ GFP_KERNEL);
if (!p->role_val_to_struct)
goto out;
rc = -ENOMEM;
- p->user_val_to_struct =
- kzalloc(p->p_users.nprim * sizeof(*(p->user_val_to_struct)),
- GFP_KERNEL);
+ p->user_val_to_struct = kcalloc(p->p_users.nprim,
+ sizeof(*p->user_val_to_struct),
+ GFP_KERNEL);
if (!p->user_val_to_struct)
goto out;
@@ -880,8 +879,6 @@ void policydb_destroy(struct policydb *p)
ebitmap_destroy(&p->filename_trans_ttypes);
ebitmap_destroy(&p->policycaps);
ebitmap_destroy(&p->permissive_map);
-
- return;
}
/*
@@ -1120,10 +1117,9 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp)
__le32 buf[2];
u32 len;
- rc = -ENOMEM;
perdatum = kzalloc(sizeof(*perdatum), GFP_KERNEL);
if (!perdatum)
- goto bad;
+ return -ENOMEM;
rc = next_entry(buf, fp, sizeof buf);
if (rc)
@@ -1154,10 +1150,9 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)
u32 len, nel;
int i, rc;
- rc = -ENOMEM;
comdatum = kzalloc(sizeof(*comdatum), GFP_KERNEL);
if (!comdatum)
- goto bad;
+ return -ENOMEM;
rc = next_entry(buf, fp, sizeof buf);
if (rc)
@@ -1320,10 +1315,9 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
u32 len, len2, ncons, nel;
int i, rc;
- rc = -ENOMEM;
cladatum = kzalloc(sizeof(*cladatum), GFP_KERNEL);
if (!cladatum)
- goto bad;
+ return -ENOMEM;
rc = next_entry(buf, fp, sizeof(u32)*6);
if (rc)
@@ -1414,10 +1408,9 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
__le32 buf[3];
u32 len;
- rc = -ENOMEM;
role = kzalloc(sizeof(*role), GFP_KERNEL);
if (!role)
- goto bad;
+ return -ENOMEM;
if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
to_read = 3;
@@ -1471,10 +1464,9 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
__le32 buf[4];
u32 len;
- rc = -ENOMEM;
typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL);
if (!typdatum)
- goto bad;
+ return -ENOMEM;
if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
to_read = 4;
@@ -1546,10 +1538,9 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
__le32 buf[3];
u32 len;
- rc = -ENOMEM;
usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL);
if (!usrdatum)
- goto bad;
+ return -ENOMEM;
if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
to_read = 3;
@@ -1597,10 +1588,9 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
__le32 buf[2];
u32 len;
- rc = -ENOMEM;
levdatum = kzalloc(sizeof(*levdatum), GFP_ATOMIC);
if (!levdatum)
- goto bad;
+ return -ENOMEM;
rc = next_entry(buf, fp, sizeof buf);
if (rc)
@@ -1614,7 +1604,7 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
goto bad;
rc = -ENOMEM;
- levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC);
+ levdatum->level = kmalloc(sizeof(*levdatum->level), GFP_ATOMIC);
if (!levdatum->level)
goto bad;
@@ -1639,10 +1629,9 @@ static int cat_read(struct policydb *p, struct hashtab *h, void *fp)
__le32 buf[3];
u32 len;
- rc = -ENOMEM;
catdatum = kzalloc(sizeof(*catdatum), GFP_ATOMIC);
if (!catdatum)
- goto bad;
+ return -ENOMEM;
rc = next_entry(buf, fp, sizeof buf);
if (rc)
@@ -1854,7 +1843,7 @@ static int range_read(struct policydb *p, void *fp)
rc = next_entry(buf, fp, sizeof(u32));
if (rc)
- goto out;
+ return rc;
nel = le32_to_cpu(buf[0]);
for (i = 0; i < nel; i++) {
@@ -1931,7 +1920,6 @@ static int filename_trans_read(struct policydb *p, void *fp)
nel = le32_to_cpu(buf[0]);
for (i = 0; i < nel; i++) {
- ft = NULL;
otype = NULL;
name = NULL;
@@ -2008,7 +1996,7 @@ static int genfs_read(struct policydb *p, void *fp)
rc = next_entry(buf, fp, sizeof(u32));
if (rc)
- goto out;
+ return rc;
nel = le32_to_cpu(buf[0]);
for (i = 0; i < nel; i++) {
@@ -2100,9 +2088,10 @@ static int genfs_read(struct policydb *p, void *fp)
}
rc = 0;
out:
- if (newgenfs)
+ if (newgenfs) {
kfree(newgenfs->fstype);
- kfree(newgenfs);
+ kfree(newgenfs);
+ }
ocontext_destroy(newc, OCON_FSUSE);
return rc;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index b4aa491a0a23d..60d9b02523215 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -157,7 +157,7 @@ static int selinux_set_mapping(struct policydb *pol,
}
k = 0;
- while (p_in->perms && p_in->perms[k]) {
+ while (p_in->perms[k]) {
/* An empty permission string skips ahead */
if (!*p_in->perms[k]) {
k++;
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index 5840a35155fc3..f6915f257486a 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -18,7 +18,7 @@ int sidtab_init(struct sidtab *s)
{
int i;
- s->htable = kmalloc(sizeof(*(s->htable)) * SIDTAB_SIZE, GFP_ATOMIC);
+ s->htable = kmalloc_array(SIDTAB_SIZE, sizeof(*s->htable), GFP_ATOMIC);
if (!s->htable)
return -ENOMEM;
for (i = 0; i < SIDTAB_SIZE; i++)
@@ -54,7 +54,7 @@ int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
}
newnode = kmalloc(sizeof(*newnode), GFP_ATOMIC);
- if (newnode == NULL) {
+ if (!newnode) {
rc = -ENOMEM;
goto out;
}
@@ -98,7 +98,7 @@ static struct context *sidtab_search_core(struct sidtab *s, u32 sid, int force)
if (force && cur && sid == cur->sid && cur->context.len)
return &cur->context;
- if (cur == NULL || sid != cur->sid || cur->context.len) {
+ if (!cur || sid != cur->sid || cur->context.len) {
/* Remap invalid SIDs to the unlabeled SID. */
sid = SECINITSID_UNLABELED;
hvalue = SIDTAB_HASH(sid);
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index 7041a580019ec..223f21ffa632e 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -692,7 +692,7 @@ int tomoyo_path_number_perm(const u8 type, const struct path *path,
{
struct tomoyo_request_info r;
struct tomoyo_obj_info obj = {
- .path1 = *path,
+ .path1 = { .mnt = path->mnt, .dentry = path->dentry },
};
int error = -ENOMEM;
struct tomoyo_path_info buf;
@@ -740,7 +740,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
struct tomoyo_path_info buf;
struct tomoyo_request_info r;
struct tomoyo_obj_info obj = {
- .path1 = *path,
+ .path1 = { .mnt = path->mnt, .dentry = path->dentry },
};
int idx;
@@ -786,7 +786,7 @@ int tomoyo_path_perm(const u8 operation, const struct path *path, const char *ta
{
struct tomoyo_request_info r;
struct tomoyo_obj_info obj = {
- .path1 = *path,
+ .path1 = { .mnt = path->mnt, .dentry = path->dentry },
};
int error;
struct tomoyo_path_info buf;
@@ -843,7 +843,7 @@ int tomoyo_mkdev_perm(const u8 operation, const struct path *path,
{
struct tomoyo_request_info r;
struct tomoyo_obj_info obj = {
- .path1 = *path,
+ .path1 = { .mnt = path->mnt, .dentry = path->dentry },
};
int error = -ENOMEM;
struct tomoyo_path_info buf;
@@ -890,8 +890,8 @@ int tomoyo_path2_perm(const u8 operation, const struct path *path1,
struct tomoyo_path_info buf2;
struct tomoyo_request_info r;
struct tomoyo_obj_info obj = {
- .path1 = *path1,
- .path2 = *path2,
+ .path1 = { .mnt = path1->mnt, .dentry = path1->dentry },
+ .path2 = { .mnt = path2->mnt, .dentry = path2->dentry }
};
int idx;
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index b5fb930349a99..130b4fa4f65fd 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -165,7 +165,7 @@ static int tomoyo_path_truncate(const struct path *path)
*/
static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry)
{
- struct path path = { parent->mnt, dentry };
+ struct path path = { .mnt = parent->mnt, .dentry = dentry };
return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL);
}
@@ -181,7 +181,7 @@ static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry)
static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry,
umode_t mode)
{
- struct path path = { parent->mnt, dentry };
+ struct path path = { .mnt = parent->mnt, .dentry = dentry };
return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path,
mode & S_IALLUGO);
}
@@ -196,7 +196,7 @@ static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry,
*/
static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry)
{
- struct path path = { parent->mnt, dentry };
+ struct path path = { .mnt = parent->mnt, .dentry = dentry };
return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL);
}
@@ -212,7 +212,7 @@ static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry)
static int tomoyo_path_symlink(const struct path *parent, struct dentry *dentry,
const char *old_name)
{
- struct path path = { parent->mnt, dentry };
+ struct path path = { .mnt = parent->mnt, .dentry = dentry };
return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name);
}
@@ -229,7 +229,7 @@ static int tomoyo_path_symlink(const struct path *parent, struct dentry *dentry,
static int tomoyo_path_mknod(const struct path *parent, struct dentry *dentry,
umode_t mode, unsigned int dev)
{
- struct path path = { parent->mnt, dentry };
+ struct path path = { .mnt = parent->mnt, .dentry = dentry };
int type = TOMOYO_TYPE_CREATE;
const unsigned int perm = mode & S_IALLUGO;
@@ -268,8 +268,8 @@ static int tomoyo_path_mknod(const struct path *parent, struct dentry *dentry,
static int tomoyo_path_link(struct dentry *old_dentry, const struct path *new_dir,
struct dentry *new_dentry)
{
- struct path path1 = { new_dir->mnt, old_dentry };
- struct path path2 = { new_dir->mnt, new_dentry };
+ struct path path1 = { .mnt = new_dir->mnt, .dentry = old_dentry };
+ struct path path2 = { .mnt = new_dir->mnt, .dentry = new_dentry };
return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2);
}
@@ -288,8 +288,8 @@ static int tomoyo_path_rename(const struct path *old_parent,
const struct path *new_parent,
struct dentry *new_dentry)
{
- struct path path1 = { old_parent->mnt, old_dentry };
- struct path path2 = { new_parent->mnt, new_dentry };
+ struct path path1 = { .mnt = old_parent->mnt, .dentry = old_dentry };
+ struct path path2 = { .mnt = new_parent->mnt, .dentry = new_dentry };
return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2);
}
@@ -417,7 +417,7 @@ static int tomoyo_sb_mount(const char *dev_name, const struct path *path,
*/
static int tomoyo_sb_umount(struct vfsmount *mnt, int flags)
{
- struct path path = { mnt, mnt->mnt_root };
+ struct path path = { .mnt = mnt, .dentry = mnt->mnt_root };
return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL);
}