aboutsummaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/Kconfig20
-rw-r--r--security/dummy.c29
-rw-r--r--security/inode.c10
-rw-r--r--security/keys/internal.h3
-rw-r--r--security/keys/key.c68
-rw-r--r--security/keys/keyctl.c61
-rw-r--r--security/keys/keyring.c28
-rw-r--r--security/keys/proc.c7
-rw-r--r--security/keys/process_keys.c69
-rw-r--r--security/keys/request_key.c34
-rw-r--r--security/keys/request_key_auth.c49
-rw-r--r--security/keys/user_defined.c25
-rw-r--r--security/selinux/Kconfig29
-rw-r--r--security/selinux/exports.c22
-rw-r--r--security/selinux/hooks.c374
-rw-r--r--security/selinux/include/av_inherit.h1
-rw-r--r--security/selinux/include/av_perm_to_string.h12
-rw-r--r--security/selinux/include/av_permissions.h36
-rw-r--r--security/selinux/include/class_to_string.h3
-rw-r--r--security/selinux/include/flask.h3
-rw-r--r--security/selinux/include/objsec.h7
-rw-r--r--security/selinux/include/xfrm.h4
-rw-r--r--security/selinux/selinuxfs.c73
-rw-r--r--security/selinux/ss/services.c2
-rw-r--r--security/selinux/xfrm.c51
25 files changed, 786 insertions, 234 deletions
diff --git a/security/Kconfig b/security/Kconfig
index 34f593410d57..67785df264e5 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -22,16 +22,22 @@ config KEYS
If you are unsure as to whether this is required, answer N.
config KEYS_DEBUG_PROC_KEYS
- bool "Enable the /proc/keys file by which all keys may be viewed"
+ bool "Enable the /proc/keys file by which keys may be viewed"
depends on KEYS
help
- This option turns on support for the /proc/keys file through which
- all the keys on the system can be listed.
+ This option turns on support for the /proc/keys file - through which
+ can be listed all the keys on the system that are viewable by the
+ reading process.
- This option is a slight security risk in that it makes it possible
- for anyone to see all the keys on the system. Normally the manager
- pretends keys that are inaccessible to a process don't exist as far
- as that process is concerned.
+ The only keys included in the list are those that grant View
+ permission to the reading process whether or not it possesses them.
+ Note that LSM security checks are still performed, and may further
+ filter out keys that the current process is not authorised to view.
+
+ Only key attributes are listed here; key payloads are not included in
+ the resulting table.
+
+ If you are unsure as to whether this is required, answer N.
config SECURITY
bool "Enable different security models"
diff --git a/security/dummy.c b/security/dummy.c
index 8ccccccc12ac..310fcdf7b749 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -191,7 +191,7 @@ static int dummy_sb_kern_mount (struct super_block *sb, void *data)
return 0;
}
-static int dummy_sb_statfs (struct super_block *sb)
+static int dummy_sb_statfs (struct dentry *dentry)
{
return 0;
}
@@ -516,6 +516,11 @@ static int dummy_task_setnice (struct task_struct *p, int nice)
return 0;
}
+static int dummy_task_setioprio (struct task_struct *p, int ioprio)
+{
+ return 0;
+}
+
static int dummy_task_setrlimit (unsigned int resource, struct rlimit *new_rlim)
{
return 0;
@@ -532,6 +537,11 @@ static int dummy_task_getscheduler (struct task_struct *p)
return 0;
}
+static int dummy_task_movememory (struct task_struct *p)
+{
+ return 0;
+}
+
static int dummy_task_wait (struct task_struct *p)
{
return 0;
@@ -810,6 +820,11 @@ static void dummy_xfrm_policy_free_security(struct xfrm_policy *xp)
{
}
+static int dummy_xfrm_policy_delete_security(struct xfrm_policy *xp)
+{
+ return 0;
+}
+
static int dummy_xfrm_state_alloc_security(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx)
{
return 0;
@@ -819,6 +834,11 @@ static void dummy_xfrm_state_free_security(struct xfrm_state *x)
{
}
+static int dummy_xfrm_state_delete_security(struct xfrm_state *x)
+{
+ return 0;
+}
+
static int dummy_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir)
{
return 0;
@@ -850,7 +870,8 @@ static int dummy_setprocattr(struct task_struct *p, char *name, void *value, siz
}
#ifdef CONFIG_KEYS
-static inline int dummy_key_alloc(struct key *key)
+static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx,
+ unsigned long flags)
{
return 0;
}
@@ -962,9 +983,11 @@ void security_fixup_ops (struct security_operations *ops)
set_to_dummy_if_null(ops, task_getsid);
set_to_dummy_if_null(ops, task_setgroups);
set_to_dummy_if_null(ops, task_setnice);
+ set_to_dummy_if_null(ops, task_setioprio);
set_to_dummy_if_null(ops, task_setrlimit);
set_to_dummy_if_null(ops, task_setscheduler);
set_to_dummy_if_null(ops, task_getscheduler);
+ set_to_dummy_if_null(ops, task_movememory);
set_to_dummy_if_null(ops, task_wait);
set_to_dummy_if_null(ops, task_kill);
set_to_dummy_if_null(ops, task_prctl);
@@ -1024,8 +1047,10 @@ void security_fixup_ops (struct security_operations *ops)
set_to_dummy_if_null(ops, xfrm_policy_alloc_security);
set_to_dummy_if_null(ops, xfrm_policy_clone_security);
set_to_dummy_if_null(ops, xfrm_policy_free_security);
+ set_to_dummy_if_null(ops, xfrm_policy_delete_security);
set_to_dummy_if_null(ops, xfrm_state_alloc_security);
set_to_dummy_if_null(ops, xfrm_state_free_security);
+ set_to_dummy_if_null(ops, xfrm_state_delete_security);
set_to_dummy_if_null(ops, xfrm_policy_lookup);
#endif /* CONFIG_SECURITY_NETWORK_XFRM */
#ifdef CONFIG_KEYS
diff --git a/security/inode.c b/security/inode.c
index 0f77b0223662..98a0df500dc6 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -135,11 +135,11 @@ static int fill_super(struct super_block *sb, void *data, int silent)
return simple_fill_super(sb, SECURITYFS_MAGIC, files);
}
-static struct super_block *get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, fill_super);
+ return get_sb_single(fs_type, flags, data, fill_super, mnt);
}
static struct file_system_type fs_type = {
@@ -224,7 +224,7 @@ struct dentry *securityfs_create_file(const char *name, mode_t mode,
pr_debug("securityfs: creating file '%s'\n",name);
- error = simple_pin_fs("securityfs", &mount, &mount_count);
+ error = simple_pin_fs(&fs_type, &mount, &mount_count);
if (error) {
dentry = ERR_PTR(error);
goto exit;
diff --git a/security/keys/internal.h b/security/keys/internal.h
index e066e6057955..3c2877f0663e 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -99,7 +99,8 @@ extern int install_process_keyring(struct task_struct *tsk);
extern struct key *request_key_and_link(struct key_type *type,
const char *description,
const char *callout_info,
- struct key *dest_keyring);
+ struct key *dest_keyring,
+ unsigned long flags);
/*
* request_key authorisation
diff --git a/security/keys/key.c b/security/keys/key.c
index b6061fa29da7..43295ca37b5d 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -15,11 +15,11 @@
#include <linux/slab.h>
#include <linux/security.h>
#include <linux/workqueue.h>
+#include <linux/random.h>
#include <linux/err.h>
#include "internal.h"
static kmem_cache_t *key_jar;
-static key_serial_t key_serial_next = 3;
struct rb_root key_serial_tree; /* tree of keys indexed by serial */
DEFINE_SPINLOCK(key_serial_lock);
@@ -169,22 +169,23 @@ static void __init __key_insert_serial(struct key *key)
/*****************************************************************************/
/*
* assign a key the next unique serial number
- * - we work through all the serial numbers between 2 and 2^31-1 in turn and
- * then wrap
+ * - these are assigned randomly to avoid security issues through covert
+ * channel problems
*/
static inline void key_alloc_serial(struct key *key)
{
struct rb_node *parent, **p;
struct key *xkey;
- spin_lock(&key_serial_lock);
-
- /* propose a likely serial number and look for a hole for it in the
+ /* propose a random serial number and look for a hole for it in the
* serial number tree */
- key->serial = key_serial_next;
- if (key->serial < 3)
- key->serial = 3;
- key_serial_next = key->serial + 1;
+ do {
+ get_random_bytes(&key->serial, sizeof(key->serial));
+
+ key->serial >>= 1; /* negative numbers are not permitted */
+ } while (key->serial < 3);
+
+ spin_lock(&key_serial_lock);
parent = NULL;
p = &key_serial_tree.rb_node;
@@ -204,19 +205,18 @@ static inline void key_alloc_serial(struct key *key)
/* we found a key with the proposed serial number - walk the tree from
* that point looking for the next unused serial number */
- serial_exists:
+serial_exists:
for (;;) {
- key->serial = key_serial_next;
+ key->serial++;
if (key->serial < 2)
key->serial = 2;
- key_serial_next = key->serial + 1;
- if (!parent->rb_parent)
+ if (!rb_parent(parent))
p = &key_serial_tree.rb_node;
- else if (parent->rb_parent->rb_left == parent)
- p = &parent->rb_parent->rb_left;
+ else if (rb_parent(parent)->rb_left == parent)
+ p = &(rb_parent(parent)->rb_left);
else
- p = &parent->rb_parent->rb_right;
+ p = &(rb_parent(parent)->rb_right);
parent = rb_next(parent);
if (!parent)
@@ -228,7 +228,7 @@ static inline void key_alloc_serial(struct key *key)
}
/* we've found a suitable hole - arrange for this key to occupy it */
- insert_here:
+insert_here:
rb_link_node(&key->serial_node, parent, p);
rb_insert_color(&key->serial_node, &key_serial_tree);
@@ -247,8 +247,8 @@ static inline void key_alloc_serial(struct key *key)
* instantiate the key or discard it before returning
*/
struct key *key_alloc(struct key_type *type, const char *desc,
- uid_t uid, gid_t gid, key_perm_t perm,
- int not_in_quota)
+ uid_t uid, gid_t gid, struct task_struct *ctx,
+ key_perm_t perm, unsigned long flags)
{
struct key_user *user = NULL;
struct key *key;
@@ -269,12 +269,14 @@ struct key *key_alloc(struct key_type *type, const char *desc,
/* check that the user's quota permits allocation of another key and
* its description */
- if (!not_in_quota) {
+ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
spin_lock(&user->lock);
- if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
- user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES
- )
- goto no_quota;
+ if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
+ if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
+ user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES
+ )
+ goto no_quota;
+ }
user->qnkeys++;
user->qnbytes += quotalen;
@@ -308,7 +310,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
key->payload.data = NULL;
key->security = NULL;
- if (!not_in_quota)
+ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
key->flags |= 1 << KEY_FLAG_IN_QUOTA;
memset(&key->type_data, 0, sizeof(key->type_data));
@@ -318,7 +320,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
#endif
/* let the security module know about the key */
- ret = security_key_alloc(key);
+ ret = security_key_alloc(key, ctx, flags);
if (ret < 0)
goto security_error;
@@ -332,7 +334,7 @@ error:
security_error:
kfree(key->description);
kmem_cache_free(key_jar, key);
- if (!not_in_quota) {
+ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
spin_lock(&user->lock);
user->qnkeys--;
user->qnbytes -= quotalen;
@@ -345,7 +347,7 @@ security_error:
no_memory_3:
kmem_cache_free(key_jar, key);
no_memory_2:
- if (!not_in_quota) {
+ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
spin_lock(&user->lock);
user->qnkeys--;
user->qnbytes -= quotalen;
@@ -761,7 +763,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
const char *description,
const void *payload,
size_t plen,
- int not_in_quota)
+ unsigned long flags)
{
struct key_type *ktype;
struct key *keyring, *key = NULL;
@@ -822,7 +824,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
/* allocate a new key */
key = key_alloc(ktype, description, current->fsuid, current->fsgid,
- perm, not_in_quota);
+ current, perm, flags);
if (IS_ERR(key)) {
key_ref = ERR_PTR(PTR_ERR(key));
goto error_3;
@@ -907,6 +909,10 @@ void key_revoke(struct key *key)
* it */
down_write(&key->sem);
set_bit(KEY_FLAG_REVOKED, &key->flags);
+
+ if (key->type->revoke)
+ key->type->revoke(key);
+
up_write(&key->sem);
} /* end key_revoke() */
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index ed71d86d2ce2..329411cf8768 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -102,7 +102,7 @@ asmlinkage long sys_add_key(const char __user *_type,
/* create or update the requested key and add it to the target
* keyring */
key_ref = key_create_or_update(keyring_ref, type, description,
- payload, plen, 0);
+ payload, plen, KEY_ALLOC_IN_QUOTA);
if (!IS_ERR(key_ref)) {
ret = key_ref_to_ptr(key_ref)->serial;
key_ref_put(key_ref);
@@ -184,7 +184,8 @@ asmlinkage long sys_request_key(const char __user *_type,
/* do the search */
key = request_key_and_link(ktype, description, callout_info,
- key_ref_to_ptr(dest_ref));
+ key_ref_to_ptr(dest_ref),
+ KEY_ALLOC_IN_QUOTA);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error5;
@@ -672,6 +673,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
*/
long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
{
+ struct key_user *newowner, *zapowner = NULL;
struct key *key;
key_ref_t key_ref;
long ret;
@@ -695,19 +697,50 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
if (!capable(CAP_SYS_ADMIN)) {
/* only the sysadmin can chown a key to some other UID */
if (uid != (uid_t) -1 && key->uid != uid)
- goto no_access;
+ goto error_put;
/* only the sysadmin can set the key's GID to a group other
* than one of those that the current process subscribes to */
if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid))
- goto no_access;
+ goto error_put;
}
- /* change the UID (have to update the quotas) */
+ /* change the UID */
if (uid != (uid_t) -1 && uid != key->uid) {
- /* don't support UID changing yet */
- ret = -EOPNOTSUPP;
- goto no_access;
+ ret = -ENOMEM;
+ newowner = key_user_lookup(uid);
+ if (!newowner)
+ goto error_put;
+
+ /* transfer the quota burden to the new user */
+ if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
+ spin_lock(&newowner->lock);
+ if (newowner->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
+ newowner->qnbytes + key->quotalen >=
+ KEYQUOTA_MAX_BYTES)
+ goto quota_overrun;
+
+ newowner->qnkeys++;
+ newowner->qnbytes += key->quotalen;
+ spin_unlock(&newowner->lock);
+
+ spin_lock(&key->user->lock);
+ key->user->qnkeys--;
+ key->user->qnbytes -= key->quotalen;
+ spin_unlock(&key->user->lock);
+ }
+
+ atomic_dec(&key->user->nkeys);
+ atomic_inc(&newowner->nkeys);
+
+ if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
+ atomic_dec(&key->user->nikeys);
+ atomic_inc(&newowner->nikeys);
+ }
+
+ zapowner = key->user;
+ key->user = newowner;
+ key->uid = uid;
}
/* change the GID */
@@ -716,12 +749,20 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
ret = 0;
- no_access:
+error_put:
up_write(&key->sem);
key_put(key);
- error:
+ if (zapowner)
+ key_user_put(zapowner);
+error:
return ret;
+quota_overrun:
+ spin_unlock(&newowner->lock);
+ zapowner = newowner;
+ ret = -EDQUOT;
+ goto error_put;
+
} /* end keyctl_chown_key() */
/*****************************************************************************/
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index bffa924c1f88..e8d02acc51e7 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -49,6 +49,7 @@ static inline unsigned keyring_hash(const char *desc)
static int keyring_instantiate(struct key *keyring,
const void *data, size_t datalen);
static int keyring_match(const struct key *keyring, const void *criterion);
+static void keyring_revoke(struct key *keyring);
static void keyring_destroy(struct key *keyring);
static void keyring_describe(const struct key *keyring, struct seq_file *m);
static long keyring_read(const struct key *keyring,
@@ -59,6 +60,7 @@ struct key_type key_type_keyring = {
.def_datalen = sizeof(struct keyring_list),
.instantiate = keyring_instantiate,
.match = keyring_match,
+ .revoke = keyring_revoke,
.destroy = keyring_destroy,
.describe = keyring_describe,
.read = keyring_read,
@@ -240,15 +242,16 @@ static long keyring_read(const struct key *keyring,
* allocate a keyring and link into the destination keyring
*/
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
- int not_in_quota, struct key *dest)
+ struct task_struct *ctx, unsigned long flags,
+ struct key *dest)
{
struct key *keyring;
int ret;
keyring = key_alloc(&key_type_keyring, description,
- uid, gid,
+ uid, gid, ctx,
(KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
- not_in_quota);
+ flags);
if (!IS_ERR(keyring)) {
ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
@@ -952,3 +955,22 @@ int keyring_clear(struct key *keyring)
} /* end keyring_clear() */
EXPORT_SYMBOL(keyring_clear);
+
+/*****************************************************************************/
+/*
+ * dispose of the links from a revoked keyring
+ * - called with the key sem write-locked
+ */
+static void keyring_revoke(struct key *keyring)
+{
+ struct keyring_list *klist = keyring->payload.subscriptions;
+
+ /* adjust the quota */
+ key_payload_reserve(keyring, 0);
+
+ if (klist) {
+ rcu_assign_pointer(keyring->payload.subscriptions, NULL);
+ call_rcu(&klist->rcu, keyring_clear_rcu_disposal);
+ }
+
+} /* end keyring_revoke() */
diff --git a/security/keys/proc.c b/security/keys/proc.c
index 12b750e51fbf..686a9ee0c5de 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -137,6 +137,13 @@ static int proc_keys_show(struct seq_file *m, void *v)
struct timespec now;
unsigned long timo;
char xbuf[12];
+ int rc;
+
+ /* check whether the current task is allowed to view the key (assuming
+ * non-possession) */
+ rc = key_task_permission(make_key_ref(key, 0), current, KEY_VIEW);
+ if (rc < 0)
+ return 0;
now = current_kernel_time();
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 217a0bef3c82..32150cf7c37f 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -67,7 +67,8 @@ struct key root_session_keyring = {
/*
* allocate the keyrings to be associated with a UID
*/
-int alloc_uid_keyring(struct user_struct *user)
+int alloc_uid_keyring(struct user_struct *user,
+ struct task_struct *ctx)
{
struct key *uid_keyring, *session_keyring;
char buf[20];
@@ -76,7 +77,8 @@ int alloc_uid_keyring(struct user_struct *user)
/* concoct a default session keyring */
sprintf(buf, "_uid_ses.%u", user->uid);
- session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, NULL);
+ session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
+ KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(session_keyring)) {
ret = PTR_ERR(session_keyring);
goto error;
@@ -86,8 +88,8 @@ int alloc_uid_keyring(struct user_struct *user)
* keyring */
sprintf(buf, "_uid.%u", user->uid);
- uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0,
- session_keyring);
+ uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
+ KEY_ALLOC_IN_QUOTA, session_keyring);
if (IS_ERR(uid_keyring)) {
key_put(session_keyring);
ret = PTR_ERR(uid_keyring);
@@ -143,7 +145,8 @@ int install_thread_keyring(struct task_struct *tsk)
sprintf(buf, "_tid.%u", tsk->pid);
- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+ keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+ KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
@@ -177,7 +180,8 @@ int install_process_keyring(struct task_struct *tsk)
if (!tsk->signal->process_keyring) {
sprintf(buf, "_pid.%u", tsk->tgid);
- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+ keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+ KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
@@ -208,6 +212,7 @@ error:
static int install_session_keyring(struct task_struct *tsk,
struct key *keyring)
{
+ unsigned long flags;
struct key *old;
char buf[20];
@@ -217,7 +222,12 @@ static int install_session_keyring(struct task_struct *tsk,
if (!keyring) {
sprintf(buf, "_ses.%u", tsk->tgid);
- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL);
+ flags = KEY_ALLOC_QUOTA_OVERRUN;
+ if (tsk->signal->session_keyring)
+ flags = KEY_ALLOC_IN_QUOTA;
+
+ keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+ flags, NULL);
if (IS_ERR(keyring))
return PTR_ERR(keyring);
}
@@ -390,6 +400,8 @@ key_ref_t search_process_keyrings(struct key_type *type,
struct request_key_auth *rka;
key_ref_t key_ref, ret, err;
+ might_sleep();
+
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
* searchable, but we failed to find a key or we found a negative key;
* otherwise we want to return a sample error (probably -EACCES) if
@@ -495,27 +507,35 @@ key_ref_t search_process_keyrings(struct key_type *type,
*/
if (context->request_key_auth &&
context == current &&
- type != &key_type_request_key_auth &&
- key_validate(context->request_key_auth) == 0
+ type != &key_type_request_key_auth
) {
- rka = context->request_key_auth->payload.data;
+ /* defend against the auth key being revoked */
+ down_read(&context->request_key_auth->sem);
- key_ref = search_process_keyrings(type, description, match,
- rka->context);
+ if (key_validate(context->request_key_auth) == 0) {
+ rka = context->request_key_auth->payload.data;
- if (!IS_ERR(key_ref))
- goto found;
+ key_ref = search_process_keyrings(type, description,
+ match, rka->context);
- switch (PTR_ERR(key_ref)) {
- case -EAGAIN: /* no key */
- if (ret)
+ up_read(&context->request_key_auth->sem);
+
+ if (!IS_ERR(key_ref))
+ goto found;
+
+ switch (PTR_ERR(key_ref)) {
+ case -EAGAIN: /* no key */
+ if (ret)
+ break;
+ case -ENOKEY: /* negative key */
+ ret = key_ref;
break;
- case -ENOKEY: /* negative key */
- ret = key_ref;
- break;
- default:
- err = key_ref;
- break;
+ default:
+ err = key_ref;
+ break;
+ }
+ } else {
+ up_read(&context->request_key_auth->sem);
}
}
@@ -717,7 +737,8 @@ long join_session_keyring(const char *name)
keyring = find_keyring_by_name(name, 0);
if (PTR_ERR(keyring) == -ENOKEY) {
/* not found - try and create a new one */
- keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL);
+ keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk,
+ KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index f030a0ccbb93..58d1efd4fc2c 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -48,7 +48,8 @@ static int call_sbin_request_key(struct key *key,
/* allocate a new session keyring */
sprintf(desc, "_req.%u", key->serial);
- keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL);
+ keyring = keyring_alloc(desc, current->fsuid, current->fsgid, current,
+ KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error_alloc;
@@ -125,7 +126,8 @@ error_alloc:
*/
static struct key *__request_key_construction(struct key_type *type,
const char *description,
- const char *callout_info)
+ const char *callout_info,
+ unsigned long flags)
{
request_key_actor_t actor;
struct key_construction cons;
@@ -133,11 +135,12 @@ static struct key *__request_key_construction(struct key_type *type,
struct key *key, *authkey;
int ret, negated;
- kenter("%s,%s,%s", type->name, description, callout_info);
+ kenter("%s,%s,%s,%lx", type->name, description, callout_info, flags);
/* create a key and add it to the queue */
key = key_alloc(type, description,
- current->fsuid, current->fsgid, KEY_POS_ALL, 0);
+ current->fsuid, current->fsgid, current, KEY_POS_ALL,
+ flags);
if (IS_ERR(key))
goto alloc_failed;
@@ -256,15 +259,16 @@ alloc_failed:
static struct key *request_key_construction(struct key_type *type,
const char *description,
struct key_user *user,
- const char *callout_info)
+ const char *callout_info,
+ unsigned long flags)
{
struct key_construction *pcons;
struct key *key, *ckey;
DECLARE_WAITQUEUE(myself, current);
- kenter("%s,%s,{%d},%s",
- type->name, description, user->uid, callout_info);
+ kenter("%s,%s,{%d},%s,%lx",
+ type->name, description, user->uid, callout_info, flags);
/* see if there's such a key under construction already */
down_write(&key_construction_sem);
@@ -280,7 +284,8 @@ static struct key *request_key_construction(struct key_type *type,
}
/* see about getting userspace to construct the key */
- key = __request_key_construction(type, description, callout_info);
+ key = __request_key_construction(type, description, callout_info,
+ flags);
error:
kleave(" = %p", key);
return key;
@@ -387,14 +392,15 @@ static void request_key_link(struct key *key, struct key *dest_keyring)
struct key *request_key_and_link(struct key_type *type,
const char *description,
const char *callout_info,
- struct key *dest_keyring)
+ struct key *dest_keyring,
+ unsigned long flags)
{
struct key_user *user;
struct key *key;
key_ref_t key_ref;
- kenter("%s,%s,%s,%p",
- type->name, description, callout_info, dest_keyring);
+ kenter("%s,%s,%s,%p,%lx",
+ type->name, description, callout_info, dest_keyring, flags);
/* search all the process keyrings for a key */
key_ref = search_process_keyrings(type, description, type->match,
@@ -427,7 +433,8 @@ struct key *request_key_and_link(struct key_type *type,
/* ask userspace (returns NULL if it waited on a key
* being constructed) */
key = request_key_construction(type, description,
- user, callout_info);
+ user, callout_info,
+ flags);
if (key)
break;
@@ -483,7 +490,8 @@ struct key *request_key(struct key_type *type,
const char *description,
const char *callout_info)
{
- return request_key_and_link(type, description, callout_info, NULL);
+ return request_key_and_link(type, description, callout_info, NULL,
+ KEY_ALLOC_IN_QUOTA);
} /* end request_key() */
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index cce6ba6b0323..cbf58a91b00a 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -20,6 +20,7 @@
static int request_key_auth_instantiate(struct key *, const void *, size_t);
static void request_key_auth_describe(const struct key *, struct seq_file *);
+static void request_key_auth_revoke(struct key *);
static void request_key_auth_destroy(struct key *);
static long request_key_auth_read(const struct key *, char __user *, size_t);
@@ -31,6 +32,7 @@ struct key_type key_type_request_key_auth = {
.def_datalen = sizeof(struct request_key_auth),
.instantiate = request_key_auth_instantiate,
.describe = request_key_auth_describe,
+ .revoke = request_key_auth_revoke,
.destroy = request_key_auth_destroy,
.read = request_key_auth_read,
};
@@ -93,6 +95,24 @@ static long request_key_auth_read(const struct key *key,
/*****************************************************************************/
/*
+ * handle revocation of an authorisation token key
+ * - called with the key sem write-locked
+ */
+static void request_key_auth_revoke(struct key *key)
+{
+ struct request_key_auth *rka = key->payload.data;
+
+ kenter("{%d}", key->serial);
+
+ if (rka->context) {
+ put_task_struct(rka->context);
+ rka->context = NULL;
+ }
+
+} /* end request_key_auth_revoke() */
+
+/*****************************************************************************/
+/*
* destroy an instantiation authorisation token key
*/
static void request_key_auth_destroy(struct key *key)
@@ -101,6 +121,11 @@ static void request_key_auth_destroy(struct key *key)
kenter("{%d}", key->serial);
+ if (rka->context) {
+ put_task_struct(rka->context);
+ rka->context = NULL;
+ }
+
key_put(rka->target_key);
kfree(rka);
@@ -131,14 +156,26 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
* another process */
if (current->request_key_auth) {
/* it is - use that instantiation context here too */
+ down_read(&current->request_key_auth->sem);
+
+ /* if the auth key has been revoked, then the key we're
+ * servicing is already instantiated */
+ if (test_bit(KEY_FLAG_REVOKED,
+ &current->request_key_auth->flags))
+ goto auth_key_revoked;
+
irka = current->request_key_auth->payload.data;
rka->context = irka->context;
rka->pid = irka->pid;
+ get_task_struct(rka->context);
+
+ up_read(&current->request_key_auth->sem);
}
else {
/* it isn't - use this process as the context */
rka->context = current;
rka->pid = current->pid;
+ get_task_struct(rka->context);
}
rka->target_key = key_get(target);
@@ -148,9 +185,9 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
sprintf(desc, "%x", target->serial);
authkey = key_alloc(&key_type_request_key_auth, desc,
- current->fsuid, current->fsgid,
+ current->fsuid, current->fsgid, current,
KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
- KEY_USR_VIEW, 1);
+ KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(authkey)) {
ret = PTR_ERR(authkey);
goto error_alloc;
@@ -161,9 +198,15 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info)
if (ret < 0)
goto error_inst;
- kleave(" = {%d})", authkey->serial);
+ kleave(" = {%d}", authkey->serial);
return authkey;
+auth_key_revoked:
+ up_read(&current->request_key_auth->sem);
+ kfree(rka);
+ kleave("= -EKEYREVOKED");
+ return ERR_PTR(-EKEYREVOKED);
+
error_inst:
key_revoke(authkey);
key_put(authkey);
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 8e71895b97a7..5bbfdebb7acf 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -28,6 +28,7 @@ struct key_type key_type_user = {
.instantiate = user_instantiate,
.update = user_update,
.match = user_match,
+ .revoke = user_revoke,
.destroy = user_destroy,
.describe = user_describe,
.read = user_read,
@@ -67,6 +68,7 @@ error:
return ret;
} /* end user_instantiate() */
+
EXPORT_SYMBOL_GPL(user_instantiate);
/*****************************************************************************/
@@ -141,7 +143,28 @@ EXPORT_SYMBOL_GPL(user_match);
/*****************************************************************************/
/*
- * dispose of the data dangling from the corpse of a user
+ * dispose of the links from a revoked keyring
+ * - called with the key sem write-locked
+ */
+void user_revoke(struct key *key)
+{
+ struct user_key_payload *upayload = key->payload.data;
+
+ /* clear the quota */
+ key_payload_reserve(key, 0);
+
+ if (upayload) {
+ rcu_assign_pointer(key->payload.data, NULL);
+ call_rcu(&upayload->rcu, user_update_rcu_disposal);
+ }
+
+} /* end user_revoke() */
+
+EXPORT_SYMBOL(user_revoke);
+
+/*****************************************************************************/
+/*
+ * dispose of the data dangling from the corpse of a user key
*/
void user_destroy(struct key *key)
{
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index f636f53ca544..814ddc42f1f4 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -1,6 +1,7 @@
config SECURITY_SELINUX
bool "NSA SELinux Support"
depends on SECURITY_NETWORK && AUDIT && NET && INET
+ select NETWORK_SECMARK
default n
help
This selects NSA Security-Enhanced Linux (SELinux).
@@ -95,3 +96,31 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE
via /selinux/checkreqprot if authorized by policy.
If you are unsure how to answer this question, answer 1.
+
+config SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
+ bool "NSA SELinux enable new secmark network controls by default"
+ depends on SECURITY_SELINUX
+ default n
+ help
+ This option determines whether the new secmark-based network
+ controls will be enabled by default. If not, the old internal
+ per-packet controls will be enabled by default, preserving
+ old behavior.
+
+ If you enable the new controls, you will need updated
+ SELinux userspace libraries, tools and policy. Typically,
+ your distribution will provide these and enable the new controls
+ in the kernel they also distribute.
+
+ Note that this option can be overriden at boot with the
+ selinux_compat_net parameter, and after boot via
+ /selinux/compat_net. See Documentation/kernel-parameters.txt
+ for details on this parameter.
+
+ If you enable the new network controls, you will likely
+ also require the SECMARK and CONNSECMARK targets, as
+ well as any conntrack helpers for protocols which you
+ wish to control.
+
+ If you are unsure what do do here, select N.
+
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
index ae4c73eb3085..9d7737db5e51 100644
--- a/security/selinux/exports.c
+++ b/security/selinux/exports.c
@@ -72,3 +72,25 @@ void selinux_get_task_sid(struct task_struct *tsk, u32 *sid)
*sid = 0;
}
+int selinux_string_to_sid(char *str, u32 *sid)
+{
+ if (selinux_enabled)
+ return security_context_to_sid(str, strlen(str), sid);
+ else {
+ *sid = 0;
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(selinux_string_to_sid);
+
+int selinux_relabel_packet_permission(u32 sid)
+{
+ if (selinux_enabled) {
+ struct task_security_struct *tsec = current->security;
+
+ return avc_has_perm(tsec->sid, sid, SECCLASS_PACKET,
+ PACKET__RELABELTO, NULL);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(selinux_relabel_packet_permission);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 90b4cdc0c948..ac7f2b2e3924 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -80,6 +80,7 @@
extern unsigned int policydb_loaded_version;
extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
+extern int selinux_compat_net;
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
int selinux_enforcing = 0;
@@ -696,6 +697,8 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
return SECCLASS_PACKET_SOCKET;
case PF_KEY:
return SECCLASS_KEY_SOCKET;
+ case PF_APPLETALK:
+ return SECCLASS_APPLETALK_SOCKET;
}
return SECCLASS_SOCKET;
@@ -1096,6 +1099,17 @@ static int may_create(struct inode *dir,
FILESYSTEM__ASSOCIATE, &ad);
}
+/* Check whether a task can create a key. */
+static int may_create_key(u32 ksid,
+ struct task_struct *ctx)
+{
+ struct task_security_struct *tsec;
+
+ tsec = ctx->security;
+
+ return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
+}
+
#define MAY_LINK 0
#define MAY_UNLINK 1
#define MAY_RMDIR 2
@@ -1518,8 +1532,9 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm)
/* Default to the current task SID. */
bsec->sid = tsec->sid;
- /* Reset create SID on execve. */
+ /* Reset create and sockcreate SID on execve. */
tsec->create_sid = 0;
+ tsec->sockcreate_sid = 0;
if (tsec->exec_sid) {
newsid = tsec->exec_sid;
@@ -1900,13 +1915,13 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data)
return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);
}
-static int selinux_sb_statfs(struct super_block *sb)
+static int selinux_sb_statfs(struct dentry *dentry)
{
struct avc_audit_data ad;
AVC_AUDIT_DATA_INIT(&ad,FS);
- ad.u.fs.dentry = sb->s_root;
- return superblock_has_perm(current, sb, FILESYSTEM__GETATTR, &ad);
+ ad.u.fs.dentry = dentry->d_sb->s_root;
+ return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
}
static int selinux_mount(char * dev_name,
@@ -2571,9 +2586,10 @@ static int selinux_task_alloc_security(struct task_struct *tsk)
tsec2->osid = tsec1->osid;
tsec2->sid = tsec1->sid;
- /* Retain the exec and create SIDs across fork */
+ /* Retain the exec, create, and sock SIDs across fork */
tsec2->exec_sid = tsec1->exec_sid;
tsec2->create_sid = tsec1->create_sid;
+ tsec2->sockcreate_sid = tsec1->sockcreate_sid;
/* Retain ptracer SID across fork, if any.
This will be reset by the ptrace hook upon any
@@ -2642,6 +2658,11 @@ static int selinux_task_setnice(struct task_struct *p, int nice)
return task_has_perm(current,p, PROCESS__SETSCHED);
}
+static int selinux_task_setioprio(struct task_struct *p, int ioprio)
+{
+ return task_has_perm(current, p, PROCESS__SETSCHED);
+}
+
static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
{
struct rlimit *old_rlim = current->signal->rlim + resource;
@@ -2671,6 +2692,11 @@ static int selinux_task_getscheduler(struct task_struct *p)
return task_has_perm(current, p, PROCESS__GETSCHED);
}
+static int selinux_task_movememory(struct task_struct *p)
+{
+ return task_has_perm(current, p, PROCESS__SETSCHED);
+}
+
static int selinux_task_kill(struct task_struct *p, struct siginfo *info, int sig)
{
u32 perm;
@@ -2913,12 +2939,14 @@ static int selinux_socket_create(int family, int type,
{
int err = 0;
struct task_security_struct *tsec;
+ u32 newsid;
if (kern)
goto out;
tsec = current->security;
- err = avc_has_perm(tsec->sid, tsec->sid,
+ newsid = tsec->sockcreate_sid ? : tsec->sid;
+ err = avc_has_perm(tsec->sid, newsid,
socket_type_to_security_class(family, type,
protocol), SOCKET__CREATE, NULL);
@@ -2931,12 +2959,14 @@ static void selinux_socket_post_create(struct socket *sock, int family,
{
struct inode_security_struct *isec;
struct task_security_struct *tsec;
+ u32 newsid;
isec = SOCK_INODE(sock)->i_security;
tsec = current->security;
+ newsid = tsec->sockcreate_sid ? : tsec->sid;
isec->sclass = socket_type_to_security_class(family, type, protocol);
- isec->sid = kern ? SECINITSID_KERNEL : tsec->sid;
+ isec->sid = kern ? SECINITSID_KERNEL : newsid;
isec->initialized = 1;
return;
@@ -3214,47 +3244,17 @@ static int selinux_socket_unix_may_send(struct socket *sock,
return 0;
}
-static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
+ struct avc_audit_data *ad, u32 sock_sid, u16 sock_class,
+ u16 family, char *addrp, int len)
{
- u16 family;
- char *addrp;
- int len, err = 0;
+ int err = 0;
u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0;
- u32 sock_sid = 0;
- u16 sock_class = 0;
- struct socket *sock;
- struct net_device *dev;
- struct avc_audit_data ad;
- family = sk->sk_family;
- if (family != PF_INET && family != PF_INET6)
+ if (!skb->dev)
goto out;
- /* Handle mapped IPv4 packets arriving via IPv6 sockets */
- if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
- family = PF_INET;
-
- read_lock_bh(&sk->sk_callback_lock);
- sock = sk->sk_socket;
- if (sock) {
- struct inode *inode;
- inode = SOCK_INODE(sock);
- if (inode) {
- struct inode_security_struct *isec;
- isec = inode->i_security;
- sock_sid = isec->sid;
- sock_class = isec->sclass;
- }
- }
- read_unlock_bh(&sk->sk_callback_lock);
- if (!sock_sid)
- goto out;
-
- dev = skb->dev;
- if (!dev)
- goto out;
-
- err = sel_netif_sids(dev, &if_sid, NULL);
+ err = sel_netif_sids(skb->dev, &if_sid, NULL);
if (err)
goto out;
@@ -3277,44 +3277,88 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
break;
}
- AVC_AUDIT_DATA_INIT(&ad, NET);
- ad.u.net.netif = dev->name;
- ad.u.net.family = family;
-
- err = selinux_parse_skb(skb, &ad, &addrp, &len, 1);
- if (err)
- goto out;
-
- err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, &ad);
+ err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
if (err)
goto out;
- /* Fixme: this lookup is inefficient */
err = security_node_sid(family, addrp, len, &node_sid);
if (err)
goto out;
- err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, &ad);
+ err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, ad);
if (err)
goto out;
if (recv_perm) {
u32 port_sid;
- /* Fixme: make this more efficient */
err = security_port_sid(sk->sk_family, sk->sk_type,
- sk->sk_protocol, ntohs(ad.u.net.sport),
+ sk->sk_protocol, ntohs(ad->u.net.sport),
&port_sid);
if (err)
goto out;
err = avc_has_perm(sock_sid, port_sid,
- sock_class, recv_perm, &ad);
+ sock_class, recv_perm, ad);
}
- if (!err)
- err = selinux_xfrm_sock_rcv_skb(sock_sid, skb);
+out:
+ return err;
+}
+
+static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+ u16 family;
+ u16 sock_class = 0;
+ char *addrp;
+ int len, err = 0;
+ u32 sock_sid = 0;
+ struct socket *sock;
+ struct avc_audit_data ad;
+
+ family = sk->sk_family;
+ if (family != PF_INET && family != PF_INET6)
+ goto out;
+
+ /* Handle mapped IPv4 packets arriving via IPv6 sockets */
+ if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP))
+ family = PF_INET;
+
+ read_lock_bh(&sk->sk_callback_lock);
+ sock = sk->sk_socket;
+ if (sock) {
+ struct inode *inode;
+ inode = SOCK_INODE(sock);
+ if (inode) {
+ struct inode_security_struct *isec;
+ isec = inode->i_security;
+ sock_sid = isec->sid;
+ sock_class = isec->sclass;
+ }
+ }
+ read_unlock_bh(&sk->sk_callback_lock);
+ if (!sock_sid)
+ goto out;
+
+ AVC_AUDIT_DATA_INIT(&ad, NET);
+ ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]";
+ ad.u.net.family = family;
+
+ err = selinux_parse_skb(skb, &ad, &addrp, &len, 1);
+ if (err)
+ goto out;
+
+ if (selinux_compat_net)
+ err = selinux_sock_rcv_skb_compat(sk, skb, &ad, sock_sid,
+ sock_class, family,
+ addrp, len);
+ else
+ err = avc_has_perm(sock_sid, skb->secmark, SECCLASS_PACKET,
+ PACKET__RECV, &ad);
+ if (err)
+ goto out;
+ err = selinux_xfrm_sock_rcv_skb(sock_sid, skb);
out:
return err;
}
@@ -3454,42 +3498,18 @@ out:
#ifdef CONFIG_NETFILTER
-static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
- struct sk_buff **pskb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *),
- u16 family)
+static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev,
+ struct inode_security_struct *isec,
+ struct avc_audit_data *ad,
+ u16 family, char *addrp, int len)
{
- char *addrp;
- int len, err = NF_ACCEPT;
+ int err;
u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0;
- struct sock *sk;
- struct socket *sock;
- struct inode *inode;
- struct sk_buff *skb = *pskb;
- struct inode_security_struct *isec;
- struct avc_audit_data ad;
- struct net_device *dev = (struct net_device *)out;
- sk = skb->sk;
- if (!sk)
- goto out;
-
- sock = sk->sk_socket;
- if (!sock)
- goto out;
-
- inode = SOCK_INODE(sock);
- if (!inode)
- goto out;
-
err = sel_netif_sids(dev, &if_sid, NULL);
if (err)
goto out;
- isec = inode->i_security;
-
switch (isec->sclass) {
case SECCLASS_UDP_SOCKET:
netif_perm = NETIF__UDP_SEND;
@@ -3509,55 +3529,88 @@ static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
break;
}
-
- AVC_AUDIT_DATA_INIT(&ad, NET);
- ad.u.net.netif = dev->name;
- ad.u.net.family = family;
-
- err = selinux_parse_skb(skb, &ad, &addrp,
- &len, 0) ? NF_DROP : NF_ACCEPT;
- if (err != NF_ACCEPT)
- goto out;
-
- err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF,
- netif_perm, &ad) ? NF_DROP : NF_ACCEPT;
- if (err != NF_ACCEPT)
+ err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
+ if (err)
goto out;
- /* Fixme: this lookup is inefficient */
- err = security_node_sid(family, addrp, len,
- &node_sid) ? NF_DROP : NF_ACCEPT;
- if (err != NF_ACCEPT)
+ err = security_node_sid(family, addrp, len, &node_sid);
+ if (err)
goto out;
- err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE,
- node_perm, &ad) ? NF_DROP : NF_ACCEPT;
- if (err != NF_ACCEPT)
+ err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, ad);
+ if (err)
goto out;
if (send_perm) {
u32 port_sid;
- /* Fixme: make this more efficient */
err = security_port_sid(sk->sk_family,
sk->sk_type,
sk->sk_protocol,
- ntohs(ad.u.net.dport),
- &port_sid) ? NF_DROP : NF_ACCEPT;
- if (err != NF_ACCEPT)
+ ntohs(ad->u.net.dport),
+ &port_sid);
+ if (err)
goto out;
err = avc_has_perm(isec->sid, port_sid, isec->sclass,
- send_perm, &ad) ? NF_DROP : NF_ACCEPT;
+ send_perm, ad);
}
+out:
+ return err;
+}
+
+static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *),
+ u16 family)
+{
+ char *addrp;
+ int len, err = 0;
+ struct sock *sk;
+ struct socket *sock;
+ struct inode *inode;
+ struct sk_buff *skb = *pskb;
+ struct inode_security_struct *isec;
+ struct avc_audit_data ad;
+ struct net_device *dev = (struct net_device *)out;
- if (err != NF_ACCEPT)
+ sk = skb->sk;
+ if (!sk)
goto out;
- err = selinux_xfrm_postroute_last(isec->sid, skb);
+ sock = sk->sk_socket;
+ if (!sock)
+ goto out;
+
+ inode = SOCK_INODE(sock);
+ if (!inode)
+ goto out;
+
+ isec = inode->i_security;
+
+ AVC_AUDIT_DATA_INIT(&ad, NET);
+ ad.u.net.netif = dev->name;
+ ad.u.net.family = family;
+
+ err = selinux_parse_skb(skb, &ad, &addrp, &len, 0);
+ if (err)
+ goto out;
+
+ if (selinux_compat_net)
+ err = selinux_ip_postroute_last_compat(sk, dev, isec, &ad,
+ family, addrp, len);
+ else
+ err = avc_has_perm(isec->sid, skb->secmark, SECCLASS_PACKET,
+ PACKET__SEND, &ad);
+
+ if (err)
+ goto out;
+ err = selinux_xfrm_postroute_last(isec->sid, skb);
out:
- return err;
+ return err ? NF_DROP : NF_ACCEPT;
}
static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum,
@@ -4114,6 +4167,10 @@ static int selinux_getprocattr(struct task_struct *p,
sid = tsec->exec_sid;
else if (!strcmp(name, "fscreate"))
sid = tsec->create_sid;
+ else if (!strcmp(name, "keycreate"))
+ sid = tsec->keycreate_sid;
+ else if (!strcmp(name, "sockcreate"))
+ sid = tsec->sockcreate_sid;
else
return -EINVAL;
@@ -4146,6 +4203,10 @@ static int selinux_setprocattr(struct task_struct *p,
error = task_has_perm(current, p, PROCESS__SETEXEC);
else if (!strcmp(name, "fscreate"))
error = task_has_perm(current, p, PROCESS__SETFSCREATE);
+ else if (!strcmp(name, "keycreate"))
+ error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
+ else if (!strcmp(name, "sockcreate"))
+ error = task_has_perm(current, p, PROCESS__SETSOCKCREATE);
else if (!strcmp(name, "current"))
error = task_has_perm(current, p, PROCESS__SETCURRENT);
else
@@ -4175,6 +4236,13 @@ static int selinux_setprocattr(struct task_struct *p,
tsec->exec_sid = sid;
else if (!strcmp(name, "fscreate"))
tsec->create_sid = sid;
+ else if (!strcmp(name, "keycreate")) {
+ error = may_create_key(sid, p);
+ if (error)
+ return error;
+ tsec->keycreate_sid = sid;
+ } else if (!strcmp(name, "sockcreate"))
+ tsec->sockcreate_sid = sid;
else if (!strcmp(name, "current")) {
struct av_decision avd;
@@ -4226,6 +4294,61 @@ static int selinux_setprocattr(struct task_struct *p,
return size;
}
+#ifdef CONFIG_KEYS
+
+static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
+ unsigned long flags)
+{
+ struct task_security_struct *tsec = tsk->security;
+ struct key_security_struct *ksec;
+
+ ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
+ if (!ksec)
+ return -ENOMEM;
+
+ ksec->obj = k;
+ if (tsec->keycreate_sid)
+ ksec->sid = tsec->keycreate_sid;
+ else
+ ksec->sid = tsec->sid;
+ k->security = ksec;
+
+ return 0;
+}
+
+static void selinux_key_free(struct key *k)
+{
+ struct key_security_struct *ksec = k->security;
+
+ k->security = NULL;
+ kfree(ksec);
+}
+
+static int selinux_key_permission(key_ref_t key_ref,
+ struct task_struct *ctx,
+ key_perm_t perm)
+{
+ struct key *key;
+ struct task_security_struct *tsec;
+ struct key_security_struct *ksec;
+
+ key = key_ref_to_ptr(key_ref);
+
+ tsec = ctx->security;
+ ksec = key->security;
+
+ /* if no specific permissions are requested, we skip the
+ permission check. No serious, additional covert channels
+ appear to be created. */
+ if (perm == 0)
+ return 0;
+
+ return avc_has_perm(tsec->sid, ksec->sid,
+ SECCLASS_KEY, perm, NULL);
+}
+
+#endif
+
static struct security_operations selinux_ops = {
.ptrace = selinux_ptrace,
.capget = selinux_capget,
@@ -4306,9 +4429,11 @@ static struct security_operations selinux_ops = {
.task_getsid = selinux_task_getsid,
.task_setgroups = selinux_task_setgroups,
.task_setnice = selinux_task_setnice,
+ .task_setioprio = selinux_task_setioprio,
.task_setrlimit = selinux_task_setrlimit,
.task_setscheduler = selinux_task_setscheduler,
.task_getscheduler = selinux_task_getscheduler,
+ .task_movememory = selinux_task_movememory,
.task_kill = selinux_task_kill,
.task_wait = selinux_task_wait,
.task_prctl = selinux_task_prctl,
@@ -4374,10 +4499,18 @@ static struct security_operations selinux_ops = {
.xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
.xfrm_policy_clone_security = selinux_xfrm_policy_clone,
.xfrm_policy_free_security = selinux_xfrm_policy_free,
+ .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
.xfrm_state_alloc_security = selinux_xfrm_state_alloc,
.xfrm_state_free_security = selinux_xfrm_state_free,
+ .xfrm_state_delete_security = selinux_xfrm_state_delete,
.xfrm_policy_lookup = selinux_xfrm_policy_lookup,
#endif
+
+#ifdef CONFIG_KEYS
+ .key_alloc = selinux_key_alloc,
+ .key_free = selinux_key_free,
+ .key_permission = selinux_key_permission,
+#endif
};
static __init int selinux_init(void)
@@ -4413,6 +4546,15 @@ static __init int selinux_init(void)
} else {
printk(KERN_INFO "SELinux: Starting in permissive mode\n");
}
+
+#ifdef CONFIG_KEYS
+ /* Add security information to initial keyrings */
+ selinux_key_alloc(&root_user_keyring, current,
+ KEY_ALLOC_NOT_IN_QUOTA);
+ selinux_key_alloc(&root_session_keyring, current,
+ KEY_ALLOC_NOT_IN_QUOTA);
+#endif
+
return 0;
}
diff --git a/security/selinux/include/av_inherit.h b/security/selinux/include/av_inherit.h
index b0e6b12931c9..a68fdd55597f 100644
--- a/security/selinux/include/av_inherit.h
+++ b/security/selinux/include/av_inherit.h
@@ -29,3 +29,4 @@
S_(SECCLASS_NETLINK_IP6FW_SOCKET, socket, 0x00400000UL)
S_(SECCLASS_NETLINK_DNRT_SOCKET, socket, 0x00400000UL)
S_(SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET, socket, 0x00400000UL)
+ S_(SECCLASS_APPLETALK_SOCKET, socket, 0x00400000UL)
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index 591e98d9315a..7c9b58380833 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -72,6 +72,8 @@
S_(SECCLASS_PROCESS, PROCESS__EXECMEM, "execmem")
S_(SECCLASS_PROCESS, PROCESS__EXECSTACK, "execstack")
S_(SECCLASS_PROCESS, PROCESS__EXECHEAP, "execheap")
+ S_(SECCLASS_PROCESS, PROCESS__SETKEYCREATE, "setkeycreate")
+ S_(SECCLASS_PROCESS, PROCESS__SETSOCKCREATE, "setsockcreate")
S_(SECCLASS_MSGQ, MSGQ__ENQUEUE, "enqueue")
S_(SECCLASS_MSG, MSG__SEND, "send")
S_(SECCLASS_MSG, MSG__RECEIVE, "receive")
@@ -239,3 +241,13 @@
S_(SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, "sendto")
S_(SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, "recvfrom")
S_(SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, "setcontext")
+ S_(SECCLASS_PACKET, PACKET__SEND, "send")
+ S_(SECCLASS_PACKET, PACKET__RECV, "recv")
+ S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto")
+ S_(SECCLASS_KEY, KEY__VIEW, "view")
+ S_(SECCLASS_KEY, KEY__READ, "read")
+ S_(SECCLASS_KEY, KEY__WRITE, "write")
+ S_(SECCLASS_KEY, KEY__SEARCH, "search")
+ S_(SECCLASS_KEY, KEY__LINK, "link")
+ S_(SECCLASS_KEY, KEY__SETATTR, "setattr")
+ S_(SECCLASS_KEY, KEY__CREATE, "create")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index d7f02edf3930..69fd4b48202c 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -467,6 +467,8 @@
#define PROCESS__EXECMEM 0x02000000UL
#define PROCESS__EXECSTACK 0x04000000UL
#define PROCESS__EXECHEAP 0x08000000UL
+#define PROCESS__SETKEYCREATE 0x10000000UL
+#define PROCESS__SETSOCKCREATE 0x20000000UL
#define IPC__CREATE 0x00000001UL
#define IPC__DESTROY 0x00000002UL
@@ -933,3 +935,37 @@
#define NETLINK_KOBJECT_UEVENT_SOCKET__SEND_MSG 0x00100000UL
#define NETLINK_KOBJECT_UEVENT_SOCKET__NAME_BIND 0x00200000UL
+#define APPLETALK_SOCKET__IOCTL 0x00000001UL
+#define APPLETALK_SOCKET__READ 0x00000002UL
+#define APPLETALK_SOCKET__WRITE 0x00000004UL
+#define APPLETALK_SOCKET__CREATE 0x00000008UL
+#define APPLETALK_SOCKET__GETATTR 0x00000010UL
+#define APPLETALK_SOCKET__SETATTR 0x00000020UL
+#define APPLETALK_SOCKET__LOCK 0x00000040UL
+#define APPLETALK_SOCKET__RELABELFROM 0x00000080UL
+#define APPLETALK_SOCKET__RELABELTO 0x00000100UL
+#define APPLETALK_SOCKET__APPEND 0x00000200UL
+#define APPLETALK_SOCKET__BIND 0x00000400UL
+#define APPLETALK_SOCKET__CONNECT 0x00000800UL
+#define APPLETALK_SOCKET__LISTEN 0x00001000UL
+#define APPLETALK_SOCKET__ACCEPT 0x00002000UL
+#define APPLETALK_SOCKET__GETOPT 0x00004000UL
+#define APPLETALK_SOCKET__SETOPT 0x00008000UL
+#define APPLETALK_SOCKET__SHUTDOWN 0x00010000UL
+#define APPLETALK_SOCKET__RECVFROM 0x00020000UL
+#define APPLETALK_SOCKET__SENDTO 0x00040000UL
+#define APPLETALK_SOCKET__RECV_MSG 0x00080000UL
+#define APPLETALK_SOCKET__SEND_MSG 0x00100000UL
+#define APPLETALK_SOCKET__NAME_BIND 0x00200000UL
+
+#define PACKET__SEND 0x00000001UL
+#define PACKET__RECV 0x00000002UL
+#define PACKET__RELABELTO 0x00000004UL
+
+#define KEY__VIEW 0x00000001UL
+#define KEY__READ 0x00000002UL
+#define KEY__WRITE 0x00000004UL
+#define KEY__SEARCH 0x00000008UL
+#define KEY__LINK 0x00000010UL
+#define KEY__SETATTR 0x00000020UL
+#define KEY__CREATE 0x00000040UL
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h
index 77b2c5996f35..24303b61309f 100644
--- a/security/selinux/include/class_to_string.h
+++ b/security/selinux/include/class_to_string.h
@@ -58,3 +58,6 @@
S_("nscd")
S_("association")
S_("netlink_kobject_uevent_socket")
+ S_("appletalk_socket")
+ S_("packet")
+ S_("key")
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h
index eb9f50823f6e..95887aed2a68 100644
--- a/security/selinux/include/flask.h
+++ b/security/selinux/include/flask.h
@@ -60,6 +60,9 @@
#define SECCLASS_NSCD 53
#define SECCLASS_ASSOCIATION 54
#define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 55
+#define SECCLASS_APPLETALK_SOCKET 56
+#define SECCLASS_PACKET 57
+#define SECCLASS_KEY 58
/*
* Security identifier indices for initial entities
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 54c030778882..cf54a304169a 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -32,6 +32,8 @@ struct task_security_struct {
u32 sid; /* current SID */
u32 exec_sid; /* exec SID */
u32 create_sid; /* fscreate SID */
+ u32 keycreate_sid; /* keycreate SID */
+ u32 sockcreate_sid; /* fscreate SID */
u32 ptrace_sid; /* SID of ptrace parent */
};
@@ -99,6 +101,11 @@ struct sk_security_struct {
u32 peer_sid; /* SID of peer */
};
+struct key_security_struct {
+ struct key *obj; /* back pointer */
+ u32 sid; /* SID of key */
+};
+
extern unsigned int selinux_checkreqprot;
#endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
index c10f1fc41502..c96498a10eb8 100644
--- a/security/selinux/include/xfrm.h
+++ b/security/selinux/include/xfrm.h
@@ -9,8 +9,10 @@
int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx);
int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new);
void selinux_xfrm_policy_free(struct xfrm_policy *xp);
+int selinux_xfrm_policy_delete(struct xfrm_policy *xp);
int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx);
void selinux_xfrm_state_free(struct xfrm_state *x);
+int selinux_xfrm_state_delete(struct xfrm_state *x);
int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir);
/*
@@ -49,7 +51,7 @@ static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb)
static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb)
{
- return NF_ACCEPT;
+ return 0;
}
static inline int selinux_socket_getpeer_stream(struct sock *sk)
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index a4efc966f065..7029bbc9bef8 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -38,6 +38,14 @@
unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
+#ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
+#define SELINUX_COMPAT_NET_VALUE 0
+#else
+#define SELINUX_COMPAT_NET_VALUE 1
+#endif
+
+int selinux_compat_net = SELINUX_COMPAT_NET_VALUE;
+
static int __init checkreqprot_setup(char *str)
{
selinux_checkreqprot = simple_strtoul(str,NULL,0) ? 1 : 0;
@@ -45,6 +53,13 @@ static int __init checkreqprot_setup(char *str)
}
__setup("checkreqprot=", checkreqprot_setup);
+static int __init selinux_compat_net_setup(char *str)
+{
+ selinux_compat_net = simple_strtoul(str,NULL,0) ? 1 : 0;
+ return 1;
+}
+__setup("selinux_compat_net=", selinux_compat_net_setup);
+
static DEFINE_MUTEX(sel_mutex);
@@ -85,6 +100,7 @@ enum sel_inos {
SEL_AVC, /* AVC management directory */
SEL_MEMBER, /* compute polyinstantiation membership decision */
SEL_CHECKREQPROT, /* check requested protection, not kernel-applied one */
+ SEL_COMPAT_NET, /* whether to use old compat network packet controls */
};
#define TMPBUFLEN 12
@@ -364,6 +380,55 @@ static struct file_operations sel_checkreqprot_ops = {
.write = sel_write_checkreqprot,
};
+static ssize_t sel_read_compat_net(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char tmpbuf[TMPBUFLEN];
+ ssize_t length;
+
+ length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_compat_net);
+ return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
+}
+
+static ssize_t sel_write_compat_net(struct file * file, const char __user * buf,
+ size_t count, loff_t *ppos)
+{
+ char *page;
+ ssize_t length;
+ int new_value;
+
+ length = task_has_security(current, SECURITY__LOAD_POLICY);
+ if (length)
+ return length;
+
+ if (count >= PAGE_SIZE)
+ return -ENOMEM;
+ if (*ppos != 0) {
+ /* No partial writes. */
+ return -EINVAL;
+ }
+ page = (char*)get_zeroed_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+ length = -EFAULT;
+ if (copy_from_user(page, buf, count))
+ goto out;
+
+ length = -EINVAL;
+ if (sscanf(page, "%d", &new_value) != 1)
+ goto out;
+
+ selinux_compat_net = new_value ? 1 : 0;
+ length = count;
+out:
+ free_page((unsigned long) page);
+ return length;
+}
+static struct file_operations sel_compat_net_ops = {
+ .read = sel_read_compat_net,
+ .write = sel_write_compat_net,
+};
+
/*
* Remaining nodes use transaction based IO methods like nfsd/nfsctl.c
*/
@@ -1219,6 +1284,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
[SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR},
[SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO},
[SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
+ [SEL_COMPAT_NET] = {"compat_net", &sel_compat_net_ops, S_IRUGO|S_IWUSR},
/* last one */ {""}
};
ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
@@ -1279,10 +1345,11 @@ err:
goto out;
}
-static struct super_block *sel_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int sel_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
{
- return get_sb_single(fs_type, flags, data, sel_fill_super);
+ return get_sb_single(fs_type, flags, data, sel_fill_super, mnt);
}
static struct file_system_type sel_fs_type = {
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index c284dbb8b8c0..e9548bc049e1 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1980,7 +1980,7 @@ int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
break;
case AUDIT_SE_SEN:
case AUDIT_SE_CLR:
- level = (op == AUDIT_SE_SEN ?
+ level = (field == AUDIT_SE_SEN ?
&ctxt->range.level[0] : &ctxt->range.level[1]);
switch (op) {
case AUDIT_EQUAL:
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index abe99d881376..6633fb059313 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -132,10 +132,7 @@ static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_us
goto out;
/*
- * Does the subject have permission to set security or permission to
- * do the relabel?
- * Must be permitted to relabel from default socket type (process type)
- * to specified context
+ * Does the subject have permission to set security context?
*/
rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
SECCLASS_ASSOCIATION,
@@ -201,6 +198,23 @@ void selinux_xfrm_policy_free(struct xfrm_policy *xp)
}
/*
+ * LSM hook implementation that authorizes deletion of labeled policies.
+ */
+int selinux_xfrm_policy_delete(struct xfrm_policy *xp)
+{
+ struct task_security_struct *tsec = current->security;
+ struct xfrm_sec_ctx *ctx = xp->security;
+ int rc = 0;
+
+ if (ctx)
+ rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
+ SECCLASS_ASSOCIATION,
+ ASSOCIATION__SETCONTEXT, NULL);
+
+ return rc;
+}
+
+/*
* LSM hook implementation that allocs and transfers sec_ctx spec to
* xfrm_state.
*/
@@ -292,6 +306,23 @@ u32 selinux_socket_getpeer_dgram(struct sk_buff *skb)
return SECSID_NULL;
}
+ /*
+ * LSM hook implementation that authorizes deletion of labeled SAs.
+ */
+int selinux_xfrm_state_delete(struct xfrm_state *x)
+{
+ struct task_security_struct *tsec = current->security;
+ struct xfrm_sec_ctx *ctx = x->security;
+ int rc = 0;
+
+ if (ctx)
+ rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
+ SECCLASS_ASSOCIATION,
+ ASSOCIATION__SETCONTEXT, NULL);
+
+ return rc;
+}
+
/*
* LSM hook that controls access to unlabelled packets. If
* a xfrm_state is authorizable (defined by macro) then it was
@@ -356,18 +387,12 @@ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb)
struct xfrm_state *x = dst_test->xfrm;
if (x && selinux_authorizable_xfrm(x))
- goto accept;
+ goto out;
}
}
rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
ASSOCIATION__SENDTO, NULL);
- if (rc)
- goto drop;
-
-accept:
- return NF_ACCEPT;
-
-drop:
- return NF_DROP;
+out:
+ return rc;
}