summaryrefslogtreecommitdiffstats
path: root/security/selinux
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/avc.c169
-rw-r--r--security/selinux/hooks.c515
-rw-r--r--security/selinux/include/av_perm_to_string.h2
-rw-r--r--security/selinux/include/av_permissions.h2
-rw-r--r--security/selinux/include/netlabel.h27
-rw-r--r--security/selinux/include/objsec.h2
-rw-r--r--security/selinux/include/security.h9
-rw-r--r--security/selinux/netlabel.c186
-rw-r--r--security/selinux/nlmsgtab.c2
-rw-r--r--security/selinux/selinuxfs.c70
-rw-r--r--security/selinux/ss/services.c2
11 files changed, 304 insertions, 682 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index eb41f43e2772..7f9b5fac8779 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -88,17 +88,16 @@ struct avc_entry {
u32 tsid;
u16 tclass;
struct av_decision avd;
- atomic_t used; /* used recently */
};
struct avc_node {
struct avc_entry ae;
- struct list_head list;
+ struct hlist_node list; /* anchored in avc_cache->slots[i] */
struct rcu_head rhead;
};
struct avc_cache {
- struct list_head slots[AVC_CACHE_SLOTS];
+ struct hlist_head slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */
spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */
atomic_t lru_hint; /* LRU hint for reclaim scan */
atomic_t active_nodes;
@@ -234,7 +233,7 @@ void __init avc_init(void)
int i;
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
- INIT_LIST_HEAD(&avc_cache.slots[i]);
+ INIT_HLIST_HEAD(&avc_cache.slots[i]);
spin_lock_init(&avc_cache.slots_lock[i]);
}
atomic_set(&avc_cache.active_nodes, 0);
@@ -250,16 +249,20 @@ int avc_get_hash_stats(char *page)
{
int i, chain_len, max_chain_len, slots_used;
struct avc_node *node;
+ struct hlist_head *head;
rcu_read_lock();
slots_used = 0;
max_chain_len = 0;
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
- if (!list_empty(&avc_cache.slots[i])) {
+ head = &avc_cache.slots[i];
+ if (!hlist_empty(head)) {
+ struct hlist_node *next;
+
slots_used++;
chain_len = 0;
- list_for_each_entry_rcu(node, &avc_cache.slots[i], list)
+ hlist_for_each_entry_rcu(node, next, head, list)
chain_len++;
if (chain_len > max_chain_len)
max_chain_len = chain_len;
@@ -283,7 +286,7 @@ static void avc_node_free(struct rcu_head *rhead)
static void avc_node_delete(struct avc_node *node)
{
- list_del_rcu(&node->list);
+ hlist_del_rcu(&node->list);
call_rcu(&node->rhead, avc_node_free);
atomic_dec(&avc_cache.active_nodes);
}
@@ -297,7 +300,7 @@ static void avc_node_kill(struct avc_node *node)
static void avc_node_replace(struct avc_node *new, struct avc_node *old)
{
- list_replace_rcu(&old->list, &new->list);
+ hlist_replace_rcu(&old->list, &new->list);
call_rcu(&old->rhead, avc_node_free);
atomic_dec(&avc_cache.active_nodes);
}
@@ -307,29 +310,31 @@ static inline int avc_reclaim_node(void)
struct avc_node *node;
int hvalue, try, ecx;
unsigned long flags;
+ struct hlist_head *head;
+ struct hlist_node *next;
+ spinlock_t *lock;
for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) {
hvalue = atomic_inc_return(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1);
+ head = &avc_cache.slots[hvalue];
+ lock = &avc_cache.slots_lock[hvalue];
- if (!spin_trylock_irqsave(&avc_cache.slots_lock[hvalue], flags))
+ if (!spin_trylock_irqsave(lock, flags))
continue;
rcu_read_lock();
- list_for_each_entry(node, &avc_cache.slots[hvalue], list) {
- if (atomic_dec_and_test(&node->ae.used)) {
- /* Recently Unused */
- avc_node_delete(node);
- avc_cache_stats_incr(reclaims);
- ecx++;
- if (ecx >= AVC_CACHE_RECLAIM) {
- rcu_read_unlock();
- spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
- goto out;
- }
+ hlist_for_each_entry(node, next, head, list) {
+ avc_node_delete(node);
+ avc_cache_stats_incr(reclaims);
+ ecx++;
+ if (ecx >= AVC_CACHE_RECLAIM) {
+ rcu_read_unlock();
+ spin_unlock_irqrestore(lock, flags);
+ goto out;
}
}
rcu_read_unlock();
- spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
+ spin_unlock_irqrestore(lock, flags);
}
out:
return ecx;
@@ -344,8 +349,7 @@ static struct avc_node *avc_alloc_node(void)
goto out;
INIT_RCU_HEAD(&node->rhead);
- INIT_LIST_HEAD(&node->list);
- atomic_set(&node->ae.used, 1);
+ INIT_HLIST_NODE(&node->list);
avc_cache_stats_incr(allocations);
if (atomic_inc_return(&avc_cache.active_nodes) > avc_cache_threshold)
@@ -355,21 +359,24 @@ out:
return node;
}
-static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
+static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd)
{
node->ae.ssid = ssid;
node->ae.tsid = tsid;
node->ae.tclass = tclass;
- memcpy(&node->ae.avd, &ae->avd, sizeof(node->ae.avd));
+ memcpy(&node->ae.avd, avd, sizeof(node->ae.avd));
}
static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
{
struct avc_node *node, *ret = NULL;
int hvalue;
+ struct hlist_head *head;
+ struct hlist_node *next;
hvalue = avc_hash(ssid, tsid, tclass);
- list_for_each_entry_rcu(node, &avc_cache.slots[hvalue], list) {
+ head = &avc_cache.slots[hvalue];
+ hlist_for_each_entry_rcu(node, next, head, list) {
if (ssid == node->ae.ssid &&
tclass == node->ae.tclass &&
tsid == node->ae.tsid) {
@@ -378,15 +385,6 @@ static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
}
}
- if (ret == NULL) {
- /* cache miss */
- goto out;
- }
-
- /* cache hit */
- if (atomic_read(&ret->ae.used) != 1)
- atomic_set(&ret->ae.used, 1);
-out:
return ret;
}
@@ -395,30 +393,25 @@ out:
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
- * @requested: requested permissions, interpreted based on @tclass
*
* Look up an AVC entry that is valid for the
- * @requested permissions between the SID pair
* (@ssid, @tsid), interpreting the permissions
* based on @tclass. If a valid AVC entry exists,
* then this function return the avc_node.
* Otherwise, this function returns NULL.
*/
-static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass, u32 requested)
+static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass)
{
struct avc_node *node;
avc_cache_stats_incr(lookups);
node = avc_search_node(ssid, tsid, tclass);
- if (node && ((node->ae.avd.decided & requested) == requested)) {
+ if (node)
avc_cache_stats_incr(hits);
- goto out;
- }
+ else
+ avc_cache_stats_incr(misses);
- node = NULL;
- avc_cache_stats_incr(misses);
-out:
return node;
}
@@ -449,34 +442,41 @@ static int avc_latest_notif_update(int seqno, int is_insert)
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
- * @ae: AVC entry
+ * @avd: resulting av decision
*
* Insert an AVC entry for the SID pair
* (@ssid, @tsid) and class @tclass.
* The access vectors and the sequence number are
* normally provided by the security server in
* response to a security_compute_av() call. If the
- * sequence number @ae->avd.seqno is not less than the latest
+ * sequence number @avd->seqno is not less than the latest
* revocation notification, then the function copies
* the access vectors into a cache entry, returns
* avc_node inserted. Otherwise, this function returns NULL.
*/
-static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
+static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd)
{
struct avc_node *pos, *node = NULL;
int hvalue;
unsigned long flag;
- if (avc_latest_notif_update(ae->avd.seqno, 1))
+ if (avc_latest_notif_update(avd->seqno, 1))
goto out;
node = avc_alloc_node();
if (node) {
+ struct hlist_head *head;
+ struct hlist_node *next;
+ spinlock_t *lock;
+
hvalue = avc_hash(ssid, tsid, tclass);
- avc_node_populate(node, ssid, tsid, tclass, ae);
+ avc_node_populate(node, ssid, tsid, tclass, avd);
+
+ head = &avc_cache.slots[hvalue];
+ lock = &avc_cache.slots_lock[hvalue];
- spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
- list_for_each_entry(pos, &avc_cache.slots[hvalue], list) {
+ spin_lock_irqsave(lock, flag);
+ hlist_for_each_entry(pos, next, head, list) {
if (pos->ae.ssid == ssid &&
pos->ae.tsid == tsid &&
pos->ae.tclass == tclass) {
@@ -484,9 +484,9 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct avc_en
goto found;
}
}
- list_add_rcu(&node->list, &avc_cache.slots[hvalue]);
+ hlist_add_head_rcu(&node->list, head);
found:
- spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
+ spin_unlock_irqrestore(lock, flag);
}
out:
return node;
@@ -742,17 +742,22 @@ static inline int avc_sidcmp(u32 x, u32 y)
* @event : Updating event
* @perms : Permission mask bits
* @ssid,@tsid,@tclass : identifier of an AVC entry
+ * @seqno : sequence number when decision was made
*
* if a valid AVC entry doesn't exist,this function returns -ENOENT.
* if kmalloc() called internal returns NULL, this function returns -ENOMEM.
* otherwise, this function update the AVC entry. The original AVC-entry object
* will release later by RCU.
*/
-static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
+static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass,
+ u32 seqno)
{
int hvalue, rc = 0;
unsigned long flag;
struct avc_node *pos, *node, *orig = NULL;
+ struct hlist_head *head;
+ struct hlist_node *next;
+ spinlock_t *lock;
node = avc_alloc_node();
if (!node) {
@@ -762,12 +767,17 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
/* Lock the target slot */
hvalue = avc_hash(ssid, tsid, tclass);
- spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
- list_for_each_entry(pos, &avc_cache.slots[hvalue], list) {
+ head = &avc_cache.slots[hvalue];
+ lock = &avc_cache.slots_lock[hvalue];
+
+ spin_lock_irqsave(lock, flag);
+
+ hlist_for_each_entry(pos, next, head, list) {
if (ssid == pos->ae.ssid &&
tsid == pos->ae.tsid &&
- tclass == pos->ae.tclass){
+ tclass == pos->ae.tclass &&
+ seqno == pos->ae.avd.seqno){
orig = pos;
break;
}
@@ -783,7 +793,7 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
* Copy and replace original node.
*/
- avc_node_populate(node, ssid, tsid, tclass, &orig->ae);
+ avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd);
switch (event) {
case AVC_CALLBACK_GRANT:
@@ -808,7 +818,7 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
}
avc_node_replace(node, orig);
out_unlock:
- spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
+ spin_unlock_irqrestore(lock, flag);
out:
return rc;
}
@@ -823,18 +833,24 @@ int avc_ss_reset(u32 seqno)
int i, rc = 0, tmprc;
unsigned long flag;
struct avc_node *node;
+ struct hlist_head *head;
+ struct hlist_node *next;
+ spinlock_t *lock;
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
- spin_lock_irqsave(&avc_cache.slots_lock[i], flag);
+ head = &avc_cache.slots[i];
+ lock = &avc_cache.slots_lock[i];
+
+ spin_lock_irqsave(lock, flag);
/*
* With preemptable RCU, the outer spinlock does not
* prevent RCU grace periods from ending.
*/
rcu_read_lock();
- list_for_each_entry(node, &avc_cache.slots[i], list)
+ hlist_for_each_entry(node, next, head, list)
avc_node_delete(node);
rcu_read_unlock();
- spin_unlock_irqrestore(&avc_cache.slots_lock[i], flag);
+ spin_unlock_irqrestore(lock, flag);
}
for (c = avc_callbacks; c; c = c->next) {
@@ -875,10 +891,10 @@ int avc_ss_reset(u32 seqno)
int avc_has_perm_noaudit(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
unsigned flags,
- struct av_decision *avd)
+ struct av_decision *in_avd)
{
struct avc_node *node;
- struct avc_entry entry, *p_ae;
+ struct av_decision avd_entry, *avd;
int rc = 0;
u32 denied;
@@ -886,29 +902,34 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
rcu_read_lock();
- node = avc_lookup(ssid, tsid, tclass, requested);
+ node = avc_lookup(ssid, tsid, tclass);
if (!node) {
rcu_read_unlock();
- rc = security_compute_av(ssid, tsid, tclass, requested, &entry.avd);
+
+ if (in_avd)
+ avd = in_avd;
+ else
+ avd = &avd_entry;
+
+ rc = security_compute_av(ssid, tsid, tclass, requested, avd);
if (rc)
goto out;
rcu_read_lock();
- node = avc_insert(ssid, tsid, tclass, &entry);
+ node = avc_insert(ssid, tsid, tclass, avd);
+ } else {
+ if (in_avd)
+ memcpy(in_avd, &node->ae.avd, sizeof(*in_avd));
+ avd = &node->ae.avd;
}
- p_ae = node ? &node->ae : &entry;
-
- if (avd)
- memcpy(avd, &p_ae->avd, sizeof(*avd));
-
- denied = requested & ~(p_ae->avd.allowed);
+ denied = requested & ~(avd->allowed);
if (denied) {
if (flags & AVC_STRICT)
rc = -EACCES;
else if (!selinux_enforcing || security_permissive_sid(ssid))
avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,
- tsid, tclass);
+ tsid, tclass, avd->seqno);
else
rc = -EACCES;
}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 00815973d412..ba808ef6babb 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -89,11 +89,10 @@
#define XATTR_SELINUX_SUFFIX "selinux"
#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
-#define NUM_SEL_MNT_OPTS 4
+#define NUM_SEL_MNT_OPTS 5
extern unsigned int policydb_loaded_version;
extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
-extern int selinux_compat_net;
extern struct security_operations *security_ops;
/* SECMARK reference count */
@@ -311,7 +310,7 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
ssec->sid = SECINITSID_UNLABELED;
sk->sk_security = ssec;
- selinux_netlbl_sk_security_reset(ssec, family);
+ selinux_netlbl_sk_security_reset(ssec);
return 0;
}
@@ -353,6 +352,7 @@ enum {
Opt_fscontext = 2,
Opt_defcontext = 3,
Opt_rootcontext = 4,
+ Opt_labelsupport = 5,
};
static const match_table_t tokens = {
@@ -360,6 +360,7 @@ static const match_table_t tokens = {
{Opt_fscontext, FSCONTEXT_STR "%s"},
{Opt_defcontext, DEFCONTEXT_STR "%s"},
{Opt_rootcontext, ROOTCONTEXT_STR "%s"},
+ {Opt_labelsupport, LABELSUPP_STR},
{Opt_error, NULL},
};
@@ -431,7 +432,7 @@ static int sb_finish_set_opts(struct super_block *sb)
}
}
- sbsec->initialized = 1;
+ sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP);
if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
@@ -441,6 +442,12 @@ static int sb_finish_set_opts(struct super_block *sb)
sb->s_id, sb->s_type->name,
labeling_behaviors[sbsec->behavior-1]);
+ if (sbsec->behavior == SECURITY_FS_USE_GENFS ||
+ sbsec->behavior == SECURITY_FS_USE_MNTPOINT ||
+ sbsec->behavior == SECURITY_FS_USE_NONE ||
+ sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
+ sbsec->flags &= ~SE_SBLABELSUPP;
+
/* Initialize the root inode. */
rc = inode_doinit_with_dentry(root_inode, root);
@@ -487,23 +494,22 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
security_init_mnt_opts(opts);
- if (!sbsec->initialized)
+ if (!(sbsec->flags & SE_SBINITIALIZED))
return -EINVAL;
if (!ss_initialized)
return -EINVAL;
- /*
- * if we ever use sbsec flags for anything other than tracking mount
- * settings this is going to need a mask
- */
- tmp = sbsec->flags;
+ tmp = sbsec->flags & SE_MNTMASK;
/* count the number of mount options for this sb */
for (i = 0; i < 8; i++) {
if (tmp & 0x01)
opts->num_mnt_opts++;
tmp >>= 1;
}
+ /* Check if the Label support flag is set */
+ if (sbsec->flags & SE_SBLABELSUPP)
+ opts->num_mnt_opts++;
opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
if (!opts->mnt_opts) {
@@ -549,6 +555,10 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
opts->mnt_opts[i] = context;
opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
}
+ if (sbsec->flags & SE_SBLABELSUPP) {
+ opts->mnt_opts[i] = NULL;
+ opts->mnt_opts_flags[i++] = SE_SBLABELSUPP;
+ }
BUG_ON(i != opts->num_mnt_opts);
@@ -562,8 +572,10 @@ out_free:
static int bad_option(struct superblock_security_struct *sbsec, char flag,
u32 old_sid, u32 new_sid)
{
+ char mnt_flags = sbsec->flags & SE_MNTMASK;
+
/* check if the old mount command had the same options */
- if (sbsec->initialized)
+ if (sbsec->flags & SE_SBINITIALIZED)
if (!(sbsec->flags & flag) ||
(old_sid != new_sid))
return 1;
@@ -571,8 +583,8 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
/* check if we were passed the same options twice,
* aka someone passed context=a,context=b
*/
- if (!sbsec->initialized)
- if (sbsec->flags & flag)
+ if (!(sbsec->flags & SE_SBINITIALIZED))
+ if (mnt_flags & flag)
return 1;
return 0;
}
@@ -626,7 +638,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* this sb does not set any security options. (The first options
* will be used for both mounts)
*/
- if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
+ if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
&& (num_opts == 0))
goto out;
@@ -637,6 +649,9 @@ static int selinux_set_mnt_opts(struct super_block *sb,
*/
for (i = 0; i < num_opts; i++) {
u32 sid;
+
+ if (flags[i] == SE_SBLABELSUPP)
+ continue;
rc = security_context_to_sid(mount_options[i],
strlen(mount_options[i]), &sid);
if (rc) {
@@ -690,19 +705,19 @@ static int selinux_set_mnt_opts(struct super_block *sb,
}
}
- if (sbsec->initialized) {
+ if (sbsec->flags & SE_SBINITIALIZED) {
/* previously mounted with options, but not on this attempt? */
- if (sbsec->flags && !num_opts)
+ if ((sbsec->flags & SE_MNTMASK) && !num_opts)
goto out_double_mount;
rc = 0;
goto out;
}
if (strcmp(sb->s_type->name, "proc") == 0)
- sbsec->proc = 1;
+ sbsec->flags |= SE_SBPROC;
/* Determine the labeling behavior to use for this filesystem type. */
- rc = security_fs_use(sbsec->proc ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
+ rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
if (rc) {
printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
__func__, sb->s_type->name, rc);
@@ -806,10 +821,10 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
}
/* how can we clone if the old one wasn't set up?? */
- BUG_ON(!oldsbsec->initialized);
+ BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
/* if fs is reusing a sb, just let its options stand... */
- if (newsbsec->initialized)
+ if (newsbsec->flags & SE_SBINITIALIZED)
return;
mutex_lock(&newsbsec->lock);
@@ -917,7 +932,8 @@ static int selinux_parse_opts_str(char *options,
goto out_err;
}
break;
-
+ case Opt_labelsupport:
+ break;
default:
rc = -EINVAL;
printk(KERN_WARNING "SELinux: unknown mount option\n");
@@ -999,7 +1015,12 @@ static void selinux_write_opts(struct seq_file *m,
char *prefix;
for (i = 0; i < opts->num_mnt_opts; i++) {
- char *has_comma = strchr(opts->mnt_opts[i], ',');
+ char *has_comma;
+
+ if (opts->mnt_opts[i])
+ has_comma = strchr(opts->mnt_opts[i], ',');
+ else
+ has_comma = NULL;
switch (opts->mnt_opts_flags[i]) {
case CONTEXT_MNT:
@@ -1014,6 +1035,10 @@ static void selinux_write_opts(struct seq_file *m,
case DEFCONTEXT_MNT:
prefix = DEFCONTEXT_STR;
break;
+ case SE_SBLABELSUPP:
+ seq_putc(m, ',');
+ seq_puts(m, LABELSUPP_STR);
+ continue;
default:
BUG();
};
@@ -1209,7 +1234,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
goto out_unlock;
sbsec = inode->i_sb->s_security;
- if (!sbsec->initialized) {
+ if (!(sbsec->flags & SE_SBINITIALIZED)) {
/* Defer initialization until selinux_complete_init,
after the initial policy is loaded and the security
server is ready to handle calls. */
@@ -1237,19 +1262,26 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
dentry = d_find_alias(inode);
}
if (!dentry) {
- printk(KERN_WARNING "SELinux: %s: no dentry for dev=%s "
- "ino=%ld\n", __func__, inode->i_sb->s_id,
- inode->i_ino);
+ /*
+ * this is can be hit on boot when a file is accessed
+ * before the policy is loaded. When we load policy we
+ * may find inodes that have no dentry on the
+ * sbsec->isec_head list. No reason to complain as these
+ * will get fixed up the next time we go through
+ * inode_doinit with a dentry, before these inodes could
+ * be used again by userspace.
+ */
goto out_unlock;
}
len = INITCONTEXTLEN;
- context = kmalloc(len, GFP_NOFS);
+ context = kmalloc(len+1, GFP_NOFS);
if (!context) {
rc = -ENOMEM;
dput(dentry);
goto out_unlock;
}
+ context[len] = '\0';
rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
context, len);
if (rc == -ERANGE) {
@@ -1262,12 +1294,13 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
}
kfree(context);
len = rc;
- context = kmalloc(len, GFP_NOFS);
+ context = kmalloc(len+1, GFP_NOFS);
if (!context) {
rc = -ENOMEM;
dput(dentry);
goto out_unlock;
}
+ context[len] = '\0';
rc = inode->i_op->getxattr(dentry,
XATTR_NAME_SELINUX,
context, len);
@@ -1289,10 +1322,19 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
sbsec->def_sid,
GFP_NOFS);
if (rc) {
- printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
- "returned %d for dev=%s ino=%ld\n",
- __func__, context, -rc,
- inode->i_sb->s_id, inode->i_ino);
+ char *dev = inode->i_sb->s_id;
+ unsigned long ino = inode->i_ino;
+
+ if (rc == -EINVAL) {
+ if (printk_ratelimit())
+ printk(KERN_NOTICE "SELinux: inode=%lu on dev=%s was found to have an invalid "
+ "context=%s. This indicates you may need to relabel the inode or the "
+ "filesystem in question.\n", ino, dev, context);
+ } else {
+ printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) "
+ "returned %d for dev=%s ino=%ld\n",
+ __func__, context, -rc, dev, ino);
+ }
kfree(context);
/* Leave with the unlabeled SID */
rc = 0;
@@ -1326,7 +1368,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
/* Default to the fs superblock SID. */
isec->sid = sbsec->sid;
- if (sbsec->proc && !S_ISLNK(inode->i_mode)) {
+ if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
struct proc_inode *proci = PROC_I(inode);
if (proci->pde) {
isec->sclass = inode_mode_to_security_class(inode->i_mode);
@@ -1587,7 +1629,7 @@ static int may_create(struct inode *dir,
if (rc)
return rc;
- if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
+ if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
rc = security_transition_sid(sid, dsec->sid, tclass, &newsid);
if (rc)
return rc;
@@ -1801,6 +1843,8 @@ static inline u32 open_file_to_av(struct file *file)
av |= FIFO_FILE__OPEN;
else if (S_ISDIR(mode))
av |= DIR__OPEN;
+ else if (S_ISSOCK(mode))
+ av |= SOCK_FILE__OPEN;
else
printk(KERN_ERR "SELinux: WARNING: inside %s with "
"unknown mode:%o\n", __func__, mode);
@@ -1815,7 +1859,7 @@ static int selinux_ptrace_may_access(struct task_struct *child,
{
int rc;
- rc = secondary_ops->ptrace_may_access(child, mode);
+ rc = cap_ptrace_may_access(child, mode);
if (rc)
return rc;
@@ -1832,7 +1876,7 @@ static int selinux_ptrace_traceme(struct task_struct *parent)
{
int rc;
- rc = secondary_ops->ptrace_traceme(parent);
+ rc = cap_ptrace_traceme(parent);
if (rc)
return rc;
@@ -1848,7 +1892,7 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
if (error)
return error;
- return secondary_ops->capget(target, effective, inheritable, permitted);
+ return cap_capget(target, effective, inheritable, permitted);
}
static int selinux_capset(struct cred *new, const struct cred *old,
@@ -1858,7 +1902,7 @@ static int selinux_capset(struct cred *new, const struct cred *old,
{
int error;
- error = secondary_ops->capset(new, old,
+ error = cap_capset(new, old,
effective, inheritable, permitted);
if (error)
return error;
@@ -1866,12 +1910,22 @@ static int selinux_capset(struct cred *new, const struct cred *old,
return cred_has_perm(old, new, PROCESS__SETCAP);
}
+/*
+ * (This comment used to live with the selinux_task_setuid hook,
+ * which was removed).
+ *
+ * Since setuid only affects the current process, and since the SELinux
+ * controls are not based on the Linux identity attributes, SELinux does not
+ * need to control this operation. However, SELinux does control the use of
+ * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
+ */
+
static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
int cap, int audit)
{
int rc;
- rc = secondary_ops->capable(tsk, cred, cap, audit);
+ rc = cap_capable(tsk, cred, cap, audit);
if (rc)
return rc;
@@ -1997,7 +2051,7 @@ static int selinux_syslog(int type)
{
int rc;
- rc = secondary_ops->syslog(type);
+ rc = cap_syslog(type);
if (rc)
return rc;
@@ -2028,10 +2082,6 @@ static int selinux_syslog(int type)
* mapping. 0 means there is enough memory for the allocation to
* succeed and -ENOMEM implies there is not.
*
- * Note that secondary_ops->capable and task_has_perm_noaudit return 0
- * if the capability is granted, but __vm_enough_memory requires 1 if
- * the capability is granted.
- *
* Do not audit the selinux permission check, as this is applied to all
* processes that allocate mappings.
*/
@@ -2058,7 +2108,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
struct inode *inode = bprm->file->f_path.dentry->d_inode;
int rc;
- rc = secondary_ops->bprm_set_creds(bprm);
+ rc = cap_bprm_set_creds(bprm);
if (rc)
return rc;
@@ -2156,11 +2206,6 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
return 0;
}
-static int selinux_bprm_check_security(struct linux_binprm *bprm)
-{
- return secondary_ops->bprm_check_security(bprm);
-}
-
static int selinux_bprm_secureexec(struct linux_binprm *bprm)
{
const struct cred *cred = current_cred();
@@ -2180,7 +2225,7 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm)
PROCESS__NOATSECURE, NULL);
}
- return (atsecure || secondary_ops->bprm_secureexec(bprm));
+ return (atsecure || cap_bprm_secureexec(bprm));
}
extern struct vfsmount *selinuxfs_mount;
@@ -2290,8 +2335,6 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
struct rlimit *rlim, *initrlim;
int rc, i;
- secondary_ops->bprm_committing_creds(bprm);
-
new_tsec = bprm->cred->security;
if (new_tsec->sid == new_tsec->osid)
return;
@@ -2337,8 +2380,6 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
int rc, i;
unsigned long flags;
- secondary_ops->bprm_committed_creds(bprm);
-
osid = tsec->osid;
sid = tsec->sid;
@@ -2400,7 +2441,8 @@ static inline int selinux_option(char *option, int len)
return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
- match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len));
+ match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
+ match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
}
static inline void take_option(char **to, char *from, int *first, int len)
@@ -2513,11 +2555,6 @@ static int selinux_mount(char *dev_name,
void *data)
{
const struct cred *cred = current_cred();
- int rc;
-
- rc = secondary_ops->sb_mount(dev_name, path, type, flags, data);
- if (rc)
- return rc;
if (flags & MS_REMOUNT)
return superblock_has_perm(cred, path->mnt->mnt_sb,
@@ -2530,11 +2567,6 @@ static int selinux_mount(char *dev_name,
static int selinux_umount(struct vfsmount *mnt, int flags)
{
const struct cred *cred = current_cred();
- int rc;
-
- rc = secondary_ops->sb_umount(mnt, flags);
- if (rc)
- return rc;
return superblock_has_perm(cred, mnt->mnt_sb,
FILESYSTEM__UNMOUNT, NULL);
@@ -2570,7 +2602,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
sid = tsec->sid;
newsid = tsec->create_sid;
- if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) {
+ if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
rc = security_transition_sid(sid, dsec->sid,
inode_mode_to_security_class(inode->i_mode),
&newsid);
@@ -2585,14 +2617,14 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
}
/* Possibly defer initialization to selinux_complete_init. */
- if (sbsec->initialized) {
+ if (sbsec->flags & SE_SBINITIALIZED) {
struct inode_security_struct *isec = inode->i_security;
isec->sclass = inode_mode_to_security_class(inode->i_mode);
isec->sid = newsid;
isec->initialized = 1;
}
- if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
+ if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
return -EOPNOTSUPP;
if (name) {
@@ -2622,21 +2654,11 @@ static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int ma
static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
{
- int rc;
-
- rc = secondary_ops->inode_link(old_dentry, dir, new_dentry);
- if (rc)
- return rc;
return may_link(dir, old_dentry, MAY_LINK);
}
static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
{
- int rc;
-
- rc = secondary_ops->inode_unlink(dir, dentry);
- if (rc)
- return rc;
return may_link(dir, dentry, MAY_UNLINK);
}
@@ -2657,12 +2679,6 @@ static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
{
- int rc;
-
- rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
- if (rc)
- return rc;
-
return may_create(dir, dentry, inode_mode_to_security_class(mode));
}
@@ -2682,22 +2698,13 @@ static int selinux_inode_readlink(struct dentry *dentry)
static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
{
const struct cred *cred = current_cred();
- int rc;
- rc = secondary_ops->inode_follow_link(dentry, nameidata);
- if (rc)
- return rc;
return dentry_has_perm(cred, NULL, dentry, FILE__READ);
}
static int selinux_inode_permission(struct inode *inode, int mask)
{
const struct cred *cred = current_cred();
- int rc;
-
- rc = secondary_ops->inode_permission(inode, mask);
- if (rc)
- return rc;
if (!mask) {
/* No permission to check. Existence test. */
@@ -2711,11 +2718,6 @@ static int selinux_inode_permission(struct inode *inode, int mask)
static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
{
const struct cred *cred = current_cred();
- int rc;
-
- rc = secondary_ops->inode_setattr(dentry, iattr);
- if (rc)
- return rc;
if (iattr->ia_valid & ATTR_FORCE)
return 0;
@@ -2769,7 +2771,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
return selinux_inode_setotherxattr(dentry, name);
sbsec = inode->i_sb->s_security;
- if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
+ if (!(sbsec->flags & SE_SBLABELSUPP))
return -EOPNOTSUPP;
if (!is_owner_or_cap(inode))
@@ -2931,16 +2933,6 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
return len;
}
-static int selinux_inode_need_killpriv(struct dentry *dentry)
-{
- return secondary_ops->inode_need_killpriv(dentry);
-}
-
-static int selinux_inode_killpriv(struct dentry *dentry)
-{
- return secondary_ops->inode_killpriv(dentry);
-}
-
static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
{
struct inode_security_struct *isec = inode->i_security;
@@ -2952,7 +2944,6 @@ static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
static int selinux_revalidate_file_permission(struct file *file, int mask)
{
const struct cred *cred = current_cred();
- int rc;
struct inode *inode = file->f_path.dentry->d_inode;
if (!mask) {
@@ -2964,29 +2955,15 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
mask |= MAY_APPEND;
- rc = file_has_perm(cred, file,
- file_mask_to_av(inode->i_mode, mask));
- if (rc)
- return rc;
-
- return selinux_netlbl_inode_permission(inode, mask);
+ return file_has_perm(cred, file,
+ file_mask_to_av(inode->i_mode, mask));
}
static int selinux_file_permission(struct file *file, int mask)
{
- struct inode *inode = file->f_path.dentry->d_inode;
- struct file_security_struct *fsec = file->f_security;
- struct inode_security_struct *isec = inode->i_security;
- u32 sid = current_sid();
-
- if (!mask) {
+ if (!mask)
/* No permission to check. Existence test. */
return 0;
- }
-
- if (sid == fsec->sid && fsec->isid == isec->sid
- && fsec->pseqno == avc_policy_seqno())
- return selinux_netlbl_inode_permission(inode, mask);
return selinux_revalidate_file_permission(file, mask);
}
@@ -3078,18 +3055,13 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
unsigned long prot)
{
const struct cred *cred = current_cred();
- int rc;
-
- rc = secondary_ops->file_mprotect(vma, reqprot, prot);
- if (rc)
- return rc;
if (selinux_checkreqprot)
prot = reqprot;
#ifndef CONFIG_PPC32
if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
- rc = 0;
+ int rc = 0;
if (vma->vm_start >= vma->vm_mm->start_brk &&
vma->vm_end <= vma->vm_mm->brk) {
rc = cred_has_perm(cred, cred, PROCESS__EXECHEAP);
@@ -3239,12 +3211,6 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred)
static int selinux_task_create(unsigned long clone_flags)
{
- int rc;
-
- rc = secondary_ops->task_create(clone_flags);
- if (rc)
- return rc;
-
return current_has_perm(current, PROCESS__FORK);
}
@@ -3278,14 +3244,6 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old,
}
/*
- * commit new credentials
- */
-static void selinux_cred_commit(struct cred *new, const struct cred *old)
-{
- secondary_ops->cred_commit(new, old);
-}
-
-/*
* set the security data for a kernel service
* - all the creation contexts are set to unlabelled
*/
@@ -3329,29 +3287,6 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
return 0;
}
-static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
-{
- /* Since setuid only affects the current process, and
- since the SELinux controls are not based on the Linux
- identity attributes, SELinux does not need to control
- this operation. However, SELinux does control the use
- of the CAP_SETUID and CAP_SETGID capabilities using the
- capable hook. */
- return 0;
-}
-
-static int selinux_task_fix_setuid(struct cred *new, const struct cred *old,
- int flags)
-{
- return secondary_ops->task_fix_setuid(new, old, flags);
-}
-
-static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
-{
- /* See the comment for setuid above. */
- return 0;
-}
-
static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
{
return current_has_perm(p, PROCESS__SETPGID);
@@ -3372,17 +3307,11 @@ static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
*secid = task_sid(p);
}
-static int selinux_task_setgroups(struct group_info *group_info)
-{
- /* See the comment for setuid above. */
- return 0;
-}
-
static int selinux_task_setnice(struct task_struct *p, int nice)
{
int rc;
- rc = secondary_ops->task_setnice(p, nice);
+ rc = cap_task_setnice(p, nice);
if (rc)
return rc;
@@ -3393,7 +3322,7 @@ static int selinux_task_setioprio(struct task_struct *p, int ioprio)
{
int rc;
- rc = secondary_ops->task_setioprio(p, ioprio);
+ rc = cap_task_setioprio(p, ioprio);
if (rc)
return rc;
@@ -3408,11 +3337,6 @@ static int selinux_task_getioprio(struct task_struct *p)
static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
{
struct rlimit *old_rlim = current->signal->rlim + resource;
- int rc;
-
- rc = secondary_ops->task_setrlimit(resource, new_rlim);
- if (rc)
- return rc;
/* Control the ability to change the hard limit (whether
lowering or raising it), so that the hard limit can
@@ -3428,7 +3352,7 @@ static int selinux_task_setscheduler(struct task_struct *p, int policy, struct s
{
int rc;
- rc = secondary_ops->task_setscheduler(p, policy, lp);
+ rc = cap_task_setscheduler(p, policy, lp);
if (rc)
return rc;
@@ -3451,10 +3375,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
u32 perm;
int rc;
- rc = secondary_ops->task_kill(p, info, sig, secid);
- if (rc)
- return rc;
-
if (!sig)
perm = PROCESS__SIGNULL; /* null signal; existence test */
else
@@ -3467,18 +3387,6 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
return rc;
}
-static int selinux_task_prctl(int option,
- unsigned long arg2,
- unsigned long arg3,
- unsigned long arg4,
- unsigned long arg5)
-{
- /* The current prctl operations do not appear to require
- any SELinux controls since they merely observe or modify
- the state of the current process. */
- return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5);
-}
-
static int selinux_task_wait(struct task_struct *p)
{
return task_has_perm(p, current, PROCESS__SIGCHLD);
@@ -3799,7 +3707,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
sksec = sock->sk->sk_security;
sksec->sid = isec->sid;
sksec->sclass = isec->sclass;
- err = selinux_netlbl_socket_post_create(sock);
+ err = selinux_netlbl_socket_post_create(sock->sk, family);
}
return err;
@@ -3990,13 +3898,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
int size)
{
- int rc;
-
- rc = socket_has_perm(current, sock, SOCKET__WRITE);
- if (rc)
- return rc;
-
- return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
+ return socket_has_perm(current, sock, SOCKET__WRITE);
}
static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
@@ -4047,10 +3949,6 @@ static int selinux_socket_unix_stream_connect(struct socket *sock,
struct avc_audit_data ad;
int err;
- err = secondary_ops->unix_stream_connect(sock, other, newsk);
- if (err)
- return err;
-
isec = SOCK_INODE(sock)->i_security;
other_isec = SOCK_INODE(other)->i_security;
@@ -4120,72 +4018,6 @@ static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
SECCLASS_NODE, NODE__RECVFROM, ad);
}
-static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
- struct sk_buff *skb,
- struct avc_audit_data *ad,
- u16 family,
- char *addrp)
-{
- int err;
- struct sk_security_struct *sksec = sk->sk_security;
- u16 sk_class;
- u32 netif_perm, node_perm, recv_perm;
- u32 port_sid, node_sid, if_sid, sk_sid;
-
- sk_sid = sksec->sid;
- sk_class = sksec->sclass;
-
- switch (sk_class) {
- case SECCLASS_UDP_SOCKET:
- netif_perm = NETIF__UDP_RECV;
- node_perm = NODE__UDP_RECV;
- recv_perm = UDP_SOCKET__RECV_MSG;
- break;
- case SECCLASS_TCP_SOCKET:
- netif_perm = NETIF__TCP_RECV;
- node_perm = NODE__TCP_RECV;
- recv_perm = TCP_SOCKET__RECV_MSG;
- break;
- case SECCLASS_DCCP_SOCKET:
- netif_perm = NETIF__DCCP_RECV;
- node_perm = NODE__DCCP_RECV;
- recv_perm = DCCP_SOCKET__RECV_MSG;
- break;
- default:
- netif_perm = NETIF__RAWIP_RECV;
- node_perm = NODE__RAWIP_RECV;
- recv_perm = 0;
- break;
- }
-
- err = sel_netif_sid(skb->iif, &if_sid);
- if (err)
- return err;
- err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
- if (err)
- return err;
-
- err = sel_netnode_sid(addrp, family, &node_sid);
- if (err)
- return err;
- err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
- if (err)
- return err;
-
- if (!recv_perm)
- return 0;
- err = sel_netport_sid(sk->sk_protocol,
- ntohs(ad->u.net.sport), &port_sid);
- if (unlikely(err)) {
- printk(KERN_WARNING
- "SELinux: failure in"
- " selinux_sock_rcv_skb_iptables_compat(),"
- " network port label not found\n");
- return err;
- }
- return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
-}
-
static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
u16 family)
{
@@ -4203,14 +4035,12 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
if (err)
return err;
- if (selinux_compat_net)
- err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
- family, addrp);
- else if (selinux_secmark_enabled())
+ if (selinux_secmark_enabled()) {
err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
PACKET__RECV, &ad);
- if (err)
- return err;
+ if (err)
+ return err;
+ }
if (selinux_policycap_netpeer) {
err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
@@ -4252,7 +4082,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
* to the selinux_sock_rcv_skb_compat() function to deal with the
* special handling. We do this in an attempt to keep this function
* as fast and as clean as possible. */
- if (selinux_compat_net || !selinux_policycap_netpeer)
+ if (!selinux_policycap_netpeer)
return selinux_sock_rcv_skb_compat(sk, skb, family);
secmark_active = selinux_secmark_enabled();
@@ -4384,7 +4214,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
newssec->peer_sid = ssec->peer_sid;
newssec->sclass = ssec->sclass;
- selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
+ selinux_netlbl_sk_security_reset(newssec);
}
static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
@@ -4428,16 +4258,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
if (peersid == SECSID_NULL) {
req->secid = sksec->sid;
req->peer_secid = SECSID_NULL;
- return 0;
+ } else {
+ err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
+ if (err)
+ return err;
+ req->secid = newsid;
+ req->peer_secid = peersid;
}
- err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
- if (err)
- return err;
-
- req->secid = newsid;
- req->peer_secid = peersid;
- return 0;
+ return selinux_netlbl_inet_conn_request(req, family);
}
static void selinux_inet_csk_clone(struct sock *newsk,
@@ -4454,7 +4283,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
/* We don't need to take any sort of lock here as we are the only
* thread with access to newsksec */
- selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family);
+ selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
}
static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
@@ -4467,8 +4296,6 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
family = PF_INET;
selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
-
- selinux_netlbl_inet_conn_established(sk, family);
}
static void selinux_req_classify_flow(const struct request_sock *req,
@@ -4620,71 +4447,6 @@ static unsigned int selinux_ipv4_output(unsigned int hooknum,
return selinux_ip_output(skb, PF_INET);
}
-static int selinux_ip_postroute_iptables_compat(struct sock *sk,
- int ifindex,
- struct avc_audit_data *ad,
- u16 family, char *addrp)
-{
- int err;
- struct sk_security_struct *sksec = sk->sk_security;
- u16 sk_class;
- u32 netif_perm, node_perm, send_perm;
- u32 port_sid, node_sid, if_sid, sk_sid;
-
- sk_sid = sksec->sid;
- sk_class = sksec->sclass;
-
- switch (sk_class) {
- case SECCLASS_UDP_SOCKET:
- netif_perm = NETIF__UDP_SEND;
- node_perm = NODE__UDP_SEND;
- send_perm = UDP_SOCKET__SEND_MSG;
- break;
- case SECCLASS_TCP_SOCKET:
- netif_perm = NETIF__TCP_SEND;
- node_perm = NODE__TCP_SEND;
- send_perm = TCP_SOCKET__SEND_MSG;
- break;
- case SECCLASS_DCCP_SOCKET:
- netif_perm = NETIF__DCCP_SEND;
- node_perm = NODE__DCCP_SEND;
- send_perm = DCCP_SOCKET__SEND_MSG;
- break;
- default:
- netif_perm = NETIF__RAWIP_SEND;
- node_perm = NODE__RAWIP_SEND;
- send_perm = 0;
- break;
- }
-
- err = sel_netif_sid(ifindex, &if_sid);
- if (err)
- return err;
- err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
- return err;
-
- err = sel_netnode_sid(addrp, family, &node_sid);
- if (err)
- return err;
- err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
- if (err)
- return err;
-
- if (send_perm != 0)
- return 0;
-
- err = sel_netport_sid(sk->sk_protocol,
- ntohs(ad->u.net.dport), &port_sid);
- if (unlikely(err)) {
- printk(KERN_WARNING
- "SELinux: failure in"
- " selinux_ip_postroute_iptables_compat(),"
- " network port label not found\n");
- return err;
- }
- return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
-}
-
static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
int ifindex,
u16 family)
@@ -4705,15 +4467,10 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
return NF_DROP;
- if (selinux_compat_net) {
- if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
- &ad, family, addrp))
- return NF_DROP;
- } else if (selinux_secmark_enabled()) {
+ if (selinux_secmark_enabled())
if (avc_has_perm(sksec->sid, skb->secmark,
SECCLASS_PACKET, PACKET__SEND, &ad))
return NF_DROP;
- }
if (selinux_policycap_netpeer)
if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
@@ -4737,7 +4494,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
* to the selinux_ip_postroute_compat() function to deal with the
* special handling. We do this in an attempt to keep this function
* as fast and as clean as possible. */
- if (selinux_compat_net || !selinux_policycap_netpeer)
+ if (!selinux_policycap_netpeer)
return selinux_ip_postroute_compat(skb, ifindex, family);
#ifdef CONFIG_XFRM
/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
@@ -4844,7 +4601,7 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
{
int err;
- err = secondary_ops->netlink_send(sk, skb);
+ err = cap_netlink_send(sk, skb);
if (err)
return err;
@@ -4859,7 +4616,7 @@ static int selinux_netlink_recv(struct sk_buff *skb, int capability)
int err;
struct avc_audit_data ad;
- err = secondary_ops->netlink_recv(skb, capability);
+ err = cap_netlink_recv(skb, capability);
if (err)
return err;
@@ -5167,11 +4924,6 @@ static int selinux_shm_shmat(struct shmid_kernel *shp,
char __user *shmaddr, int shmflg)
{
u32 perms;
- int rc;
-
- rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg);
- if (rc)
- return rc;
if (shmflg & SHM_RDONLY)
perms = SHM__READ;
@@ -5581,7 +5333,6 @@ static struct security_operations selinux_ops = {
.netlink_recv = selinux_netlink_recv,
.bprm_set_creds = selinux_bprm_set_creds,
- .bprm_check_security = selinux_bprm_check_security,
.bprm_committing_creds = selinux_bprm_committing_creds,
.bprm_committed_creds = selinux_bprm_committed_creds,
.bprm_secureexec = selinux_bprm_secureexec,
@@ -5623,8 +5374,6 @@ static struct security_operations selinux_ops = {
.inode_getsecurity = selinux_inode_getsecurity,
.inode_setsecurity = selinux_inode_setsecurity,
.inode_listsecurity = selinux_inode_listsecurity,
- .inode_need_killpriv = selinux_inode_need_killpriv,
- .inode_killpriv = selinux_inode_killpriv,
.inode_getsecid = selinux_inode_getsecid,
.file_permission = selinux_file_permission,
@@ -5644,17 +5393,12 @@ static struct security_operations selinux_ops = {
.task_create = selinux_task_create,
.cred_free = selinux_cred_free,
.cred_prepare = selinux_cred_prepare,
- .cred_commit = selinux_cred_commit,
.kernel_act_as = selinux_kernel_act_as,
.kernel_create_files_as = selinux_kernel_create_files_as,
- .task_setuid = selinux_task_setuid,
- .task_fix_setuid = selinux_task_fix_setuid,
- .task_setgid = selinux_task_setgid,
.task_setpgid = selinux_task_setpgid,
.task_getpgid = selinux_task_getpgid,
.task_getsid = selinux_task_getsid,
.task_getsecid = selinux_task_getsecid,
- .task_setgroups = selinux_task_setgroups,
.task_setnice = selinux_task_setnice,
.task_setioprio = selinux_task_setioprio,
.task_getioprio = selinux_task_getioprio,
@@ -5664,7 +5408,6 @@ static struct security_operations selinux_ops = {
.task_movememory = selinux_task_movememory,
.task_kill = selinux_task_kill,
.task_wait = selinux_task_wait,
- .task_prctl = selinux_task_prctl,
.task_to_inode = selinux_task_to_inode,
.ipc_permission = selinux_ipc_permission,
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index c0c885427b91..31df1d7c1aee 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -24,6 +24,7 @@
S_(SECCLASS_CHR_FILE, CHR_FILE__EXECMOD, "execmod")
S_(SECCLASS_CHR_FILE, CHR_FILE__OPEN, "open")
S_(SECCLASS_BLK_FILE, BLK_FILE__OPEN, "open")
+ S_(SECCLASS_SOCK_FILE, SOCK_FILE__OPEN, "open")
S_(SECCLASS_FIFO_FILE, FIFO_FILE__OPEN, "open")
S_(SECCLASS_FD, FD__USE, "use")
S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__CONNECTTO, "connectto")
@@ -152,6 +153,7 @@
S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE, "nlmsg_write")
S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_RELAY, "nlmsg_relay")
S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV, "nlmsg_readpriv")
+ S_(SECCLASS_NETLINK_AUDIT_SOCKET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT, "nlmsg_tty_audit")
S_(SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_READ, "nlmsg_read")
S_(SECCLASS_NETLINK_IP6FW_SOCKET, NETLINK_IP6FW_SOCKET__NLMSG_WRITE, "nlmsg_write")
S_(SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, "sendto")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index 0ba79fe00e11..d645192ee950 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -174,6 +174,7 @@
#define SOCK_FILE__SWAPON 0x00004000UL
#define SOCK_FILE__QUOTAON 0x00008000UL
#define SOCK_FILE__MOUNTON 0x00010000UL
+#define SOCK_FILE__OPEN 0x00020000UL
#define FIFO_FILE__IOCTL 0x00000001UL
#define FIFO_FILE__READ 0x00000002UL
#define FIFO_FILE__WRITE 0x00000004UL
@@ -707,6 +708,7 @@
#define NETLINK_AUDIT_SOCKET__NLMSG_WRITE 0x00800000UL
#define NETLINK_AUDIT_SOCKET__NLMSG_RELAY 0x01000000UL
#define NETLINK_AUDIT_SOCKET__NLMSG_READPRIV 0x02000000UL
+#define NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT 0x04000000UL
#define NETLINK_IP6FW_SOCKET__IOCTL 0x00000001UL
#define NETLINK_IP6FW_SOCKET__READ 0x00000002UL
#define NETLINK_IP6FW_SOCKET__WRITE 0x00000004UL
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h
index b913c8d06038..b4b5b9b2f0be 100644
--- a/security/selinux/include/netlabel.h
+++ b/security/selinux/include/netlabel.h
@@ -32,6 +32,7 @@
#include <linux/net.h>
#include <linux/skbuff.h>
#include <net/sock.h>
+#include <net/request_sock.h>
#include "avc.h"
#include "objsec.h"
@@ -42,8 +43,7 @@ void selinux_netlbl_cache_invalidate(void);
void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway);
void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec);
-void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
- int family);
+void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec);
int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
u16 family,
@@ -53,9 +53,9 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
u16 family,
u32 sid);
-void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family);
-int selinux_netlbl_socket_post_create(struct socket *sock);
-int selinux_netlbl_inode_permission(struct inode *inode, int mask);
+int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family);
+void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family);
+int selinux_netlbl_socket_post_create(struct sock *sk, u16 family);
int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
struct sk_buff *skb,
u16 family,
@@ -85,8 +85,7 @@ static inline void selinux_netlbl_sk_security_free(
}
static inline void selinux_netlbl_sk_security_reset(
- struct sk_security_struct *ssec,
- int family)
+ struct sk_security_struct *ssec)
{
return;
}
@@ -113,17 +112,17 @@ static inline int selinux_netlbl_conn_setsid(struct sock *sk,
return 0;
}
-static inline void selinux_netlbl_inet_conn_established(struct sock *sk,
- u16 family)
+static inline int selinux_netlbl_inet_conn_request(struct request_sock *req,
+ u16 family)
{
- return;
+ return 0;
}
-static inline int selinux_netlbl_socket_post_create(struct socket *sock)
+static inline void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
{
- return 0;
+ return;
}
-static inline int selinux_netlbl_inode_permission(struct inode *inode,
- int mask)
+static inline int selinux_netlbl_socket_post_create(struct sock *sk,
+ u16 family)
{
return 0;
}
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 3cc45168f674..c4e062336ef3 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -60,9 +60,7 @@ struct superblock_security_struct {
u32 def_sid; /* default SID for labeling */
u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */
unsigned int behavior; /* labeling behavior */
- unsigned char initialized; /* initialization flag */
unsigned char flags; /* which mount options were specified */
- unsigned char proc; /* proc fs */
struct mutex lock;
struct list_head isec_head;
spinlock_t isec_lock;
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 72447370bc95..5c3434f7626f 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -37,15 +37,23 @@
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_BOUNDARY
#endif
+/* Mask for just the mount related flags */
+#define SE_MNTMASK 0x0f
+/* Super block security struct flags for mount options */
#define CONTEXT_MNT 0x01
#define FSCONTEXT_MNT 0x02
#define ROOTCONTEXT_MNT 0x04
#define DEFCONTEXT_MNT 0x08
+/* Non-mount related flags */
+#define SE_SBINITIALIZED 0x10
+#define SE_SBPROC 0x20
+#define SE_SBLABELSUPP 0x40
#define CONTEXT_STR "context="
#define FSCONTEXT_STR "fscontext="
#define ROOTCONTEXT_STR "rootcontext="
#define DEFCONTEXT_STR "defcontext="
+#define LABELSUPP_STR "seclabel"
struct netlbl_lsm_secattr;
@@ -80,7 +88,6 @@ int security_policycap_supported(unsigned int req_cap);
#define SEL_VEC_MAX 32
struct av_decision {
u32 allowed;
- u32 decided;
u32 auditallow;
u32 auditdeny;
u32 seqno;
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 350794ab9b42..2e984413c7b2 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -100,41 +100,6 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
}
/**
- * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
- * @sk: the socket to label
- *
- * Description:
- * Attempt to label a socket using the NetLabel mechanism. Returns zero values
- * on success, negative values on failure.
- *
- */
-static int selinux_netlbl_sock_setsid(struct sock *sk)
-{
- int rc;
- struct sk_security_struct *sksec = sk->sk_security;
- struct netlbl_lsm_secattr *secattr;
-
- if (sksec->nlbl_state != NLBL_REQUIRE)
- return 0;
-
- secattr = selinux_netlbl_sock_genattr(sk);
- if (secattr == NULL)
- return -ENOMEM;
- rc = netlbl_sock_setattr(sk, secattr);
- switch (rc) {
- case 0:
- sksec->nlbl_state = NLBL_LABELED;
- break;
- case -EDESTADDRREQ:
- sksec->nlbl_state = NLBL_REQSKB;
- rc = 0;
- break;
- }
-
- return rc;
-}
-
-/**
* selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
*
* Description:
@@ -188,13 +153,9 @@ void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec)
* The caller is responsibile for all the NetLabel sk_security_struct locking.
*
*/
-void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
- int family)
+void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec)
{
- if (family == PF_INET)
- ssec->nlbl_state = NLBL_REQUIRE;
- else
- ssec->nlbl_state = NLBL_UNSET;
+ ssec->nlbl_state = NLBL_UNSET;
}
/**
@@ -281,127 +242,86 @@ skbuff_setsid_return:
}
/**
- * selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection
- * @sk: the new connection
+ * selinux_netlbl_inet_conn_request - Label an incoming stream connection
+ * @req: incoming connection request socket
*
* Description:
- * A new connection has been established on @sk so make sure it is labeled
- * correctly with the NetLabel susbsystem.
+ * A new incoming connection request is represented by @req, we need to label
+ * the new request_sock here and the stack will ensure the on-the-wire label
+ * will get preserved when a full sock is created once the connection handshake
+ * is complete. Returns zero on success, negative values on failure.
*
*/
-void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family)
+int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
{
int rc;
- struct sk_security_struct *sksec = sk->sk_security;
- struct netlbl_lsm_secattr *secattr;
- struct inet_sock *sk_inet = inet_sk(sk);
- struct sockaddr_in addr;
-
- if (sksec->nlbl_state != NLBL_REQUIRE)
- return;
+ struct netlbl_lsm_secattr secattr;
- secattr = selinux_netlbl_sock_genattr(sk);
- if (secattr == NULL)
- return;
+ if (family != PF_INET)
+ return 0;
- rc = netlbl_sock_setattr(sk, secattr);
- switch (rc) {
- case 0:
- sksec->nlbl_state = NLBL_LABELED;
- break;
- case -EDESTADDRREQ:
- /* no PF_INET6 support yet because we don't support any IPv6
- * labeling protocols */
- if (family != PF_INET) {
- sksec->nlbl_state = NLBL_UNSET;
- return;
- }
-
- addr.sin_family = family;
- addr.sin_addr.s_addr = sk_inet->daddr;
- if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr,
- secattr) != 0) {
- /* we failed to label the connected socket (could be
- * for a variety of reasons, the actual "why" isn't
- * important here) so we have to go to our backup plan,
- * labeling the packets individually in the netfilter
- * local output hook. this is okay but we need to
- * adjust the MSS of the connection to take into
- * account any labeling overhead, since we don't know
- * the exact overhead at this point we'll use the worst
- * case value which is 40 bytes for IPv4 */
- struct inet_connection_sock *sk_conn = inet_csk(sk);
- sk_conn->icsk_ext_hdr_len += 40 -
- (sk_inet->opt ? sk_inet->opt->optlen : 0);
- sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
-
- sksec->nlbl_state = NLBL_REQSKB;
- } else
- sksec->nlbl_state = NLBL_CONNLABELED;
- break;
- default:
- /* note that we are failing to label the socket which could be
- * a bad thing since it means traffic could leave the system
- * without the desired labeling, however, all is not lost as
- * we have a check in selinux_netlbl_inode_permission() to
- * pick up the pieces that we might drop here because we can't
- * return an error code */
- break;
- }
+ netlbl_secattr_init(&secattr);
+ rc = security_netlbl_sid_to_secattr(req->secid, &secattr);
+ if (rc != 0)
+ goto inet_conn_request_return;
+ rc = netlbl_req_setattr(req, &secattr);
+inet_conn_request_return:
+ netlbl_secattr_destroy(&secattr);
+ return rc;
}
/**
- * selinux_netlbl_socket_post_create - Label a socket using NetLabel
- * @sock: the socket to label
+ * selinux_netlbl_inet_csk_clone - Initialize the newly created sock
+ * @sk: the new sock
*
* Description:
- * Attempt to label a socket using the NetLabel mechanism using the given
- * SID. Returns zero values on success, negative values on failure.
+ * A new connection has been established using @sk, we've already labeled the
+ * socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
+ * we need to set the NetLabel state here since we now have a sock structure.
*
*/
-int selinux_netlbl_socket_post_create(struct socket *sock)
+void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
{
- return selinux_netlbl_sock_setsid(sock->sk);
+ struct sk_security_struct *sksec = sk->sk_security;
+
+ if (family == PF_INET)
+ sksec->nlbl_state = NLBL_LABELED;
+ else
+ sksec->nlbl_state = NLBL_UNSET;
}
/**
- * selinux_netlbl_inode_permission - Verify the socket is NetLabel labeled
- * @inode: the file descriptor's inode
- * @mask: the permission mask
+ * selinux_netlbl_socket_post_create - Label a socket using NetLabel
+ * @sock: the socket to label
+ * @family: protocol family
*
* Description:
- * Looks at a file's inode and if it is marked as a socket protected by
- * NetLabel then verify that the socket has been labeled, if not try to label
- * the socket now with the inode's SID. Returns zero on success, negative
- * values on failure.
+ * Attempt to label a socket using the NetLabel mechanism using the given
+ * SID. Returns zero values on success, negative values on failure.
*
*/
-int selinux_netlbl_inode_permission(struct inode *inode, int mask)
+int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
{
int rc;
- struct sock *sk;
- struct socket *sock;
- struct sk_security_struct *sksec;
+ struct sk_security_struct *sksec = sk->sk_security;
+ struct netlbl_lsm_secattr *secattr;
- if (!S_ISSOCK(inode->i_mode) ||
- ((mask & (MAY_WRITE | MAY_APPEND)) == 0))
- return 0;
- sock = SOCKET_I(inode);
- sk = sock->sk;
- if (sk == NULL)
- return 0;
- sksec = sk->sk_security;
- if (sksec == NULL || sksec->nlbl_state != NLBL_REQUIRE)
+ if (family != PF_INET)
return 0;
- local_bh_disable();
- bh_lock_sock_nested(sk);
- if (likely(sksec->nlbl_state == NLBL_REQUIRE))
- rc = selinux_netlbl_sock_setsid(sk);
- else
+ secattr = selinux_netlbl_sock_genattr(sk);
+ if (secattr == NULL)
+ return -ENOMEM;
+ rc = netlbl_sock_setattr(sk, family, secattr);
+ switch (rc) {
+ case 0:
+ sksec->nlbl_state = NLBL_LABELED;
+ break;
+ case -EDESTADDRREQ:
+ sksec->nlbl_state = NLBL_REQSKB;
rc = 0;
- bh_unlock_sock(sk);
- local_bh_enable();
+ break;
+ }
return rc;
}
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index 4ed7bab89c59..c6875fd3b9d6 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -113,7 +113,7 @@ static struct nlmsg_perm nlmsg_audit_perms[] =
{ AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY },
{ AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ },
{ AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ },
- { AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT },
};
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 01ec6d2c6b97..2d5136ec3d54 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -47,8 +47,6 @@ static char *policycap_names[] = {
unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
-int selinux_compat_net = 0;
-
static int __init checkreqprot_setup(char *str)
{
unsigned long checkreqprot;
@@ -58,16 +56,6 @@ static int __init checkreqprot_setup(char *str)
}
__setup("checkreqprot=", checkreqprot_setup);
-static int __init selinux_compat_net_setup(char *str)
-{
- unsigned long compat_net;
- if (!strict_strtoul(str, 0, &compat_net))
- selinux_compat_net = compat_net ? 1 : 0;
- return 1;
-}
-__setup("selinux_compat_net=", selinux_compat_net_setup);
-
-
static DEFINE_MUTEX(sel_mutex);
/* global data for booleans */
@@ -450,61 +438,6 @@ static const 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;
-
- if (new_value) {
- printk(KERN_NOTICE
- "SELinux: compat_net is deprecated, please use secmark"
- " instead\n");
- selinux_compat_net = 1;
- } else
- selinux_compat_net = 0;
- length = count;
-out:
- free_page((unsigned long) page);
- return length;
-}
-static const 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
*/
@@ -595,7 +528,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
"%x %x %x %x %u",
- avd.allowed, avd.decided,
+ avd.allowed, 0xffffffff,
avd.auditallow, avd.auditdeny,
avd.seqno);
out2:
@@ -1665,7 +1598,6 @@ 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},
[SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
[SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
/* last one */ {""}
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index c65e4fe4a0f1..deeec6c013ae 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -407,7 +407,6 @@ static int context_struct_compute_av(struct context *scontext,
* Initialize the access vectors to the default values.
*/
avd->allowed = 0;
- avd->decided = 0xffffffff;
avd->auditallow = 0;
avd->auditdeny = 0xffffffff;
avd->seqno = latest_granting;
@@ -743,7 +742,6 @@ int security_compute_av(u32 ssid,
if (!ss_initialized) {
avd->allowed = 0xffffffff;
- avd->decided = 0xffffffff;
avd->auditallow = 0;
avd->auditdeny = 0xffffffff;
avd->seqno = latest_granting;