summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-12 10:13:55 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-12 10:13:55 -0400
commit5e40d331bd72447197f26525f21711c4a265b6a6 (patch)
treecfbf5efba46b0c5c5b3c8149395f721eab839945 /security
parentd0ca47575ab3b41bb7f0fe5feec13c6cddb2913a (diff)
parent594081ee7145cc30a3977cb4e218f81213b63dc5 (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris. Mostly ima, selinux, smack and key handling updates. * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (65 commits) integrity: do zero padding of the key id KEYS: output last portion of fingerprint in /proc/keys KEYS: strip 'id:' from ca_keyid KEYS: use swapped SKID for performing partial matching KEYS: Restore partial ID matching functionality for asymmetric keys X.509: If available, use the raw subjKeyId to form the key description KEYS: handle error code encoded in pointer selinux: normalize audit log formatting selinux: cleanup error reporting in selinux_nlmsg_perm() KEYS: Check hex2bin()'s return when generating an asymmetric key ID ima: detect violations for mmaped files ima: fix race condition on ima_rdwr_violation_check and process_measurement ima: added ima_policy_flag variable ima: return an error code from ima_add_boot_aggregate() ima: provide 'ima_appraise=log' kernel option ima: move keyring initialization to ima_init() PKCS#7: Handle PKCS#7 messages that contain no X.509 certs PKCS#7: Better handling of unsupported crypto KEYS: Overhaul key identification when searching for asymmetric keys KEYS: Implement binary asymmetric key ID handling ...
Diffstat (limited to 'security')
-rw-r--r--security/integrity/Kconfig46
-rw-r--r--security/integrity/Makefile6
-rw-r--r--security/integrity/digsig_asymmetric.c7
-rw-r--r--security/integrity/evm/Kconfig8
-rw-r--r--security/integrity/evm/evm_main.c17
-rw-r--r--security/integrity/ima/Kconfig2
-rw-r--r--security/integrity/ima/ima.h24
-rw-r--r--security/integrity/ima/ima_api.c10
-rw-r--r--security/integrity/ima/ima_appraise.c17
-rw-r--r--security/integrity/ima/ima_crypto.c20
-rw-r--r--security/integrity/ima/ima_init.c25
-rw-r--r--security/integrity/ima/ima_main.c123
-rw-r--r--security/integrity/ima/ima_policy.c23
-rw-r--r--security/integrity/ima/ima_template.c30
-rw-r--r--security/integrity/integrity.h2
-rw-r--r--security/keys/big_key.c2
-rw-r--r--security/keys/encrypted-keys/encrypted.c1
-rw-r--r--security/keys/internal.h21
-rw-r--r--security/keys/key.c2
-rw-r--r--security/keys/keyctl.c2
-rw-r--r--security/keys/keyring.c58
-rw-r--r--security/keys/proc.c8
-rw-r--r--security/keys/process_keys.c13
-rw-r--r--security/keys/request_key.c21
-rw-r--r--security/keys/request_key_auth.c10
-rw-r--r--security/keys/trusted.c1
-rw-r--r--security/keys/user_defined.c14
-rw-r--r--security/selinux/hooks.c135
-rw-r--r--security/selinux/include/netif.h4
-rw-r--r--security/selinux/include/objsec.h2
-rw-r--r--security/selinux/netif.c43
-rw-r--r--security/selinux/ss/services.c14
-rw-r--r--security/smack/Kconfig16
-rw-r--r--security/smack/smack.h39
-rw-r--r--security/smack/smack_access.c118
-rw-r--r--security/smack/smack_lsm.c545
-rw-r--r--security/smack/smackfs.c76
37 files changed, 912 insertions, 593 deletions
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
index 245c6d92065..b76235ae478 100644
--- a/security/integrity/Kconfig
+++ b/security/integrity/Kconfig
@@ -1,11 +1,23 @@
#
config INTEGRITY
- def_bool y
- depends on IMA || EVM
+ bool "Integrity subsystem"
+ depends on SECURITY
+ default y
+ help
+ This option enables the integrity subsystem, which is comprised
+ of a number of different components including the Integrity
+ Measurement Architecture (IMA), Extended Verification Module
+ (EVM), IMA-appraisal extension, digital signature verification
+ extension and audit measurement log support.
+
+ Each of these components can be enabled/disabled separately.
+ Refer to the individual components for additional details.
+
+if INTEGRITY
config INTEGRITY_SIGNATURE
boolean "Digital signature verification using multiple keyrings"
- depends on INTEGRITY && KEYS
+ depends on KEYS
default n
select SIGNATURE
help
@@ -17,9 +29,21 @@ config INTEGRITY_SIGNATURE
This is useful for evm and module keyrings, when keys are
usually only added from initramfs.
+config INTEGRITY_ASYMMETRIC_KEYS
+ boolean "Enable asymmetric keys support"
+ depends on INTEGRITY_SIGNATURE
+ default n
+ select ASYMMETRIC_KEY_TYPE
+ select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+ select PUBLIC_KEY_ALGO_RSA
+ select X509_CERTIFICATE_PARSER
+ help
+ This option enables digital signature verification using
+ asymmetric keys.
+
config INTEGRITY_AUDIT
bool "Enables integrity auditing support "
- depends on INTEGRITY && AUDIT
+ depends on AUDIT
default y
help
In addition to enabling integrity auditing support, this
@@ -32,17 +56,7 @@ config INTEGRITY_AUDIT
be enabled by specifying 'integrity_audit=1' on the kernel
command line.
-config INTEGRITY_ASYMMETRIC_KEYS
- boolean "Enable asymmetric keys support"
- depends on INTEGRITY_SIGNATURE
- default n
- select ASYMMETRIC_KEY_TYPE
- select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
- select PUBLIC_KEY_ALGO_RSA
- select X509_CERTIFICATE_PARSER
- help
- This option enables digital signature verification using
- asymmetric keys.
-
source security/integrity/ima/Kconfig
source security/integrity/evm/Kconfig
+
+endif # if INTEGRITY
diff --git a/security/integrity/Makefile b/security/integrity/Makefile
index 0793f4811cb..8d1f4bf5108 100644
--- a/security/integrity/Makefile
+++ b/security/integrity/Makefile
@@ -3,11 +3,11 @@
#
obj-$(CONFIG_INTEGRITY) += integrity.o
-obj-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
-obj-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
-obj-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
integrity-y := iint.o
+integrity-$(CONFIG_INTEGRITY_AUDIT) += integrity_audit.o
+integrity-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
+integrity-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
subdir-$(CONFIG_IMA) += ima
obj-$(CONFIG_IMA) += ima/
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index 9eae4809006..4fec1816a2b 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -13,6 +13,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/err.h>
+#include <linux/ratelimit.h>
#include <linux/key-type.h>
#include <crypto/public_key.h>
#include <keys/asymmetric-type.h>
@@ -27,7 +28,7 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
struct key *key;
char name[12];
- sprintf(name, "id:%x", keyid);
+ sprintf(name, "id:%08x", keyid);
pr_debug("key search: \"%s\"\n", name);
@@ -45,8 +46,8 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
}
if (IS_ERR(key)) {
- pr_warn("Request for unknown key '%s' err %ld\n",
- name, PTR_ERR(key));
+ pr_err_ratelimited("Request for unknown key '%s' err %ld\n",
+ name, PTR_ERR(key));
switch (PTR_ERR(key)) {
/* Hide some search errors */
case -EACCES:
diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig
index d606f3d12d6..df586fa00ef 100644
--- a/security/integrity/evm/Kconfig
+++ b/security/integrity/evm/Kconfig
@@ -1,6 +1,5 @@
config EVM
boolean "EVM support"
- depends on SECURITY
select KEYS
select ENCRYPTED_KEYS
select CRYPTO_HMAC
@@ -12,10 +11,6 @@ config EVM
If you are unsure how to answer this question, answer N.
-if EVM
-
-menu "EVM options"
-
config EVM_ATTR_FSUUID
bool "FSUUID (version 2)"
default y
@@ -47,6 +42,3 @@ config EVM_EXTRA_SMACK_XATTRS
additional info to the calculation, requires existing EVM
labeled file systems to be relabeled.
-endmenu
-
-endif
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 3bcb80df4d0..9685af330de 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -126,14 +126,15 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0,
GFP_NOFS);
if (rc <= 0) {
- if (rc == 0)
- evm_status = INTEGRITY_FAIL; /* empty */
- else if (rc == -ENODATA) {
+ evm_status = INTEGRITY_FAIL;
+ if (rc == -ENODATA) {
rc = evm_find_protected_xattrs(dentry);
if (rc > 0)
evm_status = INTEGRITY_NOLABEL;
else if (rc == 0)
evm_status = INTEGRITY_NOXATTRS; /* new file */
+ } else if (rc == -EOPNOTSUPP) {
+ evm_status = INTEGRITY_UNKNOWN;
}
goto out;
}
@@ -284,6 +285,13 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
goto out;
}
evm_status = evm_verify_current_integrity(dentry);
+ if (evm_status == INTEGRITY_NOXATTRS) {
+ struct integrity_iint_cache *iint;
+
+ iint = integrity_iint_find(dentry->d_inode);
+ if (iint && (iint->flags & IMA_NEW_FILE))
+ return 0;
+ }
out:
if (evm_status != INTEGRITY_PASS)
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, dentry->d_inode,
@@ -352,7 +360,6 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
return;
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
- return;
}
/**
@@ -372,7 +379,6 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
mutex_lock(&inode->i_mutex);
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
mutex_unlock(&inode->i_mutex);
- return;
}
/**
@@ -414,7 +420,6 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
evm_update_evmxattr(dentry, NULL, NULL, 0);
- return;
}
/*
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 08758fbd496..e099875643c 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -2,8 +2,6 @@
#
config IMA
bool "Integrity Measurement Architecture(IMA)"
- depends on SECURITY
- select INTEGRITY
select SECURITYFS
select CRYPTO
select CRYPTO_HMAC
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 57da4bd7ba0..8ee997dff13 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -43,6 +43,9 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 = 8 };
#define IMA_TEMPLATE_IMA_NAME "ima"
#define IMA_TEMPLATE_IMA_FMT "d|n"
+/* current content of the policy */
+extern int ima_policy_flag;
+
/* set during initialization */
extern int ima_initialized;
extern int ima_used_chip;
@@ -90,10 +93,7 @@ extern struct list_head ima_measurements; /* list of all measurements */
/* Internal IMA function definitions */
int ima_init(void);
-void ima_cleanup(void);
int ima_fs_init(void);
-void ima_fs_cleanup(void);
-int ima_inode_alloc(struct inode *inode);
int ima_add_template_entry(struct ima_template_entry *entry, int violation,
const char *op, struct inode *inode,
const unsigned char *filename);
@@ -110,8 +110,6 @@ void ima_print_digest(struct seq_file *m, u8 *digest, int size);
struct ima_template_desc *ima_template_desc_current(void);
int ima_init_template(void);
-int ima_init_template(void);
-
/*
* used to protect h_table and sha_table
*/
@@ -151,12 +149,6 @@ int ima_store_template(struct ima_template_entry *entry, int violation,
void ima_free_template_entry(struct ima_template_entry *entry);
const char *ima_d_path(struct path *path, char **pathbuf);
-/* rbtree tree calls to lookup, insert, delete
- * integrity data associated with an inode.
- */
-struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
-struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
-
/* IMA policy related functions */
enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, FIRMWARE_CHECK, POST_SETATTR };
@@ -164,20 +156,22 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
int flags);
void ima_init_policy(void);
void ima_update_policy(void);
+void ima_update_policy_flag(void);
ssize_t ima_parse_add_rule(char *);
void ima_delete_rules(void);
/* Appraise integrity measurements */
#define IMA_APPRAISE_ENFORCE 0x01
#define IMA_APPRAISE_FIX 0x02
-#define IMA_APPRAISE_MODULES 0x04
-#define IMA_APPRAISE_FIRMWARE 0x08
+#define IMA_APPRAISE_LOG 0x04
+#define IMA_APPRAISE_MODULES 0x08
+#define IMA_APPRAISE_FIRMWARE 0x10
#ifdef CONFIG_IMA_APPRAISE
int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
- int xattr_len);
+ int xattr_len, int opened);
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
@@ -193,7 +187,7 @@ static inline int ima_appraise_measurement(int func,
struct file *file,
const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
- int xattr_len)
+ int xattr_len, int opened)
{
return INTEGRITY_UNKNOWN;
}
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index d9cd5ce14d2..86885979918 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -179,11 +179,6 @@ int ima_get_action(struct inode *inode, int mask, int function)
return ima_match_policy(inode, function, mask, flags);
}
-int ima_must_measure(struct inode *inode, int mask, int function)
-{
- return ima_match_policy(inode, function, mask, IMA_MEASURE);
-}
-
/*
* ima_collect_measurement - collect file measurement
*
@@ -330,10 +325,9 @@ const char *ima_d_path(struct path *path, char **pathbuf)
{
char *pathname = NULL;
- /* We will allow 11 spaces for ' (deleted)' to be appended */
- *pathbuf = kmalloc(PATH_MAX + 11, GFP_KERNEL);
+ *pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
if (*pathbuf) {
- pathname = d_path(path, *pathbuf, PATH_MAX + 11);
+ pathname = d_absolute_path(path, *pathbuf, PATH_MAX);
if (IS_ERR(pathname)) {
kfree(*pathbuf);
*pathbuf = NULL;
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 86bfd5c5df8..922685483bd 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -23,6 +23,8 @@ static int __init default_appraise_setup(char *str)
{
if (strncmp(str, "off", 3) == 0)
ima_appraise = 0;
+ else if (strncmp(str, "log", 3) == 0)
+ ima_appraise = IMA_APPRAISE_LOG;
else if (strncmp(str, "fix", 3) == 0)
ima_appraise = IMA_APPRAISE_FIX;
return 1;
@@ -183,7 +185,7 @@ int ima_read_xattr(struct dentry *dentry,
int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
- int xattr_len)
+ int xattr_len, int opened)
{
static const char op[] = "appraise_data";
char *cause = "unknown";
@@ -192,8 +194,6 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
enum integrity_status status = INTEGRITY_UNKNOWN;
int rc = xattr_len, hash_start = 0;
- if (!ima_appraise)
- return 0;
if (!inode->i_op->getxattr)
return INTEGRITY_UNKNOWN;
@@ -202,8 +202,11 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
goto out;
cause = "missing-hash";
- status =
- (inode->i_size == 0) ? INTEGRITY_PASS : INTEGRITY_NOLABEL;
+ status = INTEGRITY_NOLABEL;
+ if (opened & FILE_CREATED) {
+ iint->flags |= IMA_NEW_FILE;
+ status = INTEGRITY_PASS;
+ }
goto out;
}
@@ -315,7 +318,7 @@ void ima_inode_post_setattr(struct dentry *dentry)
struct integrity_iint_cache *iint;
int must_appraise, rc;
- if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode)
+ if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
|| !inode->i_op->removexattr)
return;
@@ -353,7 +356,7 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
{
struct integrity_iint_cache *iint;
- if (!ima_initialized || !ima_appraise || !S_ISREG(inode->i_mode))
+ if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode))
return;
iint = integrity_iint_find(inode);
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index 0bd732843fe..d34e7dfc111 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -80,24 +80,24 @@ static int ima_kernel_read(struct file *file, loff_t offset,
{
mm_segment_t old_fs;
char __user *buf = addr;
- ssize_t ret;
+ ssize_t ret = -EINVAL;
if (!(file->f_mode & FMODE_READ))
return -EBADF;
- if (!file->f_op->read && !file->f_op->aio_read)
- return -EINVAL;
old_fs = get_fs();
set_fs(get_ds());
if (file->f_op->read)
ret = file->f_op->read(file, buf, count, &offset);
- else
+ else if (file->f_op->aio_read)
ret = do_sync_read(file, buf, count, &offset);
+ else if (file->f_op->read_iter)
+ ret = new_sync_read(file, buf, count, &offset);
set_fs(old_fs);
return ret;
}
-int ima_init_crypto(void)
+int __init ima_init_crypto(void)
{
long rc;
@@ -116,7 +116,10 @@ static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo)
struct crypto_shash *tfm = ima_shash_tfm;
int rc;
- if (algo != ima_hash_algo && algo < HASH_ALGO__LAST) {
+ if (algo < 0 || algo >= HASH_ALGO__LAST)
+ algo = ima_hash_algo;
+
+ if (algo != ima_hash_algo) {
tfm = crypto_alloc_shash(hash_algo_name[algo], 0, 0);
if (IS_ERR(tfm)) {
rc = PTR_ERR(tfm);
@@ -200,7 +203,10 @@ static struct crypto_ahash *ima_alloc_atfm(enum hash_algo algo)
struct crypto_ahash *tfm = ima_ahash_tfm;
int rc;
- if ((algo != ima_hash_algo && algo < HASH_ALGO__LAST) || !tfm) {
+ if (algo < 0 || algo >= HASH_ALGO__LAST)
+ algo = ima_hash_algo;
+
+ if (algo != ima_hash_algo || !tfm) {
tfm = crypto_alloc_ahash(hash_algo_name[algo], 0, 0);
if (!IS_ERR(tfm)) {
if (algo == ima_hash_algo)
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index e8f9d70a465..9164fc8cac8 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -43,7 +43,7 @@ int ima_used_chip;
* a different value.) Violations add a zero entry to the measurement
* list and extend the aggregate PCR value with ff...ff's.
*/
-static void __init ima_add_boot_aggregate(void)
+static int __init ima_add_boot_aggregate(void)
{
static const char op[] = "add_boot_aggregate";
const char *audit_cause = "ENOMEM";
@@ -72,17 +72,23 @@ static void __init ima_add_boot_aggregate(void)
result = ima_alloc_init_template(iint, NULL, boot_aggregate_name,
NULL, 0, &entry);
- if (result < 0)
- return;
+ if (result < 0) {
+ audit_cause = "alloc_entry";
+ goto err_out;
+ }
result = ima_store_template(entry, violation, NULL,
boot_aggregate_name);
- if (result < 0)
+ if (result < 0) {
ima_free_template_entry(entry);
- return;
+ audit_cause = "store_entry";
+ goto err_out;
+ }
+ return 0;
err_out:
integrity_audit_msg(AUDIT_INTEGRITY_PCR, NULL, boot_aggregate_name, op,
audit_cause, result, 0);
+ return result;
}
int __init ima_init(void)
@@ -98,6 +104,10 @@ int __init ima_init(void)
if (!ima_used_chip)
pr_info("No TPM chip found, activating TPM-bypass!\n");
+ rc = ima_init_keyring(INTEGRITY_KEYRING_IMA);
+ if (rc)
+ return rc;
+
rc = ima_init_crypto();
if (rc)
return rc;
@@ -105,7 +115,10 @@ int __init ima_init(void)
if (rc != 0)
return rc;
- ima_add_boot_aggregate(); /* boot aggregate must be first entry */
+ rc = ima_add_boot_aggregate(); /* boot aggregate must be first entry */
+ if (rc != 0)
+ return rc;
+
ima_init_policy();
return ima_fs_init();
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 2917f980bf3..62f59eca32d 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -77,42 +77,39 @@ __setup("ima_hash=", hash_setup);
* could result in a file measurement error.
*
*/
-static void ima_rdwr_violation_check(struct file *file)
+static void ima_rdwr_violation_check(struct file *file,
+ struct integrity_iint_cache *iint,
+ int must_measure,
+ char **pathbuf,
+ const char **pathname)
{
struct inode *inode = file_inode(file);
fmode_t mode = file->f_mode;
bool send_tomtou = false, send_writers = false;
- char *pathbuf = NULL;
- const char *pathname;
-
- if (!S_ISREG(inode->i_mode) || !ima_initialized)
- return;
if (mode & FMODE_WRITE) {
if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
- struct integrity_iint_cache *iint;
- iint = integrity_iint_find(inode);
+ if (!iint)
+ iint = integrity_iint_find(inode);
/* IMA_MEASURE is set from reader side */
if (iint && (iint->flags & IMA_MEASURE))
send_tomtou = true;
}
} else {
- if ((atomic_read(&inode->i_writecount) > 0) &&
- ima_must_measure(inode, MAY_READ, FILE_CHECK))
+ if ((atomic_read(&inode->i_writecount) > 0) && must_measure)
send_writers = true;
}
if (!send_tomtou && !send_writers)
return;
- pathname = ima_d_path(&file->f_path, &pathbuf);
+ *pathname = ima_d_path(&file->f_path, pathbuf);
if (send_tomtou)
- ima_add_violation(file, pathname, "invalid_pcr", "ToMToU");
+ ima_add_violation(file, *pathname, "invalid_pcr", "ToMToU");
if (send_writers)
- ima_add_violation(file, pathname,
+ ima_add_violation(file, *pathname,
"invalid_pcr", "open_writers");
- kfree(pathbuf);
}
static void ima_check_last_writer(struct integrity_iint_cache *iint,
@@ -124,11 +121,13 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
return;
mutex_lock(&inode->i_mutex);
- if (atomic_read(&inode->i_writecount) == 1 &&
- iint->version != inode->i_version) {
- iint->flags &= ~IMA_DONE_MASK;
- if (iint->flags & IMA_APPRAISE)
- ima_update_xattr(iint, file);
+ if (atomic_read(&inode->i_writecount) == 1) {
+ if ((iint->version != inode->i_version) ||
+ (iint->flags & IMA_NEW_FILE)) {
+ iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);
+ if (iint->flags & IMA_APPRAISE)
+ ima_update_xattr(iint, file);
+ }
}
mutex_unlock(&inode->i_mutex);
}
@@ -154,19 +153,20 @@ void ima_file_free(struct file *file)
ima_check_last_writer(iint, inode, file);
}
-static int process_measurement(struct file *file, const char *filename,
- int mask, int function)
+static int process_measurement(struct file *file, int mask, int function,
+ int opened)
{
struct inode *inode = file_inode(file);
- struct integrity_iint_cache *iint;
+ struct integrity_iint_cache *iint = NULL;
struct ima_template_desc *template_desc;
char *pathbuf = NULL;
const char *pathname = NULL;
- int rc = -ENOMEM, action, must_appraise, _func;
+ int rc = -ENOMEM, action, must_appraise;
struct evm_ima_xattr_data *xattr_value = NULL, **xattr_ptr = NULL;
int xattr_len = 0;
+ bool violation_check;
- if (!ima_initialized || !S_ISREG(inode->i_mode))
+ if (!ima_policy_flag || !S_ISREG(inode->i_mode))
return 0;
/* Return an IMA_MEASURE, IMA_APPRAISE, IMA_AUDIT action
@@ -174,19 +174,33 @@ static int process_measurement(struct file *file, const char *filename,
* Included is the appraise submask.
*/
action = ima_get_action(inode, mask, function);
- if (!action)
+ violation_check = ((function == FILE_CHECK || function == MMAP_CHECK) &&
+ (ima_policy_flag & IMA_MEASURE));
+ if (!action && !violation_check)
return 0;
must_appraise = action & IMA_APPRAISE;
/* Is the appraise rule hook specific? */
- _func = (action & IMA_FILE_APPRAISE) ? FILE_CHECK : function;
+ if (action & IMA_FILE_APPRAISE)
+ function = FILE_CHECK;
mutex_lock(&inode->i_mutex);
- iint = integrity_inode_get(inode);
- if (!iint)
- goto out;
+ if (action) {
+ iint = integrity_inode_get(inode);
+ if (!iint)
+ goto out;
+ }
+
+ if (violation_check) {
+ ima_rdwr_violation_check(file, iint, action & IMA_MEASURE,
+ &pathbuf, &pathname);
+ if (!action) {
+ rc = 0;
+ goto out_free;
+ }
+ }
/* Determine if already appraised/measured based on bitmask
* (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED,
@@ -199,15 +213,13 @@ static int process_measurement(struct file *file, const char *filename,
/* Nothing to do, just return existing appraised status */
if (!action) {
if (must_appraise)
- rc = ima_get_cache_status(iint, _func);
+ rc = ima_get_cache_status(iint, function);
goto out_digsig;
}
template_desc = ima_template_desc_current();
- if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) {
- if (action & IMA_APPRAISE_SUBMASK)
- xattr_ptr = &xattr_value;
- } else
+ if ((action & IMA_APPRAISE_SUBMASK) ||
+ strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) != 0)
xattr_ptr = &xattr_value;
rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len);
@@ -217,23 +229,26 @@ static int process_measurement(struct file *file, const char *filename,
goto out_digsig;
}
- pathname = filename ?: ima_d_path(&file->f_path, &pathbuf);
+ if (!pathname) /* ima_rdwr_violation possibly pre-fetched */
+ pathname = ima_d_path(&file->f_path, &pathbuf);
if (action & IMA_MEASURE)
ima_store_measurement(iint, file, pathname,
xattr_value, xattr_len);
if (action & IMA_APPRAISE_SUBMASK)
- rc = ima_appraise_measurement(_func, iint, file, pathname,
- xattr_value, xattr_len);
+ rc = ima_appraise_measurement(function, iint, file, pathname,
+ xattr_value, xattr_len, opened);
if (action & IMA_AUDIT)
ima_audit_measurement(iint, pathname);
- kfree(pathbuf);
+
out_digsig:
if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG))
rc = -EACCES;
+ kfree(xattr_value);
+out_free:
+ kfree(pathbuf);
out:
mutex_unlock(&inode->i_mutex);
- kfree(xattr_value);
if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
return -EACCES;
return 0;
@@ -253,7 +268,7 @@ out:
int ima_file_mmap(struct file *file, unsigned long prot)
{
if (file && (prot & PROT_EXEC))
- return process_measurement(file, NULL, MAY_EXEC, MMAP_CHECK);
+ return process_measurement(file, MAY_EXEC, MMAP_CHECK, 0);
return 0;
}
@@ -272,10 +287,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
*/
int ima_bprm_check(struct linux_binprm *bprm)
{
- return process_measurement(bprm->file,
- (strcmp(bprm->filename, bprm->interp) == 0) ?
- bprm->filename : bprm->interp,
- MAY_EXEC, BPRM_CHECK);
+ return process_measurement(bprm->file, MAY_EXEC, BPRM_CHECK, 0);
}
/**
@@ -288,12 +300,11 @@ int ima_bprm_check(struct linux_binprm *bprm)
* On success return 0. On integrity appraisal error, assuming the file
* is in policy and IMA-appraisal is in enforcing mode, return -EACCES.
*/
-int ima_file_check(struct file *file, int mask)
+int ima_file_check(struct file *file, int mask, int opened)
{
- ima_rdwr_violation_check(file);
- return process_measurement(file, NULL,
+ return process_measurement(file,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
- FILE_CHECK);
+ FILE_CHECK, opened);
}
EXPORT_SYMBOL_GPL(ima_file_check);
@@ -316,7 +327,7 @@ int ima_module_check(struct file *file)
#endif
return 0; /* We rely on module signature checking */
}
- return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK);
+ return process_measurement(file, MAY_EXEC, MODULE_CHECK, 0);
}
int ima_fw_from_file(struct file *file, char *buf, size_t size)
@@ -327,7 +338,7 @@ int ima_fw_from_file(struct file *file, char *buf, size_t size)
return -EACCES; /* INTEGRITY_UNKNOWN */
return 0;
}
- return process_measurement(file, NULL, MAY_EXEC, FIRMWARE_CHECK);
+ return process_measurement(file, MAY_EXEC, FIRMWARE_CHECK, 0);
}
static int __init init_ima(void)
@@ -336,14 +347,10 @@ static int __init init_ima(void)
hash_setup(CONFIG_IMA_DEFAULT_HASH);
error = ima_init();
- if (error)
- goto out;
-
- error = ima_init_keyring(INTEGRITY_KEYRING_IMA);
- if (error)
- goto out;
- ima_initialized = 1;
-out:
+ if (!error) {
+ ima_initialized = 1;
+ ima_update_policy_flag();
+ }
return error;
}
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 07099a8bc28..cdc620b2152 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -35,6 +35,8 @@
#define DONT_APPRAISE 0x0008
#define AUDIT 0x0040
+int ima_policy_flag;
+
#define MAX_LSM_RULES 6
enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
@@ -295,6 +297,26 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
return action;
}
+/*
+ * Initialize the ima_policy_flag variable based on the currently
+ * loaded policy. Based on this flag, the decision to short circuit
+ * out of a function or not call the function in the first place
+ * can be made earlier.
+ */
+void ima_update_policy_flag(void)
+{
+ struct ima_rule_entry *entry;
+
+ ima_policy_flag = 0;
+ list_for_each_entry(entry, ima_rules, list) {
+ if (entry->action & IMA_DO_MASK)
+ ima_policy_flag |= entry->action;
+ }
+
+ if (!ima_appraise)
+ ima_policy_flag &= ~IMA_APPRAISE;
+}
+
/**
* ima_init_policy - initialize the default measure rules.
*
@@ -341,6 +363,7 @@ void ima_update_policy(void)
if (ima_rules == &ima_default_rules) {
ima_rules = &ima_policy_rules;
+ ima_update_policy_flag();
cause = "complete";
result = 0;
}
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index a076a967ec4..e854862c933 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -152,24 +152,6 @@ out:
return result;
}
-static int init_defined_templates(void)
-{
- int i = 0;
- int result = 0;
-
- /* Init defined templates. */
- for (i = 0; i < ARRAY_SIZE(defined_templates); i++) {
- struct ima_template_desc *template = &defined_templates[i];
-
- result = template_desc_init_fields(template->fmt,
- &(template->fields),
- &(template->num_fields));
- if (result < 0)
- return result;
- }
- return result;
-}
-
struct ima_template_desc *ima_template_desc_current(void)
{
if (!ima_template)
@@ -178,13 +160,11 @@ struct ima_template_desc *ima_template_desc_current(void)
return ima_template;
}
-int ima_init_template(void)
+int __init ima_init_template(void)
{
- int result;
-
- result = init_defined_templates();
- if (result < 0)
- return result;
+ struct ima_template_desc *template = ima_template_desc_current();
- return 0;
+ return template_desc_init_fields(template->fmt,
+ &(template->fields),
+ &(template->num_fields));
}
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 19b8e314ca9..c0379d13dbe 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -31,6 +31,7 @@
#define IMA_DIGSIG 0x01000000
#define IMA_DIGSIG_REQUIRED 0x02000000
#define IMA_PERMIT_DIRECTIO 0x04000000
+#define IMA_NEW_FILE 0x08000000
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
IMA_APPRAISE_SUBMASK)
@@ -116,7 +117,6 @@ struct integrity_iint_cache {
/* rbtree tree calls to lookup, insert, delete
* integrity data associated with an inode.
*/
-struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
#define INTEGRITY_KEYRING_EVM 0
diff --git a/security/keys/big_key.c b/security/keys/big_key.c
index c2f91a0cf88..b6adb94f6d5 100644
--- a/security/keys/big_key.c
+++ b/security/keys/big_key.c
@@ -33,11 +33,9 @@ MODULE_LICENSE("GPL");
*/
struct key_type key_type_big_key = {
.name = "big_key",
- .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.preparse = big_key_preparse,
.free_preparse = big_key_free_preparse,
.instantiate = generic_key_instantiate,
- .match = user_match,
.revoke = big_key_revoke,
.destroy = big_key_destroy,
.describe = big_key_describe,
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index 5fe443d120a..db9675db102 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -970,7 +970,6 @@ struct key_type key_type_encrypted = {
.name = "encrypted",
.instantiate = encrypted_instantiate,
.update = encrypted_update,
- .match = user_match,
.destroy = encrypted_destroy,
.describe = user_describe,
.read = encrypted_read,
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 5f20da01fd8..b8960c4959a 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -107,20 +107,16 @@ extern int iterate_over_keyring(const struct key *keyring,
int (*func)(const struct key *key, void *data),
void *data);
-typedef int (*key_match_func_t)(const struct key *, const void *);
-
struct keyring_search_context {
struct keyring_index_key index_key;
const struct cred *cred;
- key_match_func_t match;
- const void *match_data;
+ struct key_match_data match_data;
unsigned flags;
-#define KEYRING_SEARCH_LOOKUP_TYPE 0x0001 /* [as type->def_lookup_type] */
-#define KEYRING_SEARCH_NO_STATE_CHECK 0x0002 /* Skip state checks */
-#define KEYRING_SEARCH_DO_STATE_CHECK 0x0004 /* Override NO_STATE_CHECK */
-#define KEYRING_SEARCH_NO_UPDATE_TIME 0x0008 /* Don't update times */
-#define KEYRING_SEARCH_NO_CHECK_PERM 0x0010 /* Don't check permissions */
-#define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0020 /* Give an error on excessive depth */
+#define KEYRING_SEARCH_NO_STATE_CHECK 0x0001 /* Skip state checks */
+#define KEYRING_SEARCH_DO_STATE_CHECK 0x0002 /* Override NO_STATE_CHECK */
+#define KEYRING_SEARCH_NO_UPDATE_TIME 0x0004 /* Don't update times */
+#define KEYRING_SEARCH_NO_CHECK_PERM 0x0008 /* Don't check permissions */
+#define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0010 /* Give an error on excessive depth */
int (*iterator)(const void *object, void *iterator_data);
@@ -131,6 +127,8 @@ struct keyring_search_context {
struct timespec now;
};
+extern bool key_default_cmp(const struct key *key,
+ const struct key_match_data *match_data);
extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
struct keyring_search_context *ctx);
@@ -152,7 +150,8 @@ extern struct key *request_key_and_link(struct key_type *type,
struct key *dest_keyring,
unsigned long flags);
-extern int lookup_user_key_possessed(const struct key *key, const void *target);
+extern bool lookup_user_key_possessed(const struct key *key,
+ const struct key_match_data *match_data);
extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
key_perm_t perm);
#define KEY_LOOKUP_CREATE 0x01
diff --git a/security/keys/key.c b/security/keys/key.c
index 6d0cad16f00..e17ba6aefdc 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -799,7 +799,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
}
key_ref = ERR_PTR(-EINVAL);
- if (!index_key.type->match || !index_key.type->instantiate ||
+ if (!index_key.type->instantiate ||
(!index_key.description && !index_key.type->preparse))
goto error_put_type;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index e26f860e5f2..eff88a5f5d4 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -37,6 +37,8 @@ static int key_get_type_from_user(char *type,
return ret;
if (ret == 0 || ret >= len)
return -EINVAL;
+ if (type[0] == '.')
+ return -EPERM;
type[len - 1] = '\0';
return 0;
}
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 8314a7d2104..8177010174f 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -89,7 +89,6 @@ struct key_type key_type_keyring = {
.preparse = keyring_preparse,
.free_preparse = keyring_free_preparse,
.instantiate = keyring_instantiate,
- .match = user_match,
.revoke = keyring_revoke,
.destroy = keyring_destroy,
.describe = keyring_describe,
@@ -512,6 +511,15 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
EXPORT_SYMBOL(keyring_alloc);
/*
+ * By default, we keys found by getting an exact match on their descriptions.
+ */
+bool key_default_cmp(const struct key *key,
+ const struct key_match_data *match_data)
+{
+ return strcmp(key->description, match_data->raw_data) == 0;
+}
+
+/*
* Iteration function to consider each key found.
*/
static int keyring_search_iterator(const void *object, void *iterator_data)
@@ -545,7 +553,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
}
/* keys that don't match */
- if (!ctx->match(key, ctx->match_data)) {
+ if (!ctx->match_data.cmp(key, &ctx->match_data)) {
kleave(" = 0 [!match]");
return 0;
}
@@ -585,8 +593,7 @@ skipped:
*/
static int search_keyring(struct key *keyring, struct keyring_search_context *ctx)
{
- if ((ctx->flags & KEYRING_SEARCH_LOOKUP_TYPE) ==
- KEYRING_SEARCH_LOOKUP_DIRECT) {
+ if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_DIRECT) {
const void *object;
object = assoc_array_find(&keyring->keys,
@@ -627,7 +634,7 @@ static bool search_nested_keyrings(struct key *keyring,
/* Check to see if this top-level keyring is what we are looking for
* and whether it is valid or not.
*/
- if (ctx->flags & KEYRING_SEARCH_LOOKUP_ITERATE ||
+ if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE ||
keyring_compare_object(keyring, &ctx->index_key)) {
ctx->skipped_ret = 2;
ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK;
@@ -885,16 +892,25 @@ key_ref_t keyring_search(key_ref_t keyring,
.index_key.type = type,
.index_key.description = description,
.cred = current_cred(),
- .match = type->match,
- .match_data = description,
- .flags = (type->def_lookup_type |
- KEYRING_SEARCH_DO_STATE_CHECK),
+ .match_data.cmp = key_default_cmp,
+ .match_data.raw_data = description,
+ .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+ .flags = KEYRING_SEARCH_DO_STATE_CHECK,
};
+ key_ref_t key;
+ int ret;
- if (!ctx.match)
- return ERR_PTR(-ENOKEY);
+ if (type->match_preparse) {
+ ret = type->match_preparse(&ctx.match_data);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ }
- return keyring_search_aux(keyring, &ctx);
+ key = keyring_search_aux(keyring, &ctx);
+
+ if (type->match_free)
+ type->match_free(&ctx.match_data);
+ return key;
}
EXPORT_SYMBOL(keyring_search);
@@ -1014,7 +1030,7 @@ static int keyring_detect_cycle_iterator(const void *object,
/* We might get a keyring with matching index-key that is nonetheless a
* different keyring. */
- if (key != ctx->match_data)
+ if (key != ctx->match_data.raw_data)
return 0;
ctx->result = ERR_PTR(-EDEADLK);
@@ -1031,14 +1047,14 @@ static int keyring_detect_cycle_iterator(const void *object,
static int keyring_detect_cycle(struct key *A, struct key *B)
{
struct keyring_search_context ctx = {
- .index_key = A->index_key,
- .match_data = A,
- .iterator = keyring_detect_cycle_iterator,
- .flags = (KEYRING_SEARCH_LOOKUP_DIRECT |
- KEYRING_SEARCH_NO_STATE_CHECK |
- KEYRING_SEARCH_NO_UPDATE_TIME |
- KEYRING_SEARCH_NO_CHECK_PERM |
- KEYRING_SEARCH_DETECT_TOO_DEEP),
+ .index_key = A->index_key,
+ .match_data.raw_data = A,
+ .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+ .iterator = keyring_detect_cycle_iterator,
+ .flags = (KEYRING_SEARCH_NO_STATE_CHECK |
+ KEYRING_SEARCH_NO_UPDATE_TIME |
+ KEYRING_SEARCH_NO_CHECK_PERM |
+ KEYRING_SEARCH_DETECT_TOO_DEEP),
};
rcu_read_lock();
diff --git a/security/keys/proc.c b/security/keys/proc.c
index d3f6f2fd21d..972eeb336b8 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -194,10 +194,10 @@ static int proc_keys_show(struct seq_file *m, void *v)
.index_key.type = key->type,
.index_key.description = key->description,
.cred = current_cred(),
- .match = lookup_user_key_possessed,
- .match_data = key,
- .flags = (KEYRING_SEARCH_NO_STATE_CHECK |
- KEYRING_SEARCH_LOOKUP_DIRECT),
+ .match_data.cmp = lookup_user_key_possessed,
+ .match_data.raw_data = key,
+ .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+ .flags = KEYRING_SEARCH_NO_STATE_CHECK,
};
key_ref = make_key_ref(key, 0);
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 0cf8a130a26..bd536cb221e 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -489,9 +489,10 @@ found:
/*
* See if the key we're looking at is the target key.
*/
-int lookup_user_key_possessed(const struct key *key, const void *target)
+bool lookup_user_key_possessed(const struct key *key,
+ const struct key_match_data *match_data)
{
- return key == target;
+ return key == match_data->raw_data;
}
/*
@@ -516,9 +517,9 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
key_perm_t perm)
{
struct keyring_search_context ctx = {
- .match = lookup_user_key_possessed,
- .flags = (KEYRING_SEARCH_NO_STATE_CHECK |
- KEYRING_SEARCH_LOOKUP_DIRECT),
+ .match_data.cmp = lookup_user_key_possessed,
+ .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+ .flags = KEYRING_SEARCH_NO_STATE_CHECK,
};
struct request_key_auth *rka;
struct key *key;
@@ -673,7 +674,7 @@ try_again:
ctx.index_key.type = key->type;
ctx.index_key.description = key->description;
ctx.index_key.desc_len = strlen(key->description);
- ctx.match_data = key;
+ ctx.match_data.raw_data = key;
kdebug("check possessed");
skey_ref = search_process_keyrings(&ctx);
kdebug("possessed=%p", skey_ref);
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 26a94f18af9..bb4337c7ae1 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -513,9 +513,9 @@ struct key *request_key_and_link(struct key_type *type,
.index_key.type = type,
.index_key.description = description,
.cred = current_cred(),
- .match = type->match,
- .match_data = description,
- .flags = KEYRING_SEARCH_LOOKUP_DIRECT,
+ .match_data.cmp = key_default_cmp,
+ .match_data.raw_data = description,
+ .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
};
struct key *key;
key_ref_t key_ref;
@@ -525,6 +525,14 @@ struct key *request_key_and_link(struct key_type *type,
ctx.index_key.type->name, ctx.index_key.description,
callout_info, callout_len, aux, dest_keyring, flags);
+ if (type->match_preparse) {
+ ret = type->match_preparse(&ctx.match_data);
+ if (ret < 0) {
+ key = ERR_PTR(ret);
+ goto error;
+ }
+ }
+
/* search all the process keyrings for a key */
key_ref = search_process_keyrings(&ctx);
@@ -537,7 +545,7 @@ struct key *request_key_and_link(struct key_type *type,
if (ret < 0) {
key_put(key);
key = ERR_PTR(ret);
- goto error;
+ goto error_free;
}
}
} else if (PTR_ERR(key_ref) != -EAGAIN) {
@@ -547,12 +555,15 @@ struct key *request_key_and_link(struct key_type *type,
* should consult userspace if we can */
key = ERR_PTR(-ENOKEY);
if (!callout_info)
- goto error;
+ goto error_free;
key = construct_key_and_link(&ctx, callout_info, callout_len,
aux, dest_keyring, flags);
}
+error_free:
+ if (type->match_free)
+ type->match_free(&ctx.match_data);
error:
kleave(" = %p", key);
return key;
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index 842e6f410d5..6639e2cb885 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -44,12 +44,12 @@ struct key_type key_type_request_key_auth = {
.read = request_key_auth_read,
};
-int request_key_auth_preparse(struct key_preparsed_payload *prep)
+static int request_key_auth_preparse(struct key_preparsed_payload *prep)
{
return 0;
}
-void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
+static void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
{
}
@@ -246,9 +246,9 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
.index_key.type = &key_type_request_key_auth,
.index_key.description = description,
.cred = current_cred(),
- .match = user_match,
- .match_data = description,
- .flags = KEYRING_SEARCH_LOOKUP_DIRECT,
+ .match_data.cmp = key_default_cmp,
+ .match_data.raw_data = description,
+ .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
};
struct key *authkey;
key_ref_t authkey_ref;
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 6b804aa4529..c0594cb07ad 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -1096,7 +1096,6 @@ struct key_type key_type_trusted = {
.name = "trusted",
.instantiate = trusted_instantiate,
.update = trusted_update,
- .match = user_match,
.destroy = trusted_destroy,
.describe = user_describe,
.read = trusted_read,
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index eee340011f2..36b47bbd3d8 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -26,12 +26,10 @@ static int logon_vet_description(const char *desc);
*/
struct key_type key_type_user = {
.name = "user",
- .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.preparse = user_preparse,
.free_preparse = user_free_preparse,
.instantiate = generic_key_instantiate,
.update = user_update,
- .match = user_match,
.revoke = user_revoke,
.destroy = user_destroy,
.describe = user_describe,
@@ -48,12 +46,10 @@ EXPORT_SYMBOL_GPL(key_type_user);
*/
struct key_type key_type_logon = {
.name = "logon",
- .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.preparse = user_preparse,
.free_preparse = user_free_preparse,
.instantiate = generic_key_instantiate,
.update = user_update,
- .match = user_match,
.revoke = user_revoke,
.destroy = user_destroy,
.describe = user_describe,
@@ -139,16 +135,6 @@ error:
EXPORT_SYMBOL_GPL(user_update);
/*
- * match users on their name
- */
-int user_match(const struct key *key, const void *description)
-{
- return strcmp(key->description, description) == 0;
-}
-
-EXPORT_SYMBOL_GPL(user_match);
-
-/*
* dispose of the links from a revoked keyring
* - called with the key sem write-locked
*/
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index ada0d0bf346..8426a2aa8dc 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2097,6 +2097,41 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
/* binprm security operations */
+static int check_nnp_nosuid(const struct linux_binprm *bprm,
+ const struct task_security_struct *old_tsec,
+ const struct task_security_struct *new_tsec)
+{
+ int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS);
+ int nosuid = (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID);
+ int rc;
+
+ if (!nnp && !nosuid)
+ return 0; /* neither NNP nor nosuid */
+
+ if (new_tsec->sid == old_tsec->sid)
+ return 0; /* No change in credentials */
+
+ /*
+ * The only transitions we permit under NNP or nosuid
+ * are transitions to bounded SIDs, i.e. SIDs that are
+ * guaranteed to only be allowed a subset of the permissions
+ * of the current SID.
+ */
+ rc = security_bounded_transition(old_tsec->sid, new_tsec->sid);
+ if (rc) {
+ /*
+ * On failure, preserve the errno values for NNP vs nosuid.
+ * NNP: Operation not permitted for caller.
+ * nosuid: Permission denied to file.
+ */
+ if (nnp)
+ return -EPERM;
+ else
+ return -EACCES;
+ }
+ return 0;
+}
+
static int selinux_bprm_set_creds(struct linux_binprm *bprm)
{
const struct task_security_struct *old_tsec;
@@ -2133,14 +2168,10 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
/* Reset exec SID on execve. */
new_tsec->exec_sid = 0;
- /*
- * Minimize confusion: if no_new_privs or nosuid and a
- * transition is explicitly requested, then fail the exec.
- */
- if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)
- return -EPERM;
- if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
- return -EACCES;
+ /* Fail on NNP or nosuid if not an allowed transition. */
+ rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
+ if (rc)
+ return rc;
} else {
/* Check for a default transition on this program. */
rc = security_transition_sid(old_tsec->sid, isec->sid,
@@ -2148,15 +2179,19 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
&new_tsec->sid);
if (rc)
return rc;
+
+ /*
+ * Fallback to old SID on NNP or nosuid if not an allowed
+ * transition.
+ */
+ rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
+ if (rc)
+ new_tsec->sid = old_tsec->sid;
}
ad.type = LSM_AUDIT_DATA_PATH;
ad.u.path = bprm->file->f_path;
- if ((bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) ||
- (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS))
- new_tsec->sid = old_tsec->sid;
-
if (new_tsec->sid == old_tsec->sid) {
rc = avc_has_perm(old_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
@@ -4270,15 +4305,15 @@ static int selinux_socket_unix_may_send(struct socket *sock,
&ad);
}
-static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
- u32 peer_sid,
+static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
+ char *addrp, u16 family, u32 peer_sid,
struct common_audit_data *ad)
{
int err;
u32 if_sid;
u32 node_sid;
- err = sel_netif_sid(ifindex, &if_sid);
+ err = sel_netif_sid(ns, ifindex, &if_sid);
if (err)
return err;
err = avc_has_perm(peer_sid, if_sid,
@@ -4371,8 +4406,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
if (err)
return err;
- err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
- peer_sid, &ad);
+ err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif,
+ addrp, family, peer_sid, &ad);
if (err) {
selinux_netlbl_err(skb, err, 0);
return err;
@@ -4690,10 +4725,9 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
if (err) {
if (err == -EINVAL) {
- audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
- "SELinux: unrecognized netlink message"
- " type=%hu for sclass=%hu\n",
- nlh->nlmsg_type, sksec->sclass);
+ WARN_ONCE(1, "selinux_nlmsg_perm: unrecognized netlink message:"
+ " protocol=%hu nlmsg_type=%hu sclass=%hu\n",
+ sk->sk_protocol, nlh->nlmsg_type, sksec->sclass);
if (!selinux_enforcing || security_get_allow_unknown())
err = 0;
}
@@ -4711,7 +4745,8 @@ out:
#ifdef CONFIG_NETFILTER
-static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
+static unsigned int selinux_ip_forward(struct sk_buff *skb,
+ const struct net_device *indev,
u16 family)
{
int err;
@@ -4737,14 +4772,14 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
ad.type = LSM_AUDIT_DATA_NET;
ad.u.net = &net;
- ad.u.net->netif = ifindex;
+ ad.u.net->netif = indev->ifindex;
ad.u.net->family = family;
if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
return NF_DROP;
if (peerlbl_active) {
- err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
- peer_sid, &ad);
+ err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex,
+ addrp, family, peer_sid, &ad);
if (err) {
selinux_netlbl_err(skb, err, 1);
return NF_DROP;
@@ -4773,7 +4808,7 @@ static unsigned int selinux_ipv4_forward(const struct nf_hook_ops *ops,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return selinux_ip_forward(skb, in->ifindex, PF_INET);
+ return selinux_ip_forward(skb, in, PF_INET);
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -4783,7 +4818,7 @@ static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return selinux_ip_forward(skb, in->ifindex, PF_INET6);
+ return selinux_ip_forward(skb, in, PF_INET6);
}
#endif /* IPV6 */
@@ -4871,11 +4906,13 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
return NF_ACCEPT;
}
-static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
+static unsigned int selinux_ip_postroute(struct sk_buff *skb,
+ const struct net_device *outdev,
u16 family)
{
u32 secmark_perm;
u32 peer_sid;
+ int ifindex = outdev->ifindex;
struct sock *sk;
struct common_audit_data ad;
struct lsm_network_audit net = {0,};
@@ -4956,6 +4993,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
case PF_INET6:
if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
return NF_ACCEPT;
+ break;
default:
return NF_DROP_ERR(-ECONNREFUSED);
}
@@ -4987,7 +5025,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
u32 if_sid;
u32 node_sid;
- if (sel_netif_sid(ifindex, &if_sid))
+ if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid))
return NF_DROP;
if (avc_has_perm(peer_sid, if_sid,
SECCLASS_NETIF, NETIF__EGRESS, &ad))
@@ -5009,7 +5047,7 @@ static unsigned int selinux_ipv4_postroute(const struct nf_hook_ops *ops,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return selinux_ip_postroute(skb, out->ifindex, PF_INET);
+ return selinux_ip_postroute(skb, out, PF_INET);
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -5019,7 +5057,7 @@ static unsigned int selinux_ipv6_postroute(const struct nf_hook_ops *ops,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
+ return selinux_ip_postroute(skb, out, PF_INET6);
}
#endif /* IPV6 */
@@ -6033,7 +6071,7 @@ security_initcall(selinux_init);
#if defined(CONFIG_NETFILTER)
-static struct nf_hook_ops selinux_ipv4_ops[] = {
+static struct nf_hook_ops selinux_nf_ops[] = {
{
.hook = selinux_ipv4_postroute,
.owner = THIS_MODULE,
@@ -6054,12 +6092,8 @@ static struct nf_hook_ops selinux_ipv4_ops[] = {
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_SELINUX_FIRST,
- }
-};
-
+ },
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-
-static struct nf_hook_ops selinux_ipv6_ops[] = {
{
.hook = selinux_ipv6_postroute,
.owner = THIS_MODULE,
@@ -6073,32 +6107,24 @@ static struct nf_hook_ops selinux_ipv6_ops[] = {
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP6_PRI_SELINUX_FIRST,
- }
-};
-
+ },
#endif /* IPV6 */
+};
static int __init selinux_nf_ip_init(void)
{
- int err = 0;
+ int err;
if (!selinux_enabled)
- goto out;
+ return 0;
printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
- err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
+ err = nf_register_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops));
if (err)
- panic("SELinux: nf_register_hooks for IPv4: error %d\n", err);
+ panic("SELinux: nf_register_hooks: error %d\n", err);
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
- if (err)
- panic("SELinux: nf_register_hooks for IPv6: error %d\n", err);
-#endif /* IPV6 */
-
-out:
- return err;
+ return 0;
}
__initcall(selinux_nf_ip_init);
@@ -6108,10 +6134,7 @@ static void selinux_nf_ip_exit(void)
{
printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
- nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops));
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops));
-#endif /* IPV6 */
+ nf_unregister_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops));
}
#endif
diff --git a/security/selinux/include/netif.h b/security/selinux/include/netif.h
index 57c6eae81ea..c7214544409 100644
--- a/security/selinux/include/netif.h
+++ b/security/selinux/include/netif.h
@@ -17,9 +17,11 @@
#ifndef _SELINUX_NETIF_H_
#define _SELINUX_NETIF_H_
+#include <net/net_namespace.h>
+
void sel_netif_flush(void);
-int sel_netif_sid(int ifindex, u32 *sid);
+int sel_netif_sid(struct net *ns, int ifindex, u32 *sid);
#endif /* _SELINUX_NETIF_H_ */
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 078e553f52f..81fa718d5cb 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -24,6 +24,7 @@
#include <linux/binfmts.h>
#include <linux/in.h>
#include <linux/spinlock.h>
+#include <net/net_namespace.h>
#include "flask.h"
#include "avc.h"
@@ -78,6 +79,7 @@ struct ipc_security_struct {
};
struct netif_security_struct {
+ struct net *ns; /* network namespace */
int ifindex; /* device index */
u32 sid; /* SID for this interface */
};
diff --git a/security/selinux/netif.c b/security/selinux/netif.c
index 50ce177d71a..e607b4473ef 100644
--- a/security/selinux/netif.c
+++ b/security/selinux/netif.c
@@ -45,6 +45,7 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
/**
* sel_netif_hashfn - Hashing function for the interface table
+ * @ns: the network namespace
* @ifindex: the network interface
*
* Description:
@@ -52,13 +53,14 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
* bucket number for the given interface.
*
*/
-static inline u32 sel_netif_hashfn(int ifindex)
+static inline u32 sel_netif_hashfn(const struct net *ns, int ifindex)
{
- return (ifindex & (SEL_NETIF_HASH_SIZE - 1));
+ return (((uintptr_t)ns + ifindex) & (SEL_NETIF_HASH_SIZE - 1));
}
/**
* sel_netif_find - Search for an interface record
+ * @ns: the network namespace
* @ifindex: the network interface
*
* Description:
@@ -66,15 +68,15 @@ static inline u32 sel_netif_hashfn(int ifindex)
* If an entry can not be found in the table return NULL.
*
*/
-static inline struct sel_netif *sel_netif_find(int ifindex)
+static inline struct sel_netif *sel_netif_find(const struct net *ns,
+ int ifindex)
{
- int idx = sel_netif_hashfn(ifindex);
+ int idx = sel_netif_hashfn(ns, ifindex);
struct sel_netif *netif;
list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list)
- /* all of the devices should normally fit in the hash, so we
- * optimize for that case */
- if (likely(netif->nsec.ifindex == ifindex))
+ if (net_eq(netif->nsec.ns, ns) &&
+ netif->nsec.ifindex == ifindex)
return netif;
return NULL;
@@ -96,7 +98,7 @@ static int sel_netif_insert(struct sel_netif *netif)
if (sel_netif_total >= SEL_NETIF_HASH_MAX)
return -ENOSPC;
- idx = sel_netif_hashfn(netif->nsec.ifindex);
+ idx = sel_netif_hashfn(netif->nsec.ns, netif->nsec.ifindex);
list_add_rcu(&netif->list, &sel_netif_hash[idx]);
sel_netif_total++;
@@ -120,6 +122,7 @@ static void sel_netif_destroy(struct sel_netif *netif)
/**
* sel_netif_sid_slow - Lookup the SID of a network interface using the policy
+ * @ns: the network namespace
* @ifindex: the network interface
* @sid: interface SID
*
@@ -130,7 +133,7 @@ static void sel_netif_destroy(struct sel_netif *netif)
* failure.
*
*/
-static int sel_netif_sid_slow(int ifindex, u32 *sid)
+static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
{
int ret;
struct sel_netif *netif;
@@ -140,7 +143,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
/* NOTE: we always use init's network namespace since we don't
* currently support containers */
- dev = dev_get_by_index(&init_net, ifindex);
+ dev = dev_get_by_index(ns, ifindex);
if (unlikely(dev == NULL)) {
printk(KERN_WARNING
"SELinux: failure in sel_netif_sid_slow(),"
@@ -149,7 +152,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
}
spin_lock_bh(&sel_netif_lock);
- netif = sel_netif_find(ifindex);
+ netif = sel_netif_find(ns, ifindex);
if (netif != NULL) {
*sid = netif->nsec.sid;
ret = 0;
@@ -163,6 +166,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
ret = security_netif_sid(dev->name, &new->nsec.sid);
if (ret != 0)
goto out;
+ new->nsec.ns = ns;
new->nsec.ifindex = ifindex;
ret = sel_netif_insert(new);
if (ret != 0)
@@ -184,6 +188,7 @@ out:
/**
* sel_netif_sid - Lookup the SID of a network interface
+ * @ns: the network namespace
* @ifindex: the network interface
* @sid: interface SID
*
@@ -195,12 +200,12 @@ out:
* on failure.
*
*/
-int sel_netif_sid(int ifindex, u32 *sid)
+int sel_netif_sid(struct net *ns, int ifindex, u32 *sid)
{
struct sel_netif *netif;
rcu_read_lock();
- netif = sel_netif_find(ifindex);
+ netif = sel_netif_find(ns, ifindex);
if (likely(netif != NULL)) {
*sid = netif->nsec.sid;
rcu_read_unlock();
@@ -208,11 +213,12 @@ int sel_netif_sid(int ifindex, u32 *sid)
}
rcu_read_unlock();
- return sel_netif_sid_slow(ifindex, sid);
+ return sel_netif_sid_slow(ns, ifindex, sid);
}
/**
* sel_netif_kill - Remove an entry from the network interface table
+ * @ns: the network namespace
* @ifindex: the network interface
*
* Description:
@@ -220,13 +226,13 @@ int sel_netif_sid(int ifindex, u32 *sid)
* table if it exists.
*
*/
-static void sel_netif_kill(int ifindex)
+static void sel_netif_kill(const struct net *ns, int ifindex)
{
struct sel_netif *netif;
rcu_read_lock();
spin_lock_bh(&sel_netif_lock);
- netif = sel_netif_find(ifindex);
+ netif = sel_netif_find(ns, ifindex);
if (netif)
sel_netif_destroy(netif);
spin_unlock_bh(&sel_netif_lock);
@@ -257,11 +263,8 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this,
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- if (dev_net(dev) != &init_net)
- return NOTIFY_DONE;
-
if (event == NETDEV_DOWN)
- sel_netif_kill(dev->ifindex);
+ sel_netif_kill(dev_net(dev), dev->ifindex);
return NOTIFY_DONE;
}
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 2aa9d172dc7..a1d3944751b 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -728,7 +728,7 @@ static int security_validtrans_handle_fail(struct context *ocontext,
if (context_struct_to_string(tcontext, &t, &tlen))
goto out;
audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
- "security_validate_transition: denied for"
+ "op=security_validate_transition seresult=denied"
" oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
out:
@@ -877,7 +877,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
audit_log(current->audit_context,
GFP_ATOMIC, AUDIT_SELINUX_ERR,
"op=security_bounded_transition "
- "result=denied "
+ "seresult=denied "
"oldcontext=%s newcontext=%s",
old_name, new_name);
}
@@ -1351,8 +1351,8 @@ static int compute_sid_handle_invalid_context(
if (context_struct_to_string(newcontext, &n, &nlen))
goto out;
audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
- "security_compute_sid: invalid context %s"
- " for scontext=%s"
+ "op=security_compute_sid invalid_context=%s"
+ " scontext=%s"
" tcontext=%s"
" tclass=%s",
n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1));
@@ -2607,8 +2607,10 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
rc = convert_context_handle_invalid_context(&newcon);
if (rc) {
if (!context_struct_to_string(&newcon, &s, &len)) {
- audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
- "security_sid_mls_copy: invalid context %s", s);
+ audit_log(current->audit_context,
+ GFP_ATOMIC, AUDIT_SELINUX_ERR,
+ "op=security_sid_mls_copy "
+ "invalid_context=%s", s);
kfree(s);
}
goto out_unlock;
diff --git a/security/smack/Kconfig b/security/smack/Kconfig
index e69de9c642b..b065f978941 100644
--- a/security/smack/Kconfig
+++ b/security/smack/Kconfig
@@ -12,3 +12,19 @@ config SECURITY_SMACK
of other mandatory security schemes.
If you are unsure how to answer this question, answer N.
+config SECURITY_SMACK_BRINGUP
+ bool "Reporting on access granted by Smack rules"
+ depends on SECURITY_SMACK
+ default n
+ help
+ Enable the bring-up ("b") access mode in Smack rules.
+ When access is granted by a rule with the "b" mode a
+ message about the access requested is generated. The
+ intention is that a process can be granted a wide set
+ of access initially with the bringup mode set on the
+ rules. The developer can use the information to
+ identify which rules are necessary and what accesses
+ may be inappropriate. The developer can reduce the
+ access rule set once the behavior is well understood.
+ This is a superior mechanism to the oft abused
+ "permissive" mode of other systems.
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 020307ef097..b828a379377 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -71,11 +71,11 @@ struct smack_known {
#define SMK_CIPSOLEN 24
struct superblock_smack {
- char *smk_root;
- char *smk_floor;
- char *smk_hat;
- char *smk_default;
- int smk_initialized;
+ struct smack_known *smk_root;
+ struct smack_known *smk_floor;
+ struct smack_known *smk_hat;
+ struct smack_known *smk_default;
+ int smk_initialized;
};
struct socket_smack {
@@ -88,7 +88,7 @@ struct socket_smack {
* Inode smack data
*/
struct inode_smack {
- char *smk_inode; /* label of the fso */
+ struct smack_known *smk_inode; /* label of the fso */
struct smack_known *smk_task; /* label of the task */
struct smack_known *smk_mmap; /* label of the mmap domain */
struct mutex smk_lock; /* initialization lock */
@@ -112,7 +112,7 @@ struct task_smack {
struct smack_rule {
struct list_head list;
struct smack_known *smk_subject;
- char *smk_object;
+ struct smack_known *smk_object;
int smk_access;
};
@@ -123,7 +123,7 @@ struct smk_netlbladdr {
struct list_head list;
struct sockaddr_in smk_host; /* network address */
struct in_addr smk_mask; /* network mask */
- char *smk_label; /* label */
+ struct smack_known *smk_label; /* label */
};
/*
@@ -191,6 +191,7 @@ struct smk_port_label {
*/
#define MAY_TRANSMUTE 0x00001000 /* Controls directory labeling */
#define MAY_LOCK 0x00002000 /* Locks should be writes, but ... */
+#define MAY_BRINGUP 0x00004000 /* Report use of this rule */
/*
* Just to make the common cases easier to deal with
@@ -200,9 +201,9 @@ struct smk_port_label {
#define MAY_NOT 0
/*
- * Number of access types used by Smack (rwxatl)
+ * Number of access types used by Smack (rwxatlb)
*/
-#define SMK_NUM_ACCESS_TYPE 6
+#define SMK_NUM_ACCESS_TYPE 7
/* SMACK data */
struct smack_audit_data {
@@ -226,23 +227,23 @@ struct smk_audit_info {
/*
* These functions are in smack_lsm.c
*/
-struct inode_smack *new_inode_smack(char *);
+struct inode_smack *new_inode_smack(struct smack_known *);
/*
* These functions are in smack_access.c
*/
int smk_access_entry(char *, char *, struct list_head *);
-int smk_access(struct smack_known *, char *, int, struct smk_audit_info *);
-int smk_tskacc(struct task_smack *, char *, u32, struct smk_audit_info *);
-int smk_curacc(char *, u32, struct smk_audit_info *);
+int smk_access(struct smack_known *, struct smack_known *,
+ int, struct smk_audit_info *);
+int smk_tskacc(struct task_smack *, struct smack_known *,
+ u32, struct smk_audit_info *);
+int smk_curacc(struct smack_known *, u32, struct smk_audit_info *);
struct smack_known *smack_from_secid(const u32);
char *smk_parse_smack(const char *string, int len);
int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
-char *smk_import(const char *, int);
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 *);
-u32 smack_to_secid(const char *);
/*
* Shared data.
@@ -252,7 +253,7 @@ extern int smack_cipso_mapped;
extern struct smack_known *smack_net_ambient;
extern struct smack_known *smack_onlycap;
extern struct smack_known *smack_syslog_label;
-extern const char *smack_cipso_option;
+extern struct smack_known smack_cipso_option;
extern int smack_ptrace_rule;
extern struct smack_known smack_known_floor;
@@ -281,9 +282,9 @@ static inline int smk_inode_transmutable(const struct inode *isp)
}
/*
- * Present a pointer to the smack label in an inode blob.
+ * Present a pointer to the smack label entry in an inode blob.
*/
-static inline char *smk_of_inode(const struct inode *isp)
+static inline struct smack_known *smk_of_inode(const struct inode *isp)
{
struct inode_smack *sip = isp->i_security;
return sip->smk_inode;
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index f97d0842e62..5b970ffde02 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -94,7 +94,7 @@ int smk_access_entry(char *subject_label, char *object_label,
struct smack_rule *srp;
list_for_each_entry_rcu(srp, rule_list, list) {
- if (srp->smk_object == object_label &&
+ if (srp->smk_object->smk_known == object_label &&
srp->smk_subject->smk_known == subject_label) {
may = srp->smk_access;
break;
@@ -111,8 +111,8 @@ int smk_access_entry(char *subject_label, char *object_label,
/**
* smk_access - determine if a subject has a specific access to an object
- * @subject_known: a pointer to the subject's Smack label entry
- * @object_label: a pointer to the object's Smack label
+ * @subject: a pointer to the subject's Smack label entry
+ * @object: a pointer to the object's Smack label entry
* @request: the access requested, in "MAY" format
* @a : a pointer to the audit data
*
@@ -122,8 +122,8 @@ int smk_access_entry(char *subject_label, char *object_label,
*
* Smack labels are shared on smack_list
*/
-int smk_access(struct smack_known *subject_known, char *object_label,
- int request, struct smk_audit_info *a)
+int smk_access(struct smack_known *subject, struct smack_known *object,
+ int request, struct smk_audit_info *a)
{
int may = MAY_NOT;
int rc = 0;
@@ -133,7 +133,7 @@ int smk_access(struct smack_known *subject_known, char *object_label,
*
* A star subject can't access any object.
*/
- if (subject_known == &smack_known_star) {
+ if (subject == &smack_known_star) {
rc = -EACCES;
goto out_audit;
}
@@ -142,28 +142,28 @@ int smk_access(struct smack_known *subject_known, char *object_label,
* Tasks cannot be assigned the internet label.
* An internet subject can access any object.
*/
- if (object_label == smack_known_web.smk_known ||
- subject_known == &smack_known_web)
+ if (object == &smack_known_web ||
+ subject == &smack_known_web)
goto out_audit;
/*
* A star object can be accessed by any subject.
*/
- if (object_label == smack_known_star.smk_known)
+ if (object == &smack_known_star)
goto out_audit;
/*
* An object can be accessed in any way by a subject
* with the same label.
*/
- if (subject_known->smk_known == object_label)
+ if (subject->smk_known == object->smk_known)
goto out_audit;
/*
* A hat subject can read any object.
* A floor object can be read by any subject.
*/
if ((request & MAY_ANYREAD) == request) {
- if (object_label == smack_known_floor.smk_known)
+ if (object == &smack_known_floor)
goto out_audit;
- if (subject_known == &smack_known_hat)
+ if (subject == &smack_known_hat)
goto out_audit;
}
/*
@@ -174,27 +174,38 @@ int smk_access(struct smack_known *subject_known, char *object_label,
* indicates there is no entry for this pair.
*/
rcu_read_lock();
- may = smk_access_entry(subject_known->smk_known, object_label,
- &subject_known->smk_rules);
+ may = smk_access_entry(subject->smk_known, object->smk_known,
+ &subject->smk_rules);
rcu_read_unlock();
- if (may > 0 && (request & may) == request)
+ if (may <= 0 || (request & may) != request) {
+ rc = -EACCES;
goto out_audit;
+ }
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+ /*
+ * Return a positive value if using bringup mode.
+ * This allows the hooks to identify checks that
+ * succeed because of "b" rules.
+ */
+ if (may & MAY_BRINGUP)
+ rc = MAY_BRINGUP;
+#endif
- rc = -EACCES;
out_audit:
#ifdef CONFIG_AUDIT
if (a)
- smack_log(subject_known->smk_known, object_label, request,
- rc, a);
+ smack_log(subject->smk_known, object->smk_known,
+ request, rc, a);
#endif
+
return rc;
}
/**
* smk_tskacc - determine if a task has a specific access to an object
- * @tsp: a pointer to the subject task
- * @obj_label: a pointer to the object's Smack label
+ * @tsp: a pointer to the subject's task
+ * @obj_known: a pointer to the object's label entry
* @mode: the access requested, in "MAY" format
* @a : common audit data
*
@@ -203,24 +214,25 @@ out_audit:
* non zero otherwise. It allows that the task may have the capability
* to override the rules.
*/
-int smk_tskacc(struct task_smack *subject, char *obj_label,
+int smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known,
u32 mode, struct smk_audit_info *a)
{
- struct smack_known *skp = smk_of_task(subject);
+ struct smack_known *sbj_known = smk_of_task(tsp);
int may;
int rc;
/*
* Check the global rule list
*/
- rc = smk_access(skp, obj_label, mode, NULL);
- if (rc == 0) {
+ rc = smk_access(sbj_known, obj_known, mode, NULL);
+ if (rc >= 0) {
/*
* If there is an entry in the task's rule list
* it can further restrict access.
*/
- may = smk_access_entry(skp->smk_known, obj_label,
- &subject->smk_rules);
+ may = smk_access_entry(sbj_known->smk_known,
+ obj_known->smk_known,
+ &tsp->smk_rules);
if (may < 0)
goto out_audit;
if ((mode & may) == mode)
@@ -237,14 +249,15 @@ int smk_tskacc(struct task_smack *subject, char *obj_label,
out_audit:
#ifdef CONFIG_AUDIT
if (a)
- smack_log(skp->smk_known, obj_label, mode, rc, a);
+ smack_log(sbj_known->smk_known, obj_known->smk_known,
+ mode, rc, a);
#endif
return rc;
}
/**
* smk_curacc - determine if current has a specific access to an object
- * @obj_label: a pointer to the object's Smack label
+ * @obj_known: a pointer to the object's Smack label entry
* @mode: the access requested, in "MAY" format
* @a : common audit data
*
@@ -253,11 +266,12 @@ out_audit:
* non zero otherwise. It allows that current may have the capability
* to override the rules.
*/
-int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a)
+int smk_curacc(struct smack_known *obj_known,
+ u32 mode, struct smk_audit_info *a)
{
struct task_smack *tsp = current_security();
- return smk_tskacc(tsp, obj_label, mode, a);
+ return smk_tskacc(tsp, obj_known, mode, a);
}
#ifdef CONFIG_AUDIT
@@ -328,6 +342,13 @@ void smack_log(char *subject_label, char *object_label, int request,
struct smack_audit_data *sad;
struct common_audit_data *a = &ad->a;
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+ /*
+ * The result may be positive in bringup mode.
+ */
+ if (result > 0)
+ result = 0;
+#endif
/* check if we have to log the current event */
if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
return;
@@ -544,27 +565,6 @@ unlockout:
}
/**
- * smk_import - import a smack label
- * @string: a text string that might be a Smack label
- * @len: the maximum size, or zero if it is NULL terminated.
- *
- * Returns a pointer to the label in the label list that
- * matches the passed string, adding it if necessary.
- */
-char *smk_import(const char *string, int len)
-{
- struct smack_known *skp;
-
- /* labels cannot begin with a '-' */
- if (string[0] == '-')
- return NULL;
- skp = smk_import_entry(string, len);
- if (skp == NULL)
- return NULL;
- return skp->smk_known;
-}
-
-/**
* smack_from_secid - find the Smack label associated with a secid
* @secid: an integer that might be associated with a Smack label
*
@@ -590,19 +590,3 @@ struct smack_known *smack_from_secid(const u32 secid)
rcu_read_unlock();
return &smack_known_invalid;
}
-
-/**
- * smack_to_secid - find the secid associated with a Smack label
- * @smack: the Smack label
- *
- * Returns the appropriate secid if there is one,
- * otherwise 0
- */
-u32 smack_to_secid(const char *smack)
-{
- struct smack_known *skp = smk_find_entry(smack);
-
- if (skp == NULL)
- return 0;
- return skp->smk_secid;
-}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 69e5635d89e..d515ec25ae9 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -54,6 +54,151 @@
LIST_HEAD(smk_ipv6_port_list);
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static void smk_bu_mode(int mode, char *s)
+{
+ int i = 0;
+
+ if (mode & MAY_READ)
+ s[i++] = 'r';
+ if (mode & MAY_WRITE)
+ s[i++] = 'w';
+ if (mode & MAY_EXEC)
+ s[i++] = 'x';
+ if (mode & MAY_APPEND)
+ s[i++] = 'a';
+ if (mode & MAY_TRANSMUTE)
+ s[i++] = 't';
+ if (mode & MAY_LOCK)
+ s[i++] = 'l';
+ if (i == 0)
+ s[i++] = '-';
+ s[i] = '\0';
+}
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_note(char *note, struct smack_known *sskp,
+ struct smack_known *oskp, int mode, int rc)
+{
+ char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+ if (rc <= 0)
+ return rc;
+
+ smk_bu_mode(mode, acc);
+ pr_info("Smack Bringup: (%s %s %s) %s\n",
+ sskp->smk_known, oskp->smk_known, acc, note);
+ return 0;
+}
+#else
+#define smk_bu_note(note, sskp, oskp, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_current(char *note, struct smack_known *oskp,
+ int mode, int rc)
+{
+ struct task_smack *tsp = current_security();
+ char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+ if (rc <= 0)
+ return rc;
+
+ smk_bu_mode(mode, acc);
+ pr_info("Smack Bringup: (%s %s %s) %s %s\n",
+ tsp->smk_task->smk_known, oskp->smk_known,
+ acc, current->comm, note);
+ return 0;
+}
+#else
+#define smk_bu_current(note, oskp, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_task(struct task_struct *otp, int mode, int rc)
+{
+ struct task_smack *tsp = current_security();
+ struct task_smack *otsp = task_security(otp);
+ char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+ if (rc <= 0)
+ return rc;
+
+ smk_bu_mode(mode, acc);
+ pr_info("Smack Bringup: (%s %s %s) %s to %s\n",
+ tsp->smk_task->smk_known, otsp->smk_task->smk_known, acc,
+ current->comm, otp->comm);
+ return 0;
+}
+#else
+#define smk_bu_task(otp, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_inode(struct inode *inode, int mode, int rc)
+{
+ struct task_smack *tsp = current_security();
+ char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+ if (rc <= 0)
+ return rc;
+
+ smk_bu_mode(mode, acc);
+ pr_info("Smack Bringup: (%s %s %s) inode=(%s %ld) %s\n",
+ tsp->smk_task->smk_known, smk_of_inode(inode)->smk_known, acc,
+ inode->i_sb->s_id, inode->i_ino, current->comm);
+ return 0;
+}
+#else
+#define smk_bu_inode(inode, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_file(struct file *file, int mode, int rc)
+{
+ struct task_smack *tsp = current_security();
+ struct smack_known *sskp = tsp->smk_task;
+ struct inode *inode = file->f_inode;
+ char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+ if (rc <= 0)
+ return rc;
+
+ smk_bu_mode(mode, acc);
+ pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %s) %s\n",
+ sskp->smk_known, (char *)file->f_security, acc,
+ inode->i_sb->s_id, inode->i_ino, file->f_dentry->d_name.name,
+ current->comm);
+ return 0;
+}
+#else
+#define smk_bu_file(file, mode, RC) (RC)
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static int smk_bu_credfile(const struct cred *cred, struct file *file,
+ int mode, int rc)
+{
+ struct task_smack *tsp = cred->security;
+ struct smack_known *sskp = tsp->smk_task;
+ struct inode *inode = file->f_inode;
+ char acc[SMK_NUM_ACCESS_TYPE + 1];
+
+ if (rc <= 0)
+ return rc;
+
+ smk_bu_mode(mode, acc);
+ pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %s) %s\n",
+ sskp->smk_known, smk_of_inode(inode)->smk_known, acc,
+ inode->i_sb->s_id, inode->i_ino, file->f_dentry->d_name.name,
+ current->comm);
+ return 0;
+}
+#else
+#define smk_bu_credfile(cred, file, mode, RC) (RC)
+#endif
+
/**
* smk_fetch - Fetch the smack label from a file.
* @ip: a pointer to the inode
@@ -87,11 +232,11 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip,
/**
* new_inode_smack - allocate an inode security blob
- * @smack: a pointer to the Smack label to use in the blob
+ * @skp: a pointer to the Smack label entry to use in the blob
*
* Returns the new blob or NULL if there's no memory available
*/
-struct inode_smack *new_inode_smack(char *smack)
+struct inode_smack *new_inode_smack(struct smack_known *skp)
{
struct inode_smack *isp;
@@ -99,7 +244,7 @@ struct inode_smack *new_inode_smack(char *smack)
if (isp == NULL)
return NULL;
- isp->smk_inode = smack;
+ isp->smk_inode = skp;
isp->smk_flags = 0;
mutex_init(&isp->smk_lock);
@@ -178,20 +323,20 @@ static inline unsigned int smk_ptrace_mode(unsigned int mode)
/**
* smk_ptrace_rule_check - helper for ptrace access
* @tracer: tracer process
- * @tracee_label: label of the process that's about to be traced,
- * the pointer must originate from smack structures
+ * @tracee_known: label entry of the process that's about to be traced
* @mode: ptrace attachment mode (PTRACE_MODE_*)
* @func: name of the function that called us, used for audit
*
* Returns 0 on access granted, -error on error
*/
-static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label,
+static int smk_ptrace_rule_check(struct task_struct *tracer,
+ struct smack_known *tracee_known,
unsigned int mode, const char *func)
{
int rc;
struct smk_audit_info ad, *saip = NULL;
struct task_smack *tsp;
- struct smack_known *skp;
+ struct smack_known *tracer_known;
if ((mode & PTRACE_MODE_NOAUDIT) == 0) {
smk_ad_init(&ad, func, LSM_AUDIT_DATA_TASK);
@@ -200,12 +345,12 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label,
}
tsp = task_security(tracer);
- skp = smk_of_task(tsp);
+ tracer_known = smk_of_task(tsp);
if ((mode & PTRACE_MODE_ATTACH) &&
(smack_ptrace_rule == SMACK_PTRACE_EXACT ||
smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)) {
- if (skp->smk_known == tracee_label)
+ if (tracer_known->smk_known == tracee_known->smk_known)
rc = 0;
else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)
rc = -EACCES;
@@ -215,13 +360,15 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label,
rc = -EACCES;
if (saip)
- smack_log(skp->smk_known, tracee_label, 0, rc, saip);
+ smack_log(tracer_known->smk_known,
+ tracee_known->smk_known,
+ 0, rc, saip);
return rc;
}
/* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */
- rc = smk_tskacc(tsp, tracee_label, smk_ptrace_mode(mode), saip);
+ rc = smk_tskacc(tsp, tracee_known, smk_ptrace_mode(mode), saip);
return rc;
}
@@ -250,7 +397,7 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
skp = smk_of_task(task_security(ctp));
- rc = smk_ptrace_rule_check(current, skp->smk_known, mode, __func__);
+ rc = smk_ptrace_rule_check(current, skp, mode, __func__);
return rc;
}
@@ -273,8 +420,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
skp = smk_of_task(current_security());
- rc = smk_ptrace_rule_check(ptp, skp->smk_known,
- PTRACE_MODE_ATTACH, __func__);
+ rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__);
return rc;
}
@@ -318,10 +464,10 @@ static int smack_sb_alloc_security(struct super_block *sb)
if (sbsp == NULL)
return -ENOMEM;
- sbsp->smk_root = smack_known_floor.smk_known;
- sbsp->smk_default = smack_known_floor.smk_known;
- sbsp->smk_floor = smack_known_floor.smk_known;
- sbsp->smk_hat = smack_known_hat.smk_known;
+ sbsp->smk_root = &smack_known_floor;
+ sbsp->smk_default = &smack_known_floor;
+ sbsp->smk_floor = &smack_known_floor;
+ sbsp->smk_hat = &smack_known_hat;
/*
* smk_initialized will be zero from kzalloc.
*/
@@ -405,7 +551,6 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
struct smack_known *skp;
char *op;
char *commap;
- char *nsp;
int transmute = 0;
int specified = 0;
@@ -421,38 +566,38 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
op += strlen(SMK_FSHAT);
- nsp = smk_import(op, 0);
- if (nsp != NULL) {
- sp->smk_hat = nsp;
+ skp = smk_import_entry(op, 0);
+ if (skp != NULL) {
+ sp->smk_hat = skp;
specified = 1;
}
} else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
op += strlen(SMK_FSFLOOR);
- nsp = smk_import(op, 0);
- if (nsp != NULL) {
- sp->smk_floor = nsp;
+ skp = smk_import_entry(op, 0);
+ if (skp != NULL) {
+ sp->smk_floor = skp;
specified = 1;
}
} else if (strncmp(op, SMK_FSDEFAULT,
strlen(SMK_FSDEFAULT)) == 0) {
op += strlen(SMK_FSDEFAULT);
- nsp = smk_import(op, 0);
- if (nsp != NULL) {
- sp->smk_default = nsp;
+ skp = smk_import_entry(op, 0);
+ if (skp != NULL) {
+ sp->smk_default = skp;
specified = 1;
}
} else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
op += strlen(SMK_FSROOT);
- nsp = smk_import(op, 0);
- if (nsp != NULL) {
- sp->smk_root = nsp;
+ skp = smk_import_entry(op, 0);
+ if (skp != NULL) {
+ sp->smk_root = skp;
specified = 1;
}
} else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
op += strlen(SMK_FSTRANS);
- nsp = smk_import(op, 0);
- if (nsp != NULL) {
- sp->smk_root = nsp;
+ skp = smk_import_entry(op, 0);
+ if (skp != NULL) {
+ sp->smk_root = skp;
transmute = 1;
specified = 1;
}
@@ -469,8 +614,8 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
* Unprivileged mounts get root and default from the caller.
*/
skp = smk_of_current();
- sp->smk_root = skp->smk_known;
- sp->smk_default = skp->smk_known;
+ sp->smk_root = skp;
+ sp->smk_default = skp;
}
/*
* Initialize the root inode.
@@ -507,6 +652,7 @@ static int smack_sb_statfs(struct dentry *dentry)
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad);
+ rc = smk_bu_current("statfs", sbp->smk_floor, MAY_READ, rc);
return rc;
}
@@ -546,7 +692,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
tracer = ptrace_parent(current);
if (likely(tracer != NULL))
rc = smk_ptrace_rule_check(tracer,
- isp->smk_task->smk_known,
+ isp->smk_task,
PTRACE_MODE_ATTACH,
__func__);
rcu_read_unlock();
@@ -607,7 +753,7 @@ static int smack_inode_alloc_security(struct inode *inode)
{
struct smack_known *skp = smk_of_current();
- inode->i_security = new_inode_smack(skp->smk_known);
+ inode->i_security = new_inode_smack(skp);
if (inode->i_security == NULL)
return -ENOMEM;
return 0;
@@ -627,8 +773,8 @@ static void smack_inode_free_security(struct inode *inode)
/**
* smack_inode_init_security - copy out the smack from an inode
- * @inode: the inode
- * @dir: unused
+ * @inode: the newly created inode
+ * @dir: containing directory object
* @qstr: unused
* @name: where to put the attribute name
* @value: where to put the attribute value
@@ -642,8 +788,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
{
struct inode_smack *issp = inode->i_security;
struct smack_known *skp = smk_of_current();
- char *isp = smk_of_inode(inode);
- char *dsp = smk_of_inode(dir);
+ struct smack_known *isp = smk_of_inode(inode);
+ struct smack_known *dsp = smk_of_inode(dir);
int may;
if (name)
@@ -651,7 +797,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
if (value) {
rcu_read_lock();
- may = smk_access_entry(skp->smk_known, dsp, &skp->smk_rules);
+ may = smk_access_entry(skp->smk_known, dsp->smk_known,
+ &skp->smk_rules);
rcu_read_unlock();
/*
@@ -666,13 +813,13 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
issp->smk_flags |= SMK_INODE_CHANGED;
}
- *value = kstrdup(isp, GFP_NOFS);
+ *value = kstrdup(isp->smk_known, GFP_NOFS);
if (*value == NULL)
return -ENOMEM;
}
if (len)
- *len = strlen(isp) + 1;
+ *len = strlen(isp->smk_known);
return 0;
}
@@ -688,7 +835,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry)
{
- char *isp;
+ struct smack_known *isp;
struct smk_audit_info ad;
int rc;
@@ -697,11 +844,13 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
isp = smk_of_inode(old_dentry->d_inode);
rc = smk_curacc(isp, MAY_WRITE, &ad);
+ rc = smk_bu_inode(old_dentry->d_inode, MAY_WRITE, rc);
if (rc == 0 && new_dentry->d_inode != NULL) {
isp = smk_of_inode(new_dentry->d_inode);
smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry);
rc = smk_curacc(isp, MAY_WRITE, &ad);
+ rc = smk_bu_inode(new_dentry->d_inode, MAY_WRITE, rc);
}
return rc;
@@ -728,6 +877,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
* You need write access to the thing you're unlinking
*/
rc = smk_curacc(smk_of_inode(ip), MAY_WRITE, &ad);
+ rc = smk_bu_inode(ip, MAY_WRITE, rc);
if (rc == 0) {
/*
* You also need write access to the containing directory
@@ -735,6 +885,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
smk_ad_setfield_u_fs_inode(&ad, dir);
rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
+ rc = smk_bu_inode(dir, MAY_WRITE, rc);
}
return rc;
}
@@ -759,6 +910,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
* You need write access to the thing you're removing
*/
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+ rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
if (rc == 0) {
/*
* You also need write access to the containing directory
@@ -766,6 +918,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
smk_ad_setfield_u_fs_inode(&ad, dir);
rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
+ rc = smk_bu_inode(dir, MAY_WRITE, rc);
}
return rc;
@@ -773,10 +926,10 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
/**
* smack_inode_rename - Smack check on rename
- * @old_inode: the old directory
- * @old_dentry: unused
- * @new_inode: the new directory
- * @new_dentry: unused
+ * @old_inode: unused
+ * @old_dentry: the old object
+ * @new_inode: unused
+ * @new_dentry: the new object
*
* Read and write access is required on both the old and
* new directories.
@@ -789,7 +942,7 @@ static int smack_inode_rename(struct inode *old_inode,
struct dentry *new_dentry)
{
int rc;
- char *isp;
+ struct smack_known *isp;
struct smk_audit_info ad;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
@@ -797,11 +950,13 @@ static int smack_inode_rename(struct inode *old_inode,
isp = smk_of_inode(old_dentry->d_inode);
rc = smk_curacc(isp, MAY_READWRITE, &ad);
+ rc = smk_bu_inode(old_dentry->d_inode, MAY_READWRITE, rc);
if (rc == 0 && new_dentry->d_inode != NULL) {
isp = smk_of_inode(new_dentry->d_inode);
smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry);
rc = smk_curacc(isp, MAY_READWRITE, &ad);
+ rc = smk_bu_inode(new_dentry->d_inode, MAY_READWRITE, rc);
}
return rc;
}
@@ -819,6 +974,7 @@ static int smack_inode_permission(struct inode *inode, int mask)
{
struct smk_audit_info ad;
int no_block = mask & MAY_NOT_BLOCK;
+ int rc;
mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
/*
@@ -832,7 +988,9 @@ static int smack_inode_permission(struct inode *inode, int mask)
return -ECHILD;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
smk_ad_setfield_u_fs_inode(&ad, inode);
- return smk_curacc(smk_of_inode(inode), mask, &ad);
+ rc = smk_curacc(smk_of_inode(inode), mask, &ad);
+ rc = smk_bu_inode(inode, mask, rc);
+ return rc;
}
/**
@@ -845,6 +1003,8 @@ static int smack_inode_permission(struct inode *inode, int mask)
static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
{
struct smk_audit_info ad;
+ int rc;
+
/*
* Need to allow for clearing the setuid bit.
*/
@@ -853,12 +1013,14 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
- return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+ rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+ rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
+ return rc;
}
/**
* smack_inode_getattr - Smack check for getting attributes
- * @mnt: unused
+ * @mnt: vfsmount of the object
* @dentry: the object
*
* Returns 0 if access is permitted, an error code otherwise
@@ -867,21 +1029,24 @@ static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
{
struct smk_audit_info ad;
struct path path;
+ int rc;
path.dentry = dentry;
path.mnt = mnt;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, path);
- return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
+ rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
+ rc = smk_bu_inode(dentry->d_inode, MAY_READ, rc);
+ return rc;
}
/**
* smack_inode_setxattr - Smack check for setting xattrs
* @dentry: the object
* @name: name of the attribute
- * @value: unused
- * @size: unused
+ * @value: value of the attribute
+ * @size: size of the value
* @flags: unused
*
* This protects the Smack attribute explicitly.
@@ -923,7 +1088,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
rc = -EPERM;
if (rc == 0 && check_import) {
- skp = smk_import_entry(value, size);
+ skp = size ? smk_import_entry(value, size) : NULL;
if (skp == NULL || (check_star &&
(skp == &smack_known_star || skp == &smack_known_web)))
rc = -EINVAL;
@@ -932,8 +1097,10 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
- if (rc == 0)
+ if (rc == 0) {
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+ rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
+ }
return rc;
}
@@ -963,9 +1130,9 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
if (strcmp(name, XATTR_NAME_SMACK) == 0) {
skp = smk_import_entry(value, size);
if (skp != NULL)
- isp->smk_inode = skp->smk_known;
+ isp->smk_inode = skp;
else
- isp->smk_inode = smack_known_invalid.smk_known;
+ isp->smk_inode = &smack_known_invalid;
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
skp = smk_import_entry(value, size);
if (skp != NULL)
@@ -993,11 +1160,14 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
static int smack_inode_getxattr(struct dentry *dentry, const char *name)
{
struct smk_audit_info ad;
+ int rc;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
- return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
+ rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
+ rc = smk_bu_inode(dentry->d_inode, MAY_READ, rc);
+ return rc;
}
/**
@@ -1033,6 +1203,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
+ rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
if (rc != 0)
return rc;
@@ -1070,14 +1241,14 @@ static int smack_inode_getsecurity(const struct inode *inode,
struct socket *sock;
struct super_block *sbp;
struct inode *ip = (struct inode *)inode;
- char *isp;
+ struct smack_known *isp;
int ilen;
int rc = 0;
if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
isp = smk_of_inode(inode);
- ilen = strlen(isp) + 1;
- *buffer = isp;
+ ilen = strlen(isp->smk_known);
+ *buffer = isp->smk_known;
return ilen;
}
@@ -1095,15 +1266,15 @@ static int smack_inode_getsecurity(const struct inode *inode,
ssp = sock->sk->sk_security;
if (strcmp(name, XATTR_SMACK_IPIN) == 0)
- isp = ssp->smk_in->smk_known;
+ isp = ssp->smk_in;
else if (strcmp(name, XATTR_SMACK_IPOUT) == 0)
- isp = ssp->smk_out->smk_known;
+ isp = ssp->smk_out;
else
return -EOPNOTSUPP;
- ilen = strlen(isp) + 1;
+ ilen = strlen(isp->smk_known);
if (rc == 0) {
- *buffer = isp;
+ *buffer = isp->smk_known;
rc = ilen;
}
@@ -1122,13 +1293,12 @@ static int smack_inode_getsecurity(const struct inode *inode,
static int smack_inode_listsecurity(struct inode *inode, char *buffer,
size_t buffer_size)
{
- int len = strlen(XATTR_NAME_SMACK);
+ int len = sizeof(XATTR_NAME_SMACK);
- if (buffer != NULL && len <= buffer_size) {
+ if (buffer != NULL && len <= buffer_size)
memcpy(buffer, XATTR_NAME_SMACK, len);
- return len;
- }
- return -EINVAL;
+
+ return len;
}
/**
@@ -1140,7 +1310,7 @@ static void smack_inode_getsecid(const struct inode *inode, u32 *secid)
{
struct inode_smack *isp = inode->i_security;
- *secid = smack_to_secid(isp->smk_inode);
+ *secid = isp->smk_inode->smk_secid;
}
/*
@@ -1179,7 +1349,7 @@ static int smack_file_alloc_security(struct file *file)
{
struct smack_known *skp = smk_of_current();
- file->f_security = skp->smk_known;
+ file->f_security = skp;
return 0;
}
@@ -1214,11 +1384,15 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path);
- if (_IOC_DIR(cmd) & _IOC_WRITE)
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
+ rc = smk_bu_file(file, MAY_WRITE, rc);
+ }
- if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ))
+ if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) {
rc = smk_curacc(file->f_security, MAY_READ, &ad);
+ rc = smk_bu_file(file, MAY_READ, rc);
+ }
return rc;
}
@@ -1233,10 +1407,13 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
static int smack_file_lock(struct file *file, unsigned int cmd)
{
struct smk_audit_info ad;
+ int rc;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path);
- return smk_curacc(file->f_security, MAY_LOCK, &ad);
+ rc = smk_curacc(file->f_security, MAY_LOCK, &ad);
+ rc = smk_bu_file(file, MAY_LOCK, rc);
+ return rc;
}
/**
@@ -1266,12 +1443,14 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path);
rc = smk_curacc(file->f_security, MAY_LOCK, &ad);
+ rc = smk_bu_file(file, MAY_LOCK, rc);
break;
case F_SETOWN:
case F_SETSIG:
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path);
rc = smk_curacc(file->f_security, MAY_WRITE, &ad);
+ rc = smk_bu_file(file, MAY_WRITE, rc);
break;
default:
break;
@@ -1298,7 +1477,7 @@ static int smack_mmap_file(struct file *file,
struct smack_known *mkp;
struct smack_rule *srp;
struct task_smack *tsp;
- char *osmack;
+ struct smack_known *okp;
struct inode_smack *isp;
int may;
int mmay;
@@ -1324,18 +1503,19 @@ static int smack_mmap_file(struct file *file,
* to that rule's object label.
*/
list_for_each_entry_rcu(srp, &skp->smk_rules, list) {
- osmack = srp->smk_object;
+ okp = srp->smk_object;
/*
* Matching labels always allows access.
*/
- if (mkp->smk_known == osmack)
+ if (mkp->smk_known == okp->smk_known)
continue;
/*
* If there is a matching local rule take
* that into account as well.
*/
- may = smk_access_entry(srp->smk_subject->smk_known, osmack,
- &tsp->smk_rules);
+ may = smk_access_entry(srp->smk_subject->smk_known,
+ okp->smk_known,
+ &tsp->smk_rules);
if (may == -ENOENT)
may = srp->smk_access;
else
@@ -1352,8 +1532,8 @@ static int smack_mmap_file(struct file *file,
* If there isn't one a SMACK64MMAP subject
* can't have as much access as current.
*/
- mmay = smk_access_entry(mkp->smk_known, osmack,
- &mkp->smk_rules);
+ mmay = smk_access_entry(mkp->smk_known, okp->smk_known,
+ &mkp->smk_rules);
if (mmay == -ENOENT) {
rc = -EACCES;
break;
@@ -1362,8 +1542,8 @@ static int smack_mmap_file(struct file *file,
* If there is a local entry it modifies the
* potential access, too.
*/
- tmay = smk_access_entry(mkp->smk_known, osmack,
- &tsp->smk_rules);
+ tmay = smk_access_entry(mkp->smk_known, okp->smk_known,
+ &tsp->smk_rules);
if (tmay != -ENOENT)
mmay &= tmay;
@@ -1394,7 +1574,7 @@ static void smack_file_set_fowner(struct file *file)
{
struct smack_known *skp = smk_of_current();
- file->f_security = skp->smk_known;
+ file->f_security = skp;
}
/**
@@ -1423,14 +1603,15 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
file = container_of(fown, struct file, f_owner);
/* we don't log here as rc can be overriden */
- skp = smk_find_entry(file->f_security);
- rc = smk_access(skp, tkp->smk_known, MAY_WRITE, NULL);
+ skp = file->f_security;
+ rc = smk_access(skp, tkp, MAY_WRITE, NULL);
+ rc = smk_bu_note("sigiotask", skp, tkp, MAY_WRITE, rc);
if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
rc = 0;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, tsk);
- smack_log(file->f_security, tkp->smk_known, MAY_WRITE, rc, &ad);
+ smack_log(skp->smk_known, tkp->smk_known, MAY_WRITE, rc, &ad);
return rc;
}
@@ -1442,6 +1623,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
*/
static int smack_file_receive(struct file *file)
{
+ int rc;
int may = 0;
struct smk_audit_info ad;
@@ -1455,7 +1637,9 @@ static int smack_file_receive(struct file *file)
if (file->f_mode & FMODE_WRITE)
may |= MAY_WRITE;
- return smk_curacc(file->f_security, may, &ad);
+ rc = smk_curacc(file->f_security, may, &ad);
+ rc = smk_bu_file(file, may, rc);
+ return rc;
}
/**
@@ -1477,12 +1661,15 @@ static int smack_file_open(struct file *file, const struct cred *cred)
struct smk_audit_info ad;
int rc;
- if (smack_privileged(CAP_MAC_OVERRIDE))
+ if (smack_privileged(CAP_MAC_OVERRIDE)) {
+ file->f_security = isp->smk_inode;
return 0;
+ }
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path);
rc = smk_access(tsp->smk_task, isp->smk_inode, MAY_READ, &ad);
+ rc = smk_bu_credfile(cred, file, MAY_READ, rc);
if (rc == 0)
file->f_security = isp->smk_inode;
@@ -1621,7 +1808,7 @@ static int smack_kernel_create_files_as(struct cred *new,
struct inode_smack *isp = inode->i_security;
struct task_smack *tsp = new->security;
- tsp->smk_forked = smk_find_entry(isp->smk_inode);
+ tsp->smk_forked = isp->smk_inode;
tsp->smk_task = tsp->smk_forked;
return 0;
}
@@ -1639,10 +1826,13 @@ static int smk_curacc_on_task(struct task_struct *p, int access,
{
struct smk_audit_info ad;
struct smack_known *skp = smk_of_task(task_security(p));
+ int rc;
smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, p);
- return smk_curacc(skp->smk_known, access, &ad);
+ rc = smk_curacc(skp, access, &ad);
+ rc = smk_bu_task(p, access, rc);
+ return rc;
}
/**
@@ -1796,6 +1986,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
struct smk_audit_info ad;
struct smack_known *skp;
struct smack_known *tkp = smk_of_task(task_security(p));
+ int rc;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
smk_ad_setfield_u_tsk(&ad, p);
@@ -1803,15 +1994,20 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
* Sending a signal requires that the sender
* can write the receiver.
*/
- if (secid == 0)
- return smk_curacc(tkp->smk_known, MAY_WRITE, &ad);
+ if (secid == 0) {
+ rc = smk_curacc(tkp, MAY_WRITE, &ad);
+ rc = smk_bu_task(p, MAY_WRITE, rc);
+ return rc;
+ }
/*
* If the secid isn't 0 we're dealing with some USB IO
* specific behavior. This is not clean. For one thing
* we can't take privilege into account.
*/
skp = smack_from_secid(secid);
- return smk_access(skp, tkp->smk_known, MAY_WRITE, &ad);
+ rc = smk_access(skp, tkp, MAY_WRITE, &ad);
+ rc = smk_bu_note("USB signal", skp, tkp, MAY_WRITE, rc);
+ return rc;
}
/**
@@ -1845,7 +2041,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
struct inode_smack *isp = inode->i_security;
struct smack_known *skp = smk_of_task(task_security(p));
- isp->smk_inode = skp->smk_known;
+ isp->smk_inode = skp;
}
/*
@@ -1903,7 +2099,7 @@ static void smack_sk_free_security(struct sock *sk)
*
* Returns the label of the far end or NULL if it's not special.
*/
-static char *smack_host_label(struct sockaddr_in *sip)
+static struct smack_known *smack_host_label(struct sockaddr_in *sip)
{
struct smk_netlbladdr *snp;
struct in_addr *siap = &sip->sin_addr;
@@ -1920,7 +2116,7 @@ static char *smack_host_label(struct sockaddr_in *sip)
if ((&snp->smk_host.sin_addr)->s_addr ==
(siap->s_addr & (&snp->smk_mask)->s_addr)) {
/* we have found the special CIPSO option */
- if (snp->smk_label == smack_cipso_option)
+ if (snp->smk_label == &smack_cipso_option)
return NULL;
return snp->smk_label;
}
@@ -1985,13 +2181,13 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
struct smack_known *skp;
int rc;
int sk_lbl;
- char *hostsp;
+ struct smack_known *hkp;
struct socket_smack *ssp = sk->sk_security;
struct smk_audit_info ad;
rcu_read_lock();
- hostsp = smack_host_label(sap);
- if (hostsp != NULL) {
+ hkp = smack_host_label(sap);
+ if (hkp != NULL) {
#ifdef CONFIG_AUDIT
struct lsm_network_audit net;
@@ -2002,7 +2198,8 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
#endif
sk_lbl = SMACK_UNLABELED_SOCKET;
skp = ssp->smk_out;
- rc = smk_access(skp, hostsp, MAY_WRITE, &ad);
+ rc = smk_access(skp, hkp, MAY_WRITE, &ad);
+ rc = smk_bu_note("IPv4 host check", skp, hkp, MAY_WRITE, rc);
} else {
sk_lbl = SMACK_CIPSO_SOCKET;
rc = 0;
@@ -2103,18 +2300,19 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
struct socket_smack *ssp = sk->sk_security;
struct smack_known *skp;
unsigned short port = 0;
- char *object;
+ struct smack_known *object;
struct smk_audit_info ad;
+ int rc;
#ifdef CONFIG_AUDIT
struct lsm_network_audit net;
#endif
if (act == SMK_RECEIVING) {
skp = smack_net_ambient;
- object = ssp->smk_in->smk_known;
+ object = ssp->smk_in;
} else {
skp = ssp->smk_out;
- object = smack_net_ambient->smk_known;
+ object = smack_net_ambient;
}
/*
@@ -2141,7 +2339,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
list_for_each_entry(spp, &smk_ipv6_port_list, list) {
if (spp->smk_port != port)
continue;
- object = spp->smk_in->smk_known;
+ object = spp->smk_in;
if (act == SMK_CONNECTING)
ssp->smk_packet = spp->smk_out;
break;
@@ -2158,7 +2356,9 @@ auditout:
else
ad.a.u.net->v6info.daddr = address->sin6_addr;
#endif
- return smk_access(skp, object, MAY_WRITE, &ad);
+ rc = smk_access(skp, object, MAY_WRITE, &ad);
+ rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc);
+ return rc;
}
/**
@@ -2190,7 +2390,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
return -EINVAL;
if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
- nsp->smk_inode = skp->smk_known;
+ nsp->smk_inode = skp;
nsp->smk_flags |= SMK_INODE_INSTANT;
return 0;
}
@@ -2332,7 +2532,7 @@ static int smack_msg_msg_alloc_security(struct msg_msg *msg)
{
struct smack_known *skp = smk_of_current();
- msg->security = skp->smk_known;
+ msg->security = skp;
return 0;
}
@@ -2353,9 +2553,9 @@ static void smack_msg_msg_free_security(struct msg_msg *msg)
*
* Returns a pointer to the smack value
*/
-static char *smack_of_shm(struct shmid_kernel *shp)
+static struct smack_known *smack_of_shm(struct shmid_kernel *shp)
{
- return (char *)shp->shm_perm.security;
+ return (struct smack_known *)shp->shm_perm.security;
}
/**
@@ -2369,7 +2569,7 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp)
struct kern_ipc_perm *isp = &shp->shm_perm;
struct smack_known *skp = smk_of_current();
- isp->security = skp->smk_known;
+ isp->security = skp;
return 0;
}
@@ -2395,14 +2595,17 @@ static void smack_shm_free_security(struct shmid_kernel *shp)
*/
static int smk_curacc_shm(struct shmid_kernel *shp, int access)
{
- char *ssp = smack_of_shm(shp);
+ struct smack_known *ssp = smack_of_shm(shp);
struct smk_audit_info ad;
+ int rc;
#ifdef CONFIG_AUDIT
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
ad.a.u.ipc_id = shp->shm_perm.id;
#endif
- return smk_curacc(ssp, access, &ad);
+ rc = smk_curacc(ssp, access, &ad);
+ rc = smk_bu_current("shm", ssp, access, rc);
+ return rc;
}
/**
@@ -2477,9 +2680,9 @@ static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
*
* Returns a pointer to the smack value
*/
-static char *smack_of_sem(struct sem_array *sma)
+static struct smack_known *smack_of_sem(struct sem_array *sma)
{
- return (char *)sma->sem_perm.security;
+ return (struct smack_known *)sma->sem_perm.security;
}
/**
@@ -2493,7 +2696,7 @@ static int smack_sem_alloc_security(struct sem_array *sma)
struct kern_ipc_perm *isp = &sma->sem_perm;
struct smack_known *skp = smk_of_current();
- isp->security = skp->smk_known;
+ isp->security = skp;
return 0;
}
@@ -2519,14 +2722,17 @@ static void smack_sem_free_security(struct sem_array *sma)
*/
static int smk_curacc_sem(struct sem_array *sma, int access)
{
- char *ssp = smack_of_sem(sma);
+ struct smack_known *ssp = smack_of_sem(sma);
struct smk_audit_info ad;
+ int rc;
#ifdef CONFIG_AUDIT
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
ad.a.u.ipc_id = sma->sem_perm.id;
#endif
- return smk_curacc(ssp, access, &ad);
+ rc = smk_curacc(ssp, access, &ad);
+ rc = smk_bu_current("sem", ssp, access, rc);
+ return rc;
}
/**
@@ -2612,7 +2818,7 @@ static int smack_msg_queue_alloc_security(struct msg_queue *msq)
struct kern_ipc_perm *kisp = &msq->q_perm;
struct smack_known *skp = smk_of_current();
- kisp->security = skp->smk_known;
+ kisp->security = skp;
return 0;
}
@@ -2633,11 +2839,11 @@ static void smack_msg_queue_free_security(struct msg_queue *msq)
* smack_of_msq - the smack pointer for the msq
* @msq: the object
*
- * Returns a pointer to the smack value
+ * Returns a pointer to the smack label entry
*/
-static char *smack_of_msq(struct msg_queue *msq)
+static struct smack_known *smack_of_msq(struct msg_queue *msq)
{
- return (char *)msq->q_perm.security;
+ return (struct smack_known *)msq->q_perm.security;
}
/**
@@ -2649,14 +2855,17 @@ static char *smack_of_msq(struct msg_queue *msq)
*/
static int smk_curacc_msq(struct msg_queue *msq, int access)
{
- char *msp = smack_of_msq(msq);
+ struct smack_known *msp = smack_of_msq(msq);
struct smk_audit_info ad;
+ int rc;
#ifdef CONFIG_AUDIT
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
ad.a.u.ipc_id = msq->q_perm.id;
#endif
- return smk_curacc(msp, access, &ad);
+ rc = smk_curacc(msp, access, &ad);
+ rc = smk_bu_current("msq", msp, access, rc);
+ return rc;
}
/**
@@ -2749,15 +2958,18 @@ static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
*/
static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
{
- char *isp = ipp->security;
+ struct smack_known *iskp = ipp->security;
int may = smack_flags_to_may(flag);
struct smk_audit_info ad;
+ int rc;
#ifdef CONFIG_AUDIT
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC);
ad.a.u.ipc_id = ipp->id;
#endif
- return smk_curacc(isp, may, &ad);
+ rc = smk_curacc(iskp, may, &ad);
+ rc = smk_bu_current("svipc", iskp, may, rc);
+ return rc;
}
/**
@@ -2767,9 +2979,9 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
*/
static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
{
- char *smack = ipp->security;
+ struct smack_known *iskp = ipp->security;
- *secid = smack_to_secid(smack);
+ *secid = iskp->smk_secid;
}
/**
@@ -2786,7 +2998,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
struct inode_smack *isp;
struct smack_known *skp;
struct smack_known *ckp = smk_of_current();
- char *final;
+ struct smack_known *final;
char trattr[TRANS_TRUE_SIZE];
int transflag = 0;
int rc;
@@ -2826,8 +3038,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
* so there's no opportunity to set the mount
* options.
*/
- sbsp->smk_root = smack_known_star.smk_known;
- sbsp->smk_default = smack_known_star.smk_known;
+ sbsp->smk_root = &smack_known_star;
+ sbsp->smk_default = &smack_known_star;
}
isp->smk_inode = sbsp->smk_root;
isp->smk_flags |= SMK_INODE_INSTANT;
@@ -2857,7 +3069,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*
* Cgroupfs is special
*/
- final = smack_known_star.smk_known;
+ final = &smack_known_star;
break;
case DEVPTS_SUPER_MAGIC:
/*
@@ -2865,7 +3077,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
* Programs that change smack have to treat the
* pty with respect.
*/
- final = ckp->smk_known;
+ final = ckp;
break;
case PROC_SUPER_MAGIC:
/*
@@ -2879,7 +3091,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
* but watch out, because they're volitile,
* getting recreated on every reboot.
*/
- final = smack_known_star.smk_known;
+ final = &smack_known_star;
/*
* No break.
*
@@ -2898,7 +3110,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
* UNIX domain sockets use lower level socket data.
*/
if (S_ISSOCK(inode->i_mode)) {
- final = smack_known_star.smk_known;
+ final = &smack_known_star;
break;
}
/*
@@ -2915,7 +3127,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
dp = dget(opt_dentry);
skp = smk_fetch(XATTR_NAME_SMACK, inode, dp);
if (skp != NULL)
- final = skp->smk_known;
+ final = skp;
/*
* Transmuting directory
@@ -2964,7 +3176,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
}
if (final == NULL)
- isp->smk_inode = ckp->smk_known;
+ isp->smk_inode = ckp;
else
isp->smk_inode = final;
@@ -3089,9 +3301,13 @@ static int smack_unix_stream_connect(struct sock *sock,
smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
smk_ad_setfield_u_net_sk(&ad, other);
#endif
- rc = smk_access(skp, okp->smk_known, MAY_WRITE, &ad);
- if (rc == 0)
- rc = smk_access(okp, okp->smk_known, MAY_WRITE, NULL);
+ rc = smk_access(skp, okp, MAY_WRITE, &ad);
+ rc = smk_bu_note("UDS connect", skp, okp, MAY_WRITE, rc);
+ if (rc == 0) {
+ rc = smk_access(okp, skp, MAY_WRITE, NULL);
+ rc = smk_bu_note("UDS connect", okp, skp,
+ MAY_WRITE, rc);
+ }
}
/*
@@ -3117,8 +3333,8 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
{
struct socket_smack *ssp = sock->sk->sk_security;
struct socket_smack *osp = other->sk->sk_security;
- struct smack_known *skp;
struct smk_audit_info ad;
+ int rc;
#ifdef CONFIG_AUDIT
struct lsm_network_audit net;
@@ -3130,8 +3346,9 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
if (smack_privileged(CAP_MAC_OVERRIDE))
return 0;
- skp = ssp->smk_out;
- return smk_access(skp, osp->smk_in->smk_known, MAY_WRITE, &ad);
+ rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad);
+ rc = smk_bu_note("UDS send", ssp->smk_out, osp->smk_in, MAY_WRITE, rc);
+ return rc;
}
/**
@@ -3345,7 +3562,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
* This is the simplist possible security model
* for networking.
*/
- rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad);
+ rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
+ rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in,
+ MAY_WRITE, rc);
if (rc != 0)
netlbl_skbuff_err(skb, rc, 0);
break;
@@ -3488,7 +3707,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
struct netlbl_lsm_secattr secattr;
struct sockaddr_in addr;
struct iphdr *hdr;
- char *hsp;
+ struct smack_known *hskp;
int rc;
struct smk_audit_info ad;
#ifdef CONFIG_AUDIT
@@ -3525,7 +3744,8 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
* Receiving a packet requires that the other end be able to write
* here. Read access is not required.
*/
- rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad);
+ rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad);
+ rc = smk_bu_note("IPv4 connect", skp, ssp->smk_in, MAY_WRITE, rc);
if (rc != 0)
return rc;
@@ -3543,10 +3763,10 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
hdr = ip_hdr(skb);
addr.sin_addr.s_addr = hdr->saddr;
rcu_read_lock();
- hsp = smack_host_label(&addr);
+ hskp = smack_host_label(&addr);
rcu_read_unlock();
- if (hsp == NULL)
+ if (hskp == NULL)
rc = netlbl_req_setattr(req, &skp->smk_netlabel);
else
netlbl_req_delattr(req);
@@ -3598,7 +3818,7 @@ static int smack_key_alloc(struct key *key, const struct cred *cred,
{
struct smack_known *skp = smk_of_task(cred->security);
- key->security = skp->smk_known;
+ key->security = skp;
return 0;
}
@@ -3629,6 +3849,7 @@ static int smack_key_permission(key_ref_t key_ref,
struct smk_audit_info ad;
struct smack_known *tkp = smk_of_task(cred->security);
int request = 0;
+ int rc;
keyp = key_ref_to_ptr(key_ref);
if (keyp == NULL)
@@ -3653,7 +3874,9 @@ static int smack_key_permission(key_ref_t key_ref,
request = MAY_READ;
if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR))
request = MAY_WRITE;
- return smk_access(tkp, keyp->security, request, &ad);
+ rc = smk_access(tkp, keyp->security, request, &ad);
+ rc = smk_bu_note("key access", tkp, keyp->security, request, rc);
+ return rc;
}
#endif /* CONFIG_KEYS */
@@ -3684,6 +3907,7 @@ static int smack_key_permission(key_ref_t key_ref,
*/
static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
{
+ struct smack_known *skp;
char **rule = (char **)vrule;
*rule = NULL;
@@ -3693,7 +3917,9 @@ static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
if (op != Audit_equal && op != Audit_not_equal)
return -EINVAL;
- *rule = smk_import(rulestr, 0);
+ skp = smk_import_entry(rulestr, 0);
+ if (skp)
+ *rule = skp->smk_known;
return 0;
}
@@ -3812,7 +4038,12 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
*/
static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
- *secid = smack_to_secid(secdata);
+ struct smack_known *skp = smk_find_entry(secdata);
+
+ if (skp)
+ *secid = skp->smk_secid;
+ else
+ *secid = 0;
return 0;
}
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 3c720ff1059..bce4e8f1b26 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -131,14 +131,17 @@ LIST_HEAD(smack_rule_list);
struct smack_parsed_rule {
struct smack_known *smk_subject;
- char *smk_object;
+ struct smack_known *smk_object;
int smk_access1;
int smk_access2;
};
static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
-const char *smack_cipso_option = SMACK_CIPSO_OPTION;
+struct smack_known smack_cipso_option = {
+ .smk_known = SMACK_CIPSO_OPTION,
+ .smk_secid = 0,
+};
/*
* Values for parsing cipso rules
@@ -304,6 +307,10 @@ static int smk_perm_from_str(const char *string)
case 'L':
perm |= MAY_LOCK;
break;
+ case 'b':
+ case 'B':
+ perm |= MAY_BRINGUP;
+ break;
default:
return perm;
}
@@ -335,7 +342,7 @@ static int smk_fill_rule(const char *subject, const char *object,
if (rule->smk_subject == NULL)
return -EINVAL;
- rule->smk_object = smk_import(object, len);
+ rule->smk_object = smk_import_entry(object, len);
if (rule->smk_object == NULL)
return -EINVAL;
} else {
@@ -355,7 +362,7 @@ static int smk_fill_rule(const char *subject, const char *object,
kfree(cp);
if (skp == NULL)
return -ENOENT;
- rule->smk_object = skp->smk_known;
+ rule->smk_object = skp;
}
rule->smk_access1 = smk_perm_from_str(access1);
@@ -594,13 +601,15 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
* anything you read back.
*/
if (strlen(srp->smk_subject->smk_known) >= max ||
- strlen(srp->smk_object) >= max)
+ strlen(srp->smk_object->smk_known) >= max)
return;
if (srp->smk_access == 0)
return;
- seq_printf(s, "%s %s", srp->smk_subject->smk_known, srp->smk_object);
+ seq_printf(s, "%s %s",
+ srp->smk_subject->smk_known,
+ srp->smk_object->smk_known);
seq_putc(s, ' ');
@@ -616,6 +625,8 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
seq_putc(s, 't');
if (srp->smk_access & MAY_LOCK)
seq_putc(s, 'l');
+ if (srp->smk_access & MAY_BRINGUP)
+ seq_putc(s, 'b');
seq_putc(s, '\n');
}
@@ -1067,7 +1078,7 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v)
for (maskn = 0; temp_mask; temp_mask <<= 1, maskn++);
seq_printf(s, "%u.%u.%u.%u/%d %s\n",
- hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label);
+ hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label->smk_known);
return 0;
}
@@ -1147,10 +1158,10 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct smk_netlbladdr *skp;
+ struct smk_netlbladdr *snp;
struct sockaddr_in newname;
char *smack;
- char *sp;
+ struct smack_known *skp;
char *data;
char *host = (char *)&newname.sin_addr.s_addr;
int rc;
@@ -1213,15 +1224,15 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
* If smack begins with '-', it is an option, don't import it
*/
if (smack[0] != '-') {
- sp = smk_import(smack, 0);
- if (sp == NULL) {
+ skp = smk_import_entry(smack, 0);
+ if (skp == NULL) {
rc = -EINVAL;
goto free_out;
}
} else {
/* check known options */
- if (strcmp(smack, smack_cipso_option) == 0)
- sp = (char *)smack_cipso_option;
+ if (strcmp(smack, smack_cipso_option.smk_known) == 0)
+ skp = &smack_cipso_option;
else {
rc = -EINVAL;
goto free_out;
@@ -1244,9 +1255,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
nsa = newname.sin_addr.s_addr;
/* try to find if the prefix is already in the list */
found = 0;
- list_for_each_entry_rcu(skp, &smk_netlbladdr_list, list) {
- if (skp->smk_host.sin_addr.s_addr == nsa &&
- skp->smk_mask.s_addr == mask.s_addr) {
+ list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list) {
+ if (snp->smk_host.sin_addr.s_addr == nsa &&
+ snp->smk_mask.s_addr == mask.s_addr) {
found = 1;
break;
}
@@ -1254,26 +1265,26 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
smk_netlabel_audit_set(&audit_info);
if (found == 0) {
- skp = kzalloc(sizeof(*skp), GFP_KERNEL);
- if (skp == NULL)
+ snp = kzalloc(sizeof(*snp), GFP_KERNEL);
+ if (snp == NULL)
rc = -ENOMEM;
else {
rc = 0;
- skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr;
- skp->smk_mask.s_addr = mask.s_addr;
- skp->smk_label = sp;
- smk_netlbladdr_insert(skp);
+ snp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr;
+ snp->smk_mask.s_addr = mask.s_addr;
+ snp->smk_label = skp;
+ smk_netlbladdr_insert(snp);
}
} else {
/* we delete the unlabeled entry, only if the previous label
* wasn't the special CIPSO option */
- if (skp->smk_label != smack_cipso_option)
+ if (snp->smk_label != &smack_cipso_option)
rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
- &skp->smk_host.sin_addr, &skp->smk_mask,
+ &snp->smk_host.sin_addr, &snp->smk_mask,
PF_INET, &audit_info);
else
rc = 0;
- skp->smk_label = sp;
+ snp->smk_label = skp;
}
/*
@@ -1281,10 +1292,10 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
* this host so that incoming packets get labeled.
* but only if we didn't get the special CIPSO option
*/
- if (rc == 0 && sp != smack_cipso_option)
+ if (rc == 0 && skp != &smack_cipso_option)
rc = netlbl_cfg_unlbl_static_add(&init_net, NULL,
- &skp->smk_host.sin_addr, &skp->smk_mask, PF_INET,
- smack_to_secid(skp->smk_label), &audit_info);
+ &snp->smk_host.sin_addr, &snp->smk_mask, PF_INET,
+ snp->smk_label->smk_secid, &audit_info);
if (rc == 0)
rc = count;
@@ -1677,7 +1688,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
if (smack_onlycap != NULL && smack_onlycap != skp)
return -EPERM;
- data = kzalloc(count, GFP_KERNEL);
+ data = kzalloc(count + 1, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
@@ -1880,7 +1891,10 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
else if (res != -ENOENT)
return -EINVAL;
- data[0] = res == 0 ? '1' : '0';
+ /*
+ * smk_access() can return a value > 0 in the "bringup" case.
+ */
+ data[0] = res >= 0 ? '1' : '0';
data[1] = '\0';
simple_transaction_set(file, 2);
@@ -2228,7 +2242,7 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf,
if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
- data = kzalloc(count, GFP_KERNEL);
+ data = kzalloc(count + 1, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;