summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-11-05 15:32:38 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2015-11-05 15:32:38 -0800
commit1873499e13648a2dd01a394ed3217c9290921b3d (patch)
tree3a662aadb3c02bbce2e9231a90da6e98b54d33d4 /security
parent3460b01b12aaf0011cb30f6f502edd05752f70eb (diff)
parentba94c3ff20c9c179f2a80f0e4c71e1571ebbf5c7 (diff)
downloadlwn-1873499e13648a2dd01a394ed3217c9290921b3d.tar.gz
lwn-1873499e13648a2dd01a394ed3217c9290921b3d.zip
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem update from James Morris: "This is mostly maintenance updates across the subsystem, with a notable update for TPM 2.0, and addition of Jarkko Sakkinen as a maintainer of that" * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (40 commits) apparmor: clarify CRYPTO dependency selinux: Use a kmem_cache for allocation struct file_security_struct selinux: ioctl_has_perm should be static selinux: use sprintf return value selinux: use kstrdup() in security_get_bools() selinux: use kmemdup in security_sid_to_context_core() selinux: remove pointless cast in selinux_inode_setsecurity() selinux: introduce security_context_str_to_sid selinux: do not check open perm on ftruncate call selinux: change CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE default KEYS: Merge the type-specific data with the payload data KEYS: Provide a script to extract a module signature KEYS: Provide a script to extract the sys cert list from a vmlinux file keys: Be more consistent in selection of union members used certs: add .gitignore to stop git nagging about x509_certificate_list KEYS: use kvfree() in add_key Smack: limited capability for changing process label TPM: remove unnecessary little endian conversion vTPM: support little endian guests char: Drop owner assignment from i2c_driver ...
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/Kconfig2
-rw-r--r--security/integrity/digsig.c2
-rw-r--r--security/integrity/evm/evm_crypto.c2
-rw-r--r--security/keys/big_key.c47
-rw-r--r--security/keys/encrypted-keys/encrypted.c18
-rw-r--r--security/keys/encrypted-keys/encrypted.h4
-rw-r--r--security/keys/encrypted-keys/masterkey_trusted.c4
-rw-r--r--security/keys/key.c20
-rw-r--r--security/keys/keyctl.c12
-rw-r--r--security/keys/keyring.c12
-rw-r--r--security/keys/process_keys.c4
-rw-r--r--security/keys/request_key.c4
-rw-r--r--security/keys/request_key_auth.c12
-rw-r--r--security/keys/trusted.c42
-rw-r--r--security/keys/trusted.h11
-rw-r--r--security/keys/user_defined.c14
-rw-r--r--security/selinux/Kconfig4
-rw-r--r--security/selinux/hooks.c27
-rw-r--r--security/selinux/include/security.h2
-rw-r--r--security/selinux/selinuxfs.c26
-rw-r--r--security/selinux/ss/services.c22
-rw-r--r--security/smack/smack.h4
-rw-r--r--security/smack/smack_access.c6
-rw-r--r--security/smack/smack_lsm.c67
-rw-r--r--security/smack/smackfs.c208
25 files changed, 393 insertions, 183 deletions
diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
index d49c53960b60..232469baa94f 100644
--- a/security/apparmor/Kconfig
+++ b/security/apparmor/Kconfig
@@ -33,7 +33,7 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE
config SECURITY_APPARMOR_HASH
bool "SHA1 hash of loaded profiles"
depends on SECURITY_APPARMOR
- depends on CRYPTO
+ select CRYPTO
select CRYPTO_SHA1
default y
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 36fb6b527829..5be9ffbe90ba 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -105,7 +105,7 @@ int __init integrity_load_x509(const unsigned int id, const char *path)
rc,
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ),
- KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_TRUSTED);
+ KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(key)) {
rc = PTR_ERR(key);
pr_err("Problem loading X.509 certificate (%d): %s\n",
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 159ef3ea4130..461f8d891579 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -247,7 +247,7 @@ int evm_init_key(void)
return -ENOENT;
down_read(&evm_key->sem);
- ekp = evm_key->payload.data;
+ ekp = evm_key->payload.data[0];
if (ekp->decrypted_datalen > MAX_KEY_SIZE) {
rc = -EINVAL;
goto out;
diff --git a/security/keys/big_key.c b/security/keys/big_key.c
index b6adb94f6d52..907c1522ee46 100644
--- a/security/keys/big_key.c
+++ b/security/keys/big_key.c
@@ -21,6 +21,16 @@
MODULE_LICENSE("GPL");
/*
+ * Layout of key payload words.
+ */
+enum {
+ big_key_data,
+ big_key_path,
+ big_key_path_2nd_part,
+ big_key_len,
+};
+
+/*
* If the data is under this limit, there's no point creating a shm file to
* hold it as the permanently resident metadata for the shmem fs will be at
* least as large as the data.
@@ -47,7 +57,7 @@ struct key_type key_type_big_key = {
*/
int big_key_preparse(struct key_preparsed_payload *prep)
{
- struct path *path = (struct path *)&prep->payload;
+ struct path *path = (struct path *)&prep->payload.data[big_key_path];
struct file *file;
ssize_t written;
size_t datalen = prep->datalen;
@@ -60,7 +70,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
/* Set an arbitrary quota */
prep->quotalen = 16;
- prep->type_data[1] = (void *)(unsigned long)datalen;
+ prep->payload.data[big_key_len] = (void *)(unsigned long)datalen;
if (datalen > BIG_KEY_FILE_THRESHOLD) {
/* Create a shmem file to store the data in. This will permit the data
@@ -94,7 +104,8 @@ int big_key_preparse(struct key_preparsed_payload *prep)
if (!data)
return -ENOMEM;
- prep->payload[0] = memcpy(data, prep->data, prep->datalen);
+ prep->payload.data[big_key_data] = data;
+ memcpy(data, prep->data, prep->datalen);
}
return 0;
@@ -110,10 +121,10 @@ error:
void big_key_free_preparse(struct key_preparsed_payload *prep)
{
if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
- struct path *path = (struct path *)&prep->payload;
+ struct path *path = (struct path *)&prep->payload.data[big_key_path];
path_put(path);
} else {
- kfree(prep->payload[0]);
+ kfree(prep->payload.data[big_key_data]);
}
}
@@ -123,11 +134,12 @@ void big_key_free_preparse(struct key_preparsed_payload *prep)
*/
void big_key_revoke(struct key *key)
{
- struct path *path = (struct path *)&key->payload.data2;
+ struct path *path = (struct path *)&key->payload.data[big_key_path];
/* clear the quota */
key_payload_reserve(key, 0);
- if (key_is_instantiated(key) && key->type_data.x[1] > BIG_KEY_FILE_THRESHOLD)
+ if (key_is_instantiated(key) &&
+ (size_t)key->payload.data[big_key_len] > BIG_KEY_FILE_THRESHOLD)
vfs_truncate(path, 0);
}
@@ -136,14 +148,16 @@ void big_key_revoke(struct key *key)
*/
void big_key_destroy(struct key *key)
{
- if (key->type_data.x[1] > BIG_KEY_FILE_THRESHOLD) {
- struct path *path = (struct path *)&key->payload.data2;
+ size_t datalen = (size_t)key->payload.data[big_key_len];
+
+ if (datalen) {
+ struct path *path = (struct path *)&key->payload.data[big_key_path];
path_put(path);
path->mnt = NULL;
path->dentry = NULL;
} else {
- kfree(key->payload.data);
- key->payload.data = NULL;
+ kfree(key->payload.data[big_key_data]);
+ key->payload.data[big_key_data] = NULL;
}
}
@@ -152,12 +166,12 @@ void big_key_destroy(struct key *key)
*/
void big_key_describe(const struct key *key, struct seq_file *m)
{
- unsigned long datalen = key->type_data.x[1];
+ size_t datalen = (size_t)key->payload.data[big_key_len];
seq_puts(m, key->description);
if (key_is_instantiated(key))
- seq_printf(m, ": %lu [%s]",
+ seq_printf(m, ": %zu [%s]",
datalen,
datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
}
@@ -168,14 +182,14 @@ void big_key_describe(const struct key *key, struct seq_file *m)
*/
long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
{
- unsigned long datalen = key->type_data.x[1];
+ size_t datalen = (size_t)key->payload.data[big_key_len];
long ret;
if (!buffer || buflen < datalen)
return datalen;
if (datalen > BIG_KEY_FILE_THRESHOLD) {
- struct path *path = (struct path *)&key->payload.data2;
+ struct path *path = (struct path *)&key->payload.data[big_key_path];
struct file *file;
loff_t pos;
@@ -190,7 +204,8 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
ret = -EIO;
} else {
ret = datalen;
- if (copy_to_user(buffer, key->payload.data, datalen) != 0)
+ if (copy_to_user(buffer, key->payload.data[big_key_data],
+ datalen) != 0)
ret = -EFAULT;
}
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index 7bed4ad7cd76..927db9f35ad6 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -303,10 +303,10 @@ out:
*
* Use a user provided key to encrypt/decrypt an encrypted-key.
*/
-static struct key *request_user_key(const char *master_desc, u8 **master_key,
+static struct key *request_user_key(const char *master_desc, const u8 **master_key,
size_t *master_keylen)
{
- struct user_key_payload *upayload;
+ const struct user_key_payload *upayload;
struct key *ukey;
ukey = request_key(&key_type_user, master_desc, NULL);
@@ -314,7 +314,7 @@ static struct key *request_user_key(const char *master_desc, u8 **master_key,
goto error;
down_read(&ukey->sem);
- upayload = ukey->payload.data;
+ upayload = user_key_payload(ukey);
*master_key = upayload->data;
*master_keylen = upayload->datalen;
error:
@@ -426,7 +426,7 @@ static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key,
}
static struct key *request_master_key(struct encrypted_key_payload *epayload,
- u8 **master_key, size_t *master_keylen)
+ const u8 **master_key, size_t *master_keylen)
{
struct key *mkey = NULL;
@@ -653,7 +653,7 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
{
struct key *mkey;
u8 derived_key[HASH_SIZE];
- u8 *master_key;
+ const u8 *master_key;
u8 *hmac;
const char *hex_encoded_data;
unsigned int encrypted_datalen;
@@ -837,7 +837,7 @@ static void encrypted_rcu_free(struct rcu_head *rcu)
*/
static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
{
- struct encrypted_key_payload *epayload = key->payload.data;
+ struct encrypted_key_payload *epayload = key->payload.data[0];
struct encrypted_key_payload *new_epayload;
char *buf;
char *new_master_desc = NULL;
@@ -896,7 +896,7 @@ static long encrypted_read(const struct key *key, char __user *buffer,
{
struct encrypted_key_payload *epayload;
struct key *mkey;
- u8 *master_key;
+ const u8 *master_key;
size_t master_keylen;
char derived_key[HASH_SIZE];
char *ascii_buf;
@@ -957,13 +957,13 @@ out:
*/
static void encrypted_destroy(struct key *key)
{
- struct encrypted_key_payload *epayload = key->payload.data;
+ struct encrypted_key_payload *epayload = key->payload.data[0];
if (!epayload)
return;
memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
- kfree(key->payload.data);
+ kfree(key->payload.data[0]);
}
struct key_type key_type_encrypted = {
diff --git a/security/keys/encrypted-keys/encrypted.h b/security/keys/encrypted-keys/encrypted.h
index 8136a2d44c63..47802c0de735 100644
--- a/security/keys/encrypted-keys/encrypted.h
+++ b/security/keys/encrypted-keys/encrypted.h
@@ -5,10 +5,10 @@
#if defined(CONFIG_TRUSTED_KEYS) || \
(defined(CONFIG_TRUSTED_KEYS_MODULE) && defined(CONFIG_ENCRYPTED_KEYS_MODULE))
extern struct key *request_trusted_key(const char *trusted_desc,
- u8 **master_key, size_t *master_keylen);
+ const u8 **master_key, size_t *master_keylen);
#else
static inline struct key *request_trusted_key(const char *trusted_desc,
- u8 **master_key,
+ const u8 **master_key,
size_t *master_keylen)
{
return ERR_PTR(-EOPNOTSUPP);
diff --git a/security/keys/encrypted-keys/masterkey_trusted.c b/security/keys/encrypted-keys/masterkey_trusted.c
index 013f7e5d3a2f..b5b4812dbc87 100644
--- a/security/keys/encrypted-keys/masterkey_trusted.c
+++ b/security/keys/encrypted-keys/masterkey_trusted.c
@@ -29,7 +29,7 @@
* data, trusted key type data is not visible decrypted from userspace.
*/
struct key *request_trusted_key(const char *trusted_desc,
- u8 **master_key, size_t *master_keylen)
+ const u8 **master_key, size_t *master_keylen)
{
struct trusted_key_payload *tpayload;
struct key *tkey;
@@ -39,7 +39,7 @@ struct key *request_trusted_key(const char *trusted_desc,
goto error;
down_read(&tkey->sem);
- tpayload = tkey->payload.data;
+ tpayload = tkey->payload.data[0];
*master_key = tpayload->key;
*master_keylen = tpayload->key_len;
error:
diff --git a/security/keys/key.c b/security/keys/key.c
index aee2ec5a18fc..ab7997ded725 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -278,7 +278,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
key->index_key.desc_len = desclen;
key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL);
- if (!key->description)
+ if (!key->index_key.description)
goto no_memory_3;
atomic_set(&key->usage, 1);
@@ -554,7 +554,7 @@ int key_reject_and_link(struct key *key,
if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
/* mark the key as being negatively instantiated */
atomic_inc(&key->user->nikeys);
- key->type_data.reject_error = -error;
+ key->reject_error = -error;
smp_wmb();
set_bit(KEY_FLAG_NEGATIVE, &key->flags);
set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
@@ -1046,14 +1046,14 @@ int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
ret = key_payload_reserve(key, prep->quotalen);
if (ret == 0) {
- key->type_data.p[0] = prep->type_data[0];
- key->type_data.p[1] = prep->type_data[1];
- rcu_assign_keypointer(key, prep->payload[0]);
- key->payload.data2[1] = prep->payload[1];
- prep->type_data[0] = NULL;
- prep->type_data[1] = NULL;
- prep->payload[0] = NULL;
- prep->payload[1] = NULL;
+ rcu_assign_keypointer(key, prep->payload.data[0]);
+ key->payload.data[1] = prep->payload.data[1];
+ key->payload.data[2] = prep->payload.data[2];
+ key->payload.data[3] = prep->payload.data[3];
+ prep->payload.data[0] = NULL;
+ prep->payload.data[1] = NULL;
+ prep->payload.data[2] = NULL;
+ prep->payload.data[3] = NULL;
}
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 0b9ec78a7a7a..fb111eafcb89 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -67,7 +67,6 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
char type[32], *description;
void *payload;
long ret;
- bool vm;
ret = -EINVAL;
if (plen > 1024 * 1024 - 1)
@@ -98,14 +97,12 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
/* pull the payload in if one was supplied */
payload = NULL;
- vm = false;
if (_payload) {
ret = -ENOMEM;
payload = kmalloc(plen, GFP_KERNEL | __GFP_NOWARN);
if (!payload) {
if (plen <= PAGE_SIZE)
goto error2;
- vm = true;
payload = vmalloc(plen);
if (!payload)
goto error2;
@@ -138,10 +135,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
key_ref_put(keyring_ref);
error3:
- if (!vm)
- kfree(payload);
- else
- vfree(payload);
+ kvfree(payload);
error2:
kfree(description);
error:
@@ -1033,7 +1027,7 @@ long keyctl_instantiate_key_common(key_serial_t id,
if (!instkey)
goto error;
- rka = instkey->payload.data;
+ rka = instkey->payload.data[0];
if (rka->target_key->serial != id)
goto error;
@@ -1200,7 +1194,7 @@ long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error,
if (!instkey)
goto error;
- rka = instkey->payload.data;
+ rka = instkey->payload.data[0];
if (rka->target_key->serial != id)
goto error;
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index d33437007ad2..f931ccfeefb0 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -118,7 +118,7 @@ static void keyring_publish_name(struct key *keyring)
if (!keyring_name_hash[bucket].next)
INIT_LIST_HEAD(&keyring_name_hash[bucket]);
- list_add_tail(&keyring->type_data.link,
+ list_add_tail(&keyring->name_link,
&keyring_name_hash[bucket]);
write_unlock(&keyring_name_lock);
@@ -387,9 +387,9 @@ static void keyring_destroy(struct key *keyring)
if (keyring->description) {
write_lock(&keyring_name_lock);
- if (keyring->type_data.link.next != NULL &&
- !list_empty(&keyring->type_data.link))
- list_del(&keyring->type_data.link);
+ if (keyring->name_link.next != NULL &&
+ !list_empty(&keyring->name_link))
+ list_del(&keyring->name_link);
write_unlock(&keyring_name_lock);
}
@@ -572,7 +572,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
/* we set a different error code if we pass a negative key */
if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
smp_rmb();
- ctx->result = ERR_PTR(key->type_data.reject_error);
+ ctx->result = ERR_PTR(key->reject_error);
kleave(" = %d [neg]", ctx->skipped_ret);
goto skipped;
}
@@ -990,7 +990,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
* that's readable and that hasn't been revoked */
list_for_each_entry(keyring,
&keyring_name_hash[bucket],
- type_data.link
+ name_link
) {
if (!kuid_has_mapping(current_user_ns(), keyring->user->uid))
continue;
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 43b4cddbf2b3..a3f85d2a00bb 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -457,7 +457,7 @@ key_ref_t search_process_keyrings(struct keyring_search_context *ctx)
down_read(&cred->request_key_auth->sem);
if (key_validate(ctx->cred->request_key_auth) == 0) {
- rka = ctx->cred->request_key_auth->payload.data;
+ rka = ctx->cred->request_key_auth->payload.data[0];
ctx->cred = rka->cred;
key_ref = search_process_keyrings(ctx);
@@ -647,7 +647,7 @@ try_again:
key_ref = ERR_PTR(-EKEYREVOKED);
key = NULL;
} else {
- rka = ctx.cred->request_key_auth->payload.data;
+ rka = ctx.cred->request_key_auth->payload.data[0];
key = rka->dest_keyring;
__key_get(key);
}
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 0d6253124278..c7a117c9a8f3 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -271,7 +271,7 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
if (cred->request_key_auth) {
authkey = cred->request_key_auth;
down_read(&authkey->sem);
- rka = authkey->payload.data;
+ rka = authkey->payload.data[0];
if (!test_bit(KEY_FLAG_REVOKED,
&authkey->flags))
dest_keyring =
@@ -596,7 +596,7 @@ int wait_for_key_construction(struct key *key, bool intr)
return -ERESTARTSYS;
if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
smp_rmb();
- return key->type_data.reject_error;
+ return key->reject_error;
}
return key_validate(key);
}
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index 5d672f7580dd..4f0f112fe276 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -59,7 +59,7 @@ static void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
static int request_key_auth_instantiate(struct key *key,
struct key_preparsed_payload *prep)
{
- key->payload.data = (struct request_key_auth *)prep->data;
+ key->payload.data[0] = (struct request_key_auth *)prep->data;
return 0;
}
@@ -69,7 +69,7 @@ static int request_key_auth_instantiate(struct key *key,
static void request_key_auth_describe(const struct key *key,
struct seq_file *m)
{
- struct request_key_auth *rka = key->payload.data;
+ struct request_key_auth *rka = key->payload.data[0];
seq_puts(m, "key:");
seq_puts(m, key->description);
@@ -84,7 +84,7 @@ static void request_key_auth_describe(const struct key *key,
static long request_key_auth_read(const struct key *key,
char __user *buffer, size_t buflen)
{
- struct request_key_auth *rka = key->payload.data;
+ struct request_key_auth *rka = key->payload.data[0];
size_t datalen;
long ret;
@@ -110,7 +110,7 @@ static long request_key_auth_read(const struct key *key,
*/
static void request_key_auth_revoke(struct key *key)
{
- struct request_key_auth *rka = key->payload.data;
+ struct request_key_auth *rka = key->payload.data[0];
kenter("{%d}", key->serial);
@@ -125,7 +125,7 @@ static void request_key_auth_revoke(struct key *key)
*/
static void request_key_auth_destroy(struct key *key)
{
- struct request_key_auth *rka = key->payload.data;
+ struct request_key_auth *rka = key->payload.data[0];
kenter("{%d}", key->serial);
@@ -179,7 +179,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
if (test_bit(KEY_FLAG_REVOKED, &cred->request_key_auth->flags))
goto auth_key_revoked;
- irka = cred->request_key_auth->payload.data;
+ irka = cred->request_key_auth->payload.data[0];
rka->cred = get_cred(irka->cred);
rka->pid = irka->pid;
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index c0594cb07ada..903dace648a1 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -862,12 +862,19 @@ static int datablob_parse(char *datablob, struct trusted_key_payload *p,
static struct trusted_key_options *trusted_options_alloc(void)
{
struct trusted_key_options *options;
+ int tpm2;
+
+ tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
+ if (tpm2 < 0)
+ return NULL;
options = kzalloc(sizeof *options, GFP_KERNEL);
if (options) {
/* set any non-zero defaults */
options->keytype = SRK_keytype;
- options->keyhandle = SRKHANDLE;
+
+ if (!tpm2)
+ options->keyhandle = SRKHANDLE;
}
return options;
}
@@ -905,6 +912,11 @@ static int trusted_instantiate(struct key *key,
int ret = 0;
int key_cmd;
size_t key_len;
+ int tpm2;
+
+ tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
+ if (tpm2 < 0)
+ return tpm2;
if (datalen <= 0 || datalen > 32767 || !prep->data)
return -EINVAL;
@@ -932,12 +944,20 @@ static int trusted_instantiate(struct key *key,
goto out;
}
+ if (!options->keyhandle) {
+ ret = -EINVAL;
+ goto out;
+ }
+
dump_payload(payload);
dump_options(options);
switch (key_cmd) {
case Opt_load:
- ret = key_unseal(payload, options);
+ if (tpm2)
+ ret = tpm_unseal_trusted(TPM_ANY_NUM, payload, options);
+ else
+ ret = key_unseal(payload, options);
dump_payload(payload);
dump_options(options);
if (ret < 0)
@@ -950,7 +970,10 @@ static int trusted_instantiate(struct key *key,
pr_info("trusted_key: key_create failed (%d)\n", ret);
goto out;
}
- ret = key_seal(payload, options);
+ if (tpm2)
+ ret = tpm_seal_trusted(TPM_ANY_NUM, payload, options);
+ else
+ ret = key_seal(payload, options);
if (ret < 0)
pr_info("trusted_key: key_seal failed (%d)\n", ret);
break;
@@ -984,7 +1007,7 @@ static void trusted_rcu_free(struct rcu_head *rcu)
*/
static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
{
- struct trusted_key_payload *p = key->payload.data;
+ struct trusted_key_payload *p = key->payload.data[0];
struct trusted_key_payload *new_p;
struct trusted_key_options *new_o;
size_t datalen = prep->datalen;
@@ -1018,6 +1041,13 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
kfree(new_p);
goto out;
}
+
+ if (!new_o->keyhandle) {
+ ret = -EINVAL;
+ kfree(new_p);
+ goto out;
+ }
+
/* copy old key values, and reseal with new pcrs */
new_p->migratable = p->migratable;
new_p->key_len = p->key_len;
@@ -1084,12 +1114,12 @@ static long trusted_read(const struct key *key, char __user *buffer,
*/
static void trusted_destroy(struct key *key)
{
- struct trusted_key_payload *p = key->payload.data;
+ struct trusted_key_payload *p = key->payload.data[0];
if (!p)
return;
memset(p->key, 0, p->key_len);
- kfree(key->payload.data);
+ kfree(key->payload.data[0]);
}
struct key_type key_type_trusted = {
diff --git a/security/keys/trusted.h b/security/keys/trusted.h
index 3249fbd2b653..ff001a5dcb24 100644
--- a/security/keys/trusted.h
+++ b/security/keys/trusted.h
@@ -2,7 +2,6 @@
#define __TRUSTED_KEY_H
/* implementation specific TPM constants */
-#define MAX_PCRINFO_SIZE 64
#define MAX_BUF_SIZE 512
#define TPM_GETRANDOM_SIZE 14
#define TPM_OSAP_SIZE 36
@@ -36,16 +35,6 @@ enum {
SRK_keytype = 4
};
-struct trusted_key_options {
- uint16_t keytype;
- uint32_t keyhandle;
- unsigned char keyauth[SHA1_DIGEST_SIZE];
- unsigned char blobauth[SHA1_DIGEST_SIZE];
- uint32_t pcrinfo_len;
- unsigned char pcrinfo[MAX_PCRINFO_SIZE];
- int pcrlock;
-};
-
#define TPM_DEBUG 0
#if TPM_DEBUG
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 36b47bbd3d8c..28cb30f80256 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -74,7 +74,7 @@ int user_preparse(struct key_preparsed_payload *prep)
/* attach the data */
prep->quotalen = datalen;
- prep->payload[0] = upayload;
+ prep->payload.data[0] = upayload;
upayload->datalen = datalen;
memcpy(upayload->data, prep->data, datalen);
return 0;
@@ -86,7 +86,7 @@ EXPORT_SYMBOL_GPL(user_preparse);
*/
void user_free_preparse(struct key_preparsed_payload *prep)
{
- kfree(prep->payload[0]);
+ kfree(prep->payload.data[0]);
}
EXPORT_SYMBOL_GPL(user_free_preparse);
@@ -120,7 +120,7 @@ int user_update(struct key *key, struct key_preparsed_payload *prep)
if (ret == 0) {
/* attach the new data, displacing the old */
- zap = key->payload.data;
+ zap = key->payload.data[0];
rcu_assign_keypointer(key, upayload);
key->expiry = 0;
}
@@ -140,7 +140,7 @@ EXPORT_SYMBOL_GPL(user_update);
*/
void user_revoke(struct key *key)
{
- struct user_key_payload *upayload = key->payload.data;
+ struct user_key_payload *upayload = key->payload.data[0];
/* clear the quota */
key_payload_reserve(key, 0);
@@ -158,7 +158,7 @@ EXPORT_SYMBOL(user_revoke);
*/
void user_destroy(struct key *key)
{
- struct user_key_payload *upayload = key->payload.data;
+ struct user_key_payload *upayload = key->payload.data[0];
kfree(upayload);
}
@@ -183,10 +183,10 @@ EXPORT_SYMBOL_GPL(user_describe);
*/
long user_read(const struct key *key, char __user *buffer, size_t buflen)
{
- struct user_key_payload *upayload;
+ const struct user_key_payload *upayload;
long ret;
- upayload = rcu_dereference_key(key);
+ upayload = user_key_payload(key);
ret = upayload->datalen;
/* we can return the data as is */
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index bca1b74a4a2f..8691e92f27e5 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -78,7 +78,7 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE
int "NSA SELinux checkreqprot default value"
depends on SECURITY_SELINUX
range 0 1
- default 1
+ default 0
help
This option sets the default value for the 'checkreqprot' flag
that determines whether SELinux checks the protection requested
@@ -92,7 +92,7 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE
'checkreqprot=' boot parameter. It may also be changed at runtime
via /selinux/checkreqprot if authorized by policy.
- If you are unsure how to answer this question, answer 1.
+ If you are unsure how to answer this question, answer 0.
config SECURITY_SELINUX_POLICYDB_VERSION_MAX
bool "NSA SELinux maximum supported policy format version"
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 26f4039d54b8..9e591e5989be 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -126,6 +126,7 @@ int selinux_enabled = 1;
#endif
static struct kmem_cache *sel_inode_cache;
+static struct kmem_cache *file_security_cache;
/**
* selinux_secmark_enabled - Check to see if SECMARK is currently enabled
@@ -287,7 +288,7 @@ static int file_alloc_security(struct file *file)
struct file_security_struct *fsec;
u32 sid = current_sid();
- fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL);
+ fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
if (!fsec)
return -ENOMEM;
@@ -302,7 +303,7 @@ static void file_free_security(struct file *file)
{
struct file_security_struct *fsec = file->f_security;
file->f_security = NULL;
- kfree(fsec);
+ kmem_cache_free(file_security_cache, fsec);
}
static int superblock_alloc_security(struct super_block *sb)
@@ -674,10 +675,9 @@ static int selinux_set_mnt_opts(struct super_block *sb,
if (flags[i] == SBLABEL_MNT)
continue;
- rc = security_context_to_sid(mount_options[i],
- strlen(mount_options[i]), &sid, GFP_KERNEL);
+ rc = security_context_str_to_sid(mount_options[i], &sid, GFP_KERNEL);
if (rc) {
- printk(KERN_WARNING "SELinux: security_context_to_sid"
+ printk(KERN_WARNING "SELinux: security_context_str_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n",
mount_options[i], sb->s_id, name, rc);
goto out;
@@ -2617,15 +2617,12 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
for (i = 0; i < opts.num_mnt_opts; i++) {
u32 sid;
- size_t len;
if (flags[i] == SBLABEL_MNT)
continue;
- len = strlen(mount_options[i]);
- rc = security_context_to_sid(mount_options[i], len, &sid,
- GFP_KERNEL);
+ rc = security_context_str_to_sid(mount_options[i], &sid, GFP_KERNEL);
if (rc) {
- printk(KERN_WARNING "SELinux: security_context_to_sid"
+ printk(KERN_WARNING "SELinux: security_context_str_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n",
mount_options[i], sb->s_id, sb->s_type->name, rc);
goto out_free_opts;
@@ -2946,7 +2943,8 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
return dentry_has_perm(cred, dentry, FILE__SETATTR);
- if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE))
+ if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE)
+ && !(ia_valid & ATTR_FILE))
av |= FILE__OPEN;
return dentry_has_perm(cred, dentry, av);
@@ -3166,7 +3164,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
if (!value || !size)
return -EACCES;
- rc = security_context_to_sid((void *)value, size, &newsid, GFP_KERNEL);
+ rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL);
if (rc)
return rc;
@@ -3238,7 +3236,7 @@ static void selinux_file_free_security(struct file *file)
* Check whether a task has the ioctl permission and cmd
* operation to an inode.
*/
-int ioctl_has_perm(const struct cred *cred, struct file *file,
+static int ioctl_has_perm(const struct cred *cred, struct file *file,
u32 requested, u16 cmd)
{
struct common_audit_data ad;
@@ -6093,6 +6091,9 @@ static __init int selinux_init(void)
sel_inode_cache = kmem_cache_create("selinux_inode_security",
sizeof(struct inode_security_struct),
0, SLAB_PANIC, NULL);
+ file_security_cache = kmem_cache_create("selinux_file_security",
+ sizeof(struct file_security_struct),
+ 0, SLAB_PANIC, NULL);
avc_init();
security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 6a681d26bf20..223e9fd15d66 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -166,6 +166,8 @@ int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len);
int security_context_to_sid(const char *scontext, u32 scontext_len,
u32 *out_sid, gfp_t gfp);
+int security_context_str_to_sid(const char *scontext, u32 *out_sid, gfp_t gfp);
+
int security_context_to_sid_default(const char *scontext, u32 scontext_len,
u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 5bed7716f8ab..c02da25d7b63 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -731,13 +731,11 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
- length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
- GFP_KERNEL);
+ length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
if (length)
goto out;
- length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
- GFP_KERNEL);
+ length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
@@ -819,13 +817,11 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
objname = namebuf;
}
- length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
- GFP_KERNEL);
+ length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
if (length)
goto out;
- length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
- GFP_KERNEL);
+ length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
@@ -882,13 +878,11 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
- length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
- GFP_KERNEL);
+ length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
if (length)
goto out;
- length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
- GFP_KERNEL);
+ length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
@@ -940,7 +934,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s", con, user) != 2)
goto out;
- length = security_context_to_sid(con, strlen(con) + 1, &sid, GFP_KERNEL);
+ length = security_context_str_to_sid(con, &sid, GFP_KERNEL);
if (length)
goto out;
@@ -1000,13 +994,11 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out;
- length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
- GFP_KERNEL);
+ length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
if (length)
goto out;
- length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
- GFP_KERNEL);
+ length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
if (length)
goto out;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index b7df12ba61d8..ebb5eb3c318c 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1218,13 +1218,10 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
/*
* Copy the user name, role name and type name into the context.
*/
- sprintf(scontextp, "%s:%s:%s",
+ scontextp += sprintf(scontextp, "%s:%s:%s",
sym_name(&policydb, SYM_USERS, context->user - 1),
sym_name(&policydb, SYM_ROLES, context->role - 1),
sym_name(&policydb, SYM_TYPES, context->type - 1));
- scontextp += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) +
- 1 + strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) +
- 1 + strlen(sym_name(&policydb, SYM_TYPES, context->type - 1));
mls_sid_to_context(context, &scontextp);
@@ -1259,12 +1256,12 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
*scontext_len = strlen(initial_sid_to_string[sid]) + 1;
if (!scontext)
goto out;
- scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
+ scontextp = kmemdup(initial_sid_to_string[sid],
+ *scontext_len, GFP_ATOMIC);
if (!scontextp) {
rc = -ENOMEM;
goto out;
}
- strcpy(scontextp, initial_sid_to_string[sid]);
*scontext = scontextp;
goto out;
}
@@ -1476,6 +1473,11 @@ int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
sid, SECSID_NULL, gfp, 0);
}
+int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
+{
+ return security_context_to_sid(scontext, strlen(scontext), sid, gfp);
+}
+
/**
* security_context_to_sid_default - Obtain a SID for a given security context,
* falling back to specified default if needed.
@@ -2604,18 +2606,12 @@ int security_get_bools(int *len, char ***names, int **values)
goto err;
for (i = 0; i < *len; i++) {
- size_t name_len;
-
(*values)[i] = policydb.bool_val_to_struct[i]->state;
- name_len = strlen(sym_name(&policydb, SYM_BOOLS, i)) + 1;
rc = -ENOMEM;
- (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
+ (*names)[i] = kstrdup(sym_name(&policydb, SYM_BOOLS, i), GFP_ATOMIC);
if (!(*names)[i])
goto err;
-
- strncpy((*names)[i], sym_name(&policydb, SYM_BOOLS, i), name_len);
- (*names)[i][name_len - 1] = 0;
}
rc = 0;
out:
diff --git a/security/smack/smack.h b/security/smack/smack.h
index fff0c612bbb7..6c91156ae225 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -115,6 +115,7 @@ struct task_smack {
struct smack_known *smk_forked; /* label when forked */
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 */
};
#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
@@ -169,7 +170,7 @@ struct smk_port_label {
};
#endif /* SMACK_IPV6_PORT_LABELING */
-struct smack_onlycap {
+struct smack_known_list_elem {
struct list_head list;
struct smack_known *smk_label;
};
@@ -301,6 +302,7 @@ struct smack_known *smk_import_entry(const char *, int);
void smk_insert_entry(struct smack_known *skp);
struct smack_known *smk_find_entry(const char *);
int smack_privileged(int cap);
+void smk_destroy_label_list(struct list_head *list);
/*
* Shared data.
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index bc1053fb5d1d..a283f9e796c1 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -637,7 +637,7 @@ DEFINE_MUTEX(smack_onlycap_lock);
int smack_privileged(int cap)
{
struct smack_known *skp = smk_of_current();
- struct smack_onlycap *sop;
+ struct smack_known_list_elem *sklep;
/*
* All kernel tasks are privileged
@@ -654,8 +654,8 @@ int smack_privileged(int cap)
return 1;
}
- list_for_each_entry_rcu(sop, &smack_onlycap_list, list) {
- if (sop->smk_label == skp) {
+ list_for_each_entry_rcu(sklep, &smack_onlycap_list, list) {
+ if (sklep->smk_label == skp) {
rcu_read_unlock();
return 1;
}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 996c88956438..ff81026f6ddb 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -52,7 +52,7 @@
#define SMK_SENDING 2
#ifdef SMACK_IPV6_PORT_LABELING
-LIST_HEAD(smk_ipv6_port_list);
+static LIST_HEAD(smk_ipv6_port_list);
#endif
static struct kmem_cache *smack_inode_cache;
int smack_enabled;
@@ -326,6 +326,7 @@ static struct task_smack *new_task_smack(struct smack_known *task,
tsp->smk_task = task;
tsp->smk_forked = forked;
INIT_LIST_HEAD(&tsp->smk_rules);
+ INIT_LIST_HEAD(&tsp->smk_relabel);
mutex_init(&tsp->smk_rules_lock);
return tsp;
@@ -361,6 +362,35 @@ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead,
}
/**
+ * smk_copy_relabel - copy smk_relabel labels list
+ * @nhead: new rules header pointer
+ * @ohead: old rules header pointer
+ * @gfp: type of the memory for the allocation
+ *
+ * Returns 0 on success, -ENOMEM on error
+ */
+static int smk_copy_relabel(struct list_head *nhead, struct list_head *ohead,
+ gfp_t gfp)
+{
+ struct smack_known_list_elem *nklep;
+ struct smack_known_list_elem *oklep;
+
+ INIT_LIST_HEAD(nhead);
+
+ list_for_each_entry(oklep, ohead, list) {
+ nklep = kzalloc(sizeof(struct smack_known_list_elem), gfp);
+ if (nklep == NULL) {
+ smk_destroy_label_list(nhead);
+ return -ENOMEM;
+ }
+ nklep->smk_label = oklep->smk_label;
+ list_add(&nklep->list, nhead);
+ }
+
+ return 0;
+}
+
+/**
* smk_ptrace_mode - helper function for converting PTRACE_MODE_* into MAY_*
* @mode - input mode in form of PTRACE_MODE_*
*
@@ -1922,6 +1952,8 @@ static void smack_cred_free(struct cred *cred)
return;
cred->security = NULL;
+ smk_destroy_label_list(&tsp->smk_relabel);
+
list_for_each_safe(l, n, &tsp->smk_rules) {
rp = list_entry(l, struct smack_rule, list);
list_del(&rp->list);
@@ -1953,6 +1985,11 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
if (rc != 0)
return rc;
+ rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel,
+ gfp);
+ if (rc != 0)
+ return rc;
+
new->security = new_tsp;
return 0;
}
@@ -3354,6 +3391,9 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*/
isp->smk_inode = smk_of_current();
break;
+ case PIPEFS_MAGIC:
+ isp->smk_inode = smk_of_current();
+ break;
default:
isp->smk_inode = sbsp->smk_root;
break;
@@ -3549,9 +3589,11 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
static int smack_setprocattr(struct task_struct *p, char *name,
void *value, size_t size)
{
- struct task_smack *tsp;
+ struct task_smack *tsp = current_security();
struct cred *new;
struct smack_known *skp;
+ struct smack_known_list_elem *sklep;
+ int rc;
/*
* Changing another process' Smack value is too dangerous
@@ -3560,7 +3602,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
if (p != current)
return -EPERM;
- if (!smack_privileged(CAP_MAC_ADMIN))
+ if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel))
return -EPERM;
if (value == NULL || size == 0 || size >= SMK_LONGLABEL)
@@ -3579,12 +3621,27 @@ static int smack_setprocattr(struct task_struct *p, char *name,
if (skp == &smack_known_web)
return -EPERM;
+ if (!smack_privileged(CAP_MAC_ADMIN)) {
+ rc = -EPERM;
+ list_for_each_entry(sklep, &tsp->smk_relabel, list)
+ if (sklep->smk_label == skp) {
+ rc = 0;
+ break;
+ }
+ if (rc)
+ return rc;
+ }
+
new = prepare_creds();
if (new == NULL)
return -ENOMEM;
tsp = new->security;
tsp->smk_task = skp;
+ /*
+ * process can change its label only once
+ */
+ smk_destroy_label_list(&tsp->smk_relabel);
commit_creds(new);
return size;
@@ -4708,8 +4765,6 @@ static __init int smack_init(void)
if (!security_module_enable("smack"))
return 0;
- smack_enabled = 1;
-
smack_inode_cache = KMEM_CACHE(inode_smack, 0);
if (!smack_inode_cache)
return -ENOMEM;
@@ -4721,6 +4776,8 @@ static __init int smack_init(void)
return -ENOMEM;
}
+ smack_enabled = 1;
+
pr_info("Smack: Initializing.\n");
#ifdef CONFIG_SECURITY_SMACK_NETFILTER
pr_info("Smack: Netfilter enabled.\n");
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index c20b154a33f2..94bd9e41c9ec 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -61,6 +61,7 @@ enum smk_inos {
#if IS_ENABLED(CONFIG_IPV6)
SMK_NET6ADDR = 23, /* single label IPv6 hosts */
#endif /* CONFIG_IPV6 */
+ SMK_RELABEL_SELF = 24, /* relabel possible without CAP_MAC_ADMIN */
};
/*
@@ -1501,8 +1502,8 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf,
*/
if (smack[0] != '-') {
skp = smk_import_entry(smack, 0);
- if (skp == NULL) {
- rc = -EINVAL;
+ if (IS_ERR(skp)) {
+ rc = PTR_ERR(skp);
goto free_out;
}
} else {
@@ -1914,10 +1915,10 @@ static void *onlycap_seq_next(struct seq_file *s, void *v, loff_t *pos)
static int onlycap_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
- struct smack_onlycap *sop =
- list_entry_rcu(list, struct smack_onlycap, list);
+ struct smack_known_list_elem *sklep =
+ list_entry_rcu(list, struct smack_known_list_elem, list);
- seq_puts(s, sop->smk_label->smk_known);
+ seq_puts(s, sklep->smk_label->smk_known);
seq_putc(s, ' ');
return 0;
@@ -1974,6 +1975,54 @@ static void smk_list_swap_rcu(struct list_head *public,
}
/**
+ * smk_parse_label_list - parse list of Smack labels, separated by spaces
+ *
+ * @data: the string to parse
+ * @private: destination list
+ *
+ * Returns zero on success or error code, as appropriate
+ */
+static int smk_parse_label_list(char *data, struct list_head *list)
+{
+ char *tok;
+ struct smack_known *skp;
+ struct smack_known_list_elem *sklep;
+
+ while ((tok = strsep(&data, " ")) != NULL) {
+ if (!*tok)
+ continue;
+
+ skp = smk_import_entry(tok, 0);
+ if (IS_ERR(skp))
+ return PTR_ERR(skp);
+
+ sklep = kzalloc(sizeof(*sklep), GFP_KERNEL);
+ if (sklep == NULL)
+ return -ENOMEM;
+
+ sklep->smk_label = skp;
+ list_add(&sklep->list, list);
+ }
+
+ return 0;
+}
+
+/**
+ * smk_destroy_label_list - destroy a list of smack_known_list_elem
+ * @head: header pointer of the list to destroy
+ */
+void smk_destroy_label_list(struct list_head *list)
+{
+ struct smack_known_list_elem *sklep;
+ struct smack_known_list_elem *sklep2;
+
+ list_for_each_entry_safe(sklep, sklep2, list, list)
+ kfree(sklep);
+
+ INIT_LIST_HEAD(list);
+}
+
+/**
* smk_write_onlycap - write() for smackfs/onlycap
* @file: file pointer, not actually used
* @buf: where to get the data from
@@ -1986,13 +2035,8 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char *data;
- char *data_parse;
- char *tok;
- struct smack_known *skp;
- struct smack_onlycap *sop;
- struct smack_onlycap *sop2;
LIST_HEAD(list_tmp);
- int rc = count;
+ int rc;
if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
@@ -2006,26 +2050,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
return -EFAULT;
}
- data_parse = data;
- while ((tok = strsep(&data_parse, " ")) != NULL) {
- if (!*tok)
- continue;
-
- skp = smk_import_entry(tok, 0);
- if (IS_ERR(skp)) {
- rc = PTR_ERR(skp);
- break;
- }
-
- sop = kzalloc(sizeof(*sop), GFP_KERNEL);
- if (sop == NULL) {
- rc = -ENOMEM;
- break;
- }
-
- sop->smk_label = skp;
- list_add_rcu(&sop->list, &list_tmp);
- }
+ rc = smk_parse_label_list(data, &list_tmp);
kfree(data);
/*
@@ -2038,17 +2063,14 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
* But do so only on invalid label, not on system errors.
* The invalid label must be first to count as clearing attempt.
*/
- if (rc == -EINVAL && list_empty(&list_tmp))
- rc = count;
-
- if (rc >= 0) {
+ if (!rc || (rc == -EINVAL && list_empty(&list_tmp))) {
mutex_lock(&smack_onlycap_lock);
smk_list_swap_rcu(&smack_onlycap_list, &list_tmp);
mutex_unlock(&smack_onlycap_lock);
+ rc = count;
}
- list_for_each_entry_safe(sop, sop2, &list_tmp, list)
- kfree(sop);
+ smk_destroy_label_list(&list_tmp);
return rc;
}
@@ -2698,6 +2720,113 @@ static const struct file_operations smk_syslog_ops = {
.llseek = default_llseek,
};
+/*
+ * Seq_file read operations for /smack/relabel-self
+ */
+
+static void *relabel_self_seq_start(struct seq_file *s, loff_t *pos)
+{
+ struct task_smack *tsp = current_security();
+
+ return smk_seq_start(s, pos, &tsp->smk_relabel);
+}
+
+static void *relabel_self_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ struct task_smack *tsp = current_security();
+
+ return smk_seq_next(s, v, pos, &tsp->smk_relabel);
+}
+
+static int relabel_self_seq_show(struct seq_file *s, void *v)
+{
+ struct list_head *list = v;
+ struct smack_known_list_elem *sklep =
+ list_entry(list, struct smack_known_list_elem, list);
+
+ seq_puts(s, sklep->smk_label->smk_known);
+ seq_putc(s, ' ');
+
+ return 0;
+}
+
+static const struct seq_operations relabel_self_seq_ops = {
+ .start = relabel_self_seq_start,
+ .next = relabel_self_seq_next,
+ .show = relabel_self_seq_show,
+ .stop = smk_seq_stop,
+};
+
+/**
+ * smk_open_relabel_self - open() for /smack/relabel-self
+ * @inode: inode structure representing file
+ * @file: "relabel-self" file pointer
+ *
+ * Connect our relabel_self_seq_* operations with /smack/relabel-self
+ * file_operations
+ */
+static int smk_open_relabel_self(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &relabel_self_seq_ops);
+}
+
+/**
+ * smk_write_relabel_self - write() for /smack/relabel-self
+ * @file: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start - must be 0
+ *
+ */
+static ssize_t smk_write_relabel_self(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_smack *tsp = current_security();
+ char *data;
+ int rc;
+ LIST_HEAD(list_tmp);
+
+ /*
+ * Must have privilege.
+ */
+ if (!smack_privileged(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ /*
+ * Enough data must be present.
+ */
+ if (*ppos != 0)
+ return -EINVAL;
+
+ data = kzalloc(count + 1, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(data, buf, count) != 0) {
+ kfree(data);
+ return -EFAULT;
+ }
+
+ rc = smk_parse_label_list(data, &list_tmp);
+ kfree(data);
+
+ if (!rc || (rc == -EINVAL && list_empty(&list_tmp))) {
+ smk_destroy_label_list(&tsp->smk_relabel);
+ list_splice(&list_tmp, &tsp->smk_relabel);
+ return count;
+ }
+
+ smk_destroy_label_list(&list_tmp);
+ return rc;
+}
+
+static const struct file_operations smk_relabel_self_ops = {
+ .open = smk_open_relabel_self,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .write = smk_write_relabel_self,
+ .release = seq_release,
+};
/**
* smk_read_ptrace - read() for /smack/ptrace
@@ -2824,6 +2953,9 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
[SMK_NET6ADDR] = {
"ipv6host", &smk_net6addr_ops, S_IRUGO|S_IWUSR},
#endif /* CONFIG_IPV6 */
+ [SMK_RELABEL_SELF] = {
+ "relabel-self", &smk_relabel_self_ops,
+ S_IRUGO|S_IWUGO},
/* last one */
{""}
};
@@ -2892,7 +3024,7 @@ static int __init init_smk_fs(void)
int err;
int rc;
- if (!security_module_enable("smack"))
+ if (smack_enabled == 0)
return 0;
err = smk_init_sysfs();