summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/Kconfig10
-rw-r--r--security/commoncap.c4
-rw-r--r--security/keys/internal.h8
-rw-r--r--security/root_plug.c2
-rw-r--r--security/security.c8
-rw-r--r--security/selinux/Kconfig2
-rw-r--r--security/selinux/Makefile1
-rw-r--r--security/selinux/avc.c13
-rw-r--r--security/selinux/hooks.c165
-rw-r--r--security/selinux/include/av_perm_to_string.h5
-rw-r--r--security/selinux/include/av_permissions.h5
-rw-r--r--security/selinux/include/netlabel.h16
-rw-r--r--security/selinux/include/netport.h31
-rw-r--r--security/selinux/include/objsec.h15
-rw-r--r--security/selinux/include/security.h15
-rw-r--r--security/selinux/netlabel.c82
-rw-r--r--security/selinux/netlink.c2
-rw-r--r--security/selinux/netport.c286
-rw-r--r--security/selinux/selinuxfs.c11
-rw-r--r--security/selinux/ss/avtab.c40
-rw-r--r--security/selinux/ss/conditional.c16
-rw-r--r--security/selinux/ss/ebitmap.c14
-rw-r--r--security/selinux/ss/policydb.c65
-rw-r--r--security/selinux/ss/policydb.h2
-rw-r--r--security/selinux/ss/services.c69
25 files changed, 617 insertions, 270 deletions
diff --git a/security/Kconfig b/security/Kconfig
index 5dfc206748cf..49b51f964897 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -113,10 +113,12 @@ config SECURITY_DEFAULT_MMAP_MIN_ADDR
from userspace allocation. Keeping a user from writing to low pages
can help reduce the impact of kernel NULL pointer bugs.
- For most users with lots of address space a value of 65536 is
- reasonable and should cause no problems. Programs which use vm86
- functionality would either need additional permissions from either
- the LSM or the capabilities module or have this protection disabled.
+ For most ia64, ppc64 and x86 users with lots of address space
+ a value of 65536 is reasonable and should cause no problems.
+ On arm and other archs it should not be higher than 32768.
+ Programs which use vm86 functionality would either need additional
+ permissions from either the LSM or the capabilities module or have
+ this protection disabled.
This value can be changed after boot using the
/proc/sys/vm/mmap_min_addr tunable.
diff --git a/security/commoncap.c b/security/commoncap.c
index 06d5c9469ba3..852905789caf 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -267,7 +267,7 @@ static int get_file_caps(struct linux_binprm *bprm)
rc = cap_from_disk(&vcaps, bprm, rc);
if (rc)
printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
- __FUNCTION__, rc, bprm->filename);
+ __func__, rc, bprm->filename);
out:
dput(dentry);
@@ -302,7 +302,7 @@ int cap_bprm_set_security (struct linux_binprm *bprm)
ret = get_file_caps(bprm);
if (ret)
printk(KERN_NOTICE "%s: get_file_caps returned %d for %s\n",
- __FUNCTION__, ret, bprm->filename);
+ __func__, ret, bprm->filename);
/* To support inheritance of root-permissions and suid-root
* executables under compatibility mode, we raise all three
diff --git a/security/keys/internal.h b/security/keys/internal.h
index d36d69393356..7d894ef70370 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -22,16 +22,16 @@ void no_printk(const char *fmt, ...)
#ifdef __KDEBUG
#define kenter(FMT, ...) \
- printk(KERN_DEBUG "==> %s("FMT")\n", __FUNCTION__, ##__VA_ARGS__)
+ printk(KERN_DEBUG "==> %s("FMT")\n", __func__, ##__VA_ARGS__)
#define kleave(FMT, ...) \
- printk(KERN_DEBUG "<== %s()"FMT"\n", __FUNCTION__, ##__VA_ARGS__)
+ printk(KERN_DEBUG "<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
#define kdebug(FMT, ...) \
printk(KERN_DEBUG "xxx" FMT"yyy\n", ##__VA_ARGS__)
#else
#define kenter(FMT, ...) \
- no_printk(KERN_DEBUG "==> %s("FMT")\n", __FUNCTION__, ##__VA_ARGS__)
+ no_printk(KERN_DEBUG "==> %s("FMT")\n", __func__, ##__VA_ARGS__)
#define kleave(FMT, ...) \
- no_printk(KERN_DEBUG "<== %s()"FMT"\n", __FUNCTION__, ##__VA_ARGS__)
+ no_printk(KERN_DEBUG "<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
#define kdebug(FMT, ...) \
no_printk(KERN_DEBUG FMT"\n", ##__VA_ARGS__)
#endif
diff --git a/security/root_plug.c b/security/root_plug.c
index 870f13095bb6..6112d1404c81 100644
--- a/security/root_plug.c
+++ b/security/root_plug.c
@@ -49,7 +49,7 @@ module_param(debug, bool, 0600);
do { \
if (debug) \
printk(KERN_DEBUG "%s: %s: " fmt , \
- MY_NAME , __FUNCTION__ , \
+ MY_NAME , __func__ , \
## arg); \
} while (0)
diff --git a/security/security.c b/security/security.c
index c9ff7d18c2f4..54affd0ce6ad 100644
--- a/security/security.c
+++ b/security/security.c
@@ -57,7 +57,7 @@ int __init security_init(void)
if (verify(&dummy_security_ops)) {
printk(KERN_ERR "%s could not verify "
- "dummy_security_ops structure.\n", __FUNCTION__);
+ "dummy_security_ops structure.\n", __func__);
return -EIO;
}
@@ -82,7 +82,7 @@ int register_security(struct security_operations *ops)
{
if (verify(ops)) {
printk(KERN_DEBUG "%s could not verify "
- "security_operations structure.\n", __FUNCTION__);
+ "security_operations structure.\n", __func__);
return -EINVAL;
}
@@ -110,13 +110,13 @@ int mod_reg_security(const char *name, struct security_operations *ops)
{
if (verify(ops)) {
printk(KERN_INFO "%s could not verify "
- "security operations.\n", __FUNCTION__);
+ "security operations.\n", __func__);
return -EINVAL;
}
if (ops == security_ops) {
printk(KERN_INFO "%s security operations "
- "already registered.\n", __FUNCTION__);
+ "already registered.\n", __func__);
return -EINVAL;
}
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index 2b517d618672..a436d1cfa88b 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -145,7 +145,7 @@ config SECURITY_SELINUX_POLICYDB_VERSION_MAX
config SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
int "NSA SELinux maximum supported policy format version value"
depends on SECURITY_SELINUX_POLICYDB_VERSION_MAX
- range 15 22
+ range 15 23
default 19
help
This option sets the value for the maximum policy format version
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index 00afd85f1edb..d47fc5e545e0 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -11,6 +11,7 @@ selinux-y := avc.o \
nlmsgtab.o \
netif.o \
netnode.o \
+ netport.o \
exports.o
selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 187964e88af1..a4fc6e6d038a 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -871,6 +871,8 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
int rc = 0;
u32 denied;
+ BUG_ON(!requested);
+
rcu_read_lock();
node = avc_lookup(ssid, tsid, tclass, requested);
@@ -890,13 +892,14 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
denied = requested & ~(p_ae->avd.allowed);
- if (!requested || denied) {
- if (selinux_enforcing || (flags & AVC_STRICT))
+ 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);
else
- if (node)
- avc_update_node(AVC_CALLBACK_GRANT,requested,
- ssid,tsid,tclass);
+ rc = -EACCES;
}
rcu_read_unlock();
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d39b59cf8a08..34f2d46c7984 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -80,6 +80,7 @@
#include "objsec.h"
#include "netif.h"
#include "netnode.h"
+#include "netport.h"
#include "xfrm.h"
#include "netlabel.h"
@@ -161,8 +162,7 @@ static int task_alloc_security(struct task_struct *task)
if (!tsec)
return -ENOMEM;
- tsec->task = task;
- tsec->osid = tsec->sid = tsec->ptrace_sid = SECINITSID_UNLABELED;
+ tsec->osid = tsec->sid = SECINITSID_UNLABELED;
task->security = tsec;
return 0;
@@ -218,7 +218,6 @@ static int file_alloc_security(struct file *file)
if (!fsec)
return -ENOMEM;
- fsec->file = file;
fsec->sid = tsec->sid;
fsec->fown_sid = tsec->sid;
file->f_security = fsec;
@@ -275,12 +274,11 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
if (!ssec)
return -ENOMEM;
- ssec->sk = sk;
ssec->peer_sid = SECINITSID_UNLABELED;
ssec->sid = SECINITSID_UNLABELED;
sk->sk_security = ssec;
- selinux_netlbl_sk_security_init(ssec, family);
+ selinux_netlbl_sk_security_reset(ssec, family);
return 0;
}
@@ -324,10 +322,10 @@ enum {
};
static match_table_t tokens = {
- {Opt_context, "context=%s"},
- {Opt_fscontext, "fscontext=%s"},
- {Opt_defcontext, "defcontext=%s"},
- {Opt_rootcontext, "rootcontext=%s"},
+ {Opt_context, CONTEXT_STR "%s"},
+ {Opt_fscontext, FSCONTEXT_STR "%s"},
+ {Opt_defcontext, DEFCONTEXT_STR "%s"},
+ {Opt_rootcontext, ROOTCONTEXT_STR "%s"},
{Opt_error, NULL},
};
@@ -671,7 +669,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid);
if (rc) {
printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
- __FUNCTION__, sb->s_type->name, rc);
+ __func__, sb->s_type->name, rc);
goto out;
}
@@ -1137,7 +1135,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
}
if (!dentry) {
printk(KERN_WARNING "%s: no dentry for dev=%s "
- "ino=%ld\n", __FUNCTION__, inode->i_sb->s_id,
+ "ino=%ld\n", __func__, inode->i_sb->s_id,
inode->i_ino);
goto out_unlock;
}
@@ -1175,7 +1173,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
if (rc < 0) {
if (rc != -ENODATA) {
printk(KERN_WARNING "%s: getxattr returned "
- "%d for dev=%s ino=%ld\n", __FUNCTION__,
+ "%d for dev=%s ino=%ld\n", __func__,
-rc, inode->i_sb->s_id, inode->i_ino);
kfree(context);
goto out_unlock;
@@ -1190,7 +1188,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
if (rc) {
printk(KERN_WARNING "%s: context_to_sid(%s) "
"returned %d for dev=%s ino=%ld\n",
- __FUNCTION__, context, -rc,
+ __func__, context, -rc,
inode->i_sb->s_id, inode->i_ino);
kfree(context);
/* Leave with the unlabeled SID */
@@ -1618,6 +1616,35 @@ static inline u32 file_mask_to_av(int mode, int mask)
return av;
}
+/*
+ * Convert a file mask to an access vector and include the correct open
+ * open permission.
+ */
+static inline u32 open_file_mask_to_av(int mode, int mask)
+{
+ u32 av = file_mask_to_av(mode, mask);
+
+ if (selinux_policycap_openperm) {
+ /*
+ * lnk files and socks do not really have an 'open'
+ */
+ if (S_ISREG(mode))
+ av |= FILE__OPEN;
+ else if (S_ISCHR(mode))
+ av |= CHR_FILE__OPEN;
+ else if (S_ISBLK(mode))
+ av |= BLK_FILE__OPEN;
+ else if (S_ISFIFO(mode))
+ av |= FIFO_FILE__OPEN;
+ else if (S_ISDIR(mode))
+ av |= DIR__OPEN;
+ else
+ printk(KERN_ERR "SELinux: WARNING: inside open_file_to_av "
+ "with unknown mode:%x\n", mode);
+ }
+ return av;
+}
+
/* Convert a Linux file to an access vector. */
static inline u32 file_to_av(struct file *file)
{
@@ -1645,19 +1672,13 @@ static inline u32 file_to_av(struct file *file)
static int selinux_ptrace(struct task_struct *parent, struct task_struct *child)
{
- struct task_security_struct *psec = parent->security;
- struct task_security_struct *csec = child->security;
int rc;
rc = secondary_ops->ptrace(parent,child);
if (rc)
return rc;
- rc = task_has_perm(parent, child, PROCESS__PTRACE);
- /* Save the SID of the tracing process for later use in apply_creds. */
- if (!(child->ptrace & PT_PTRACED) && !rc)
- csec->ptrace_sid = psec->sid;
- return rc;
+ return task_has_perm(parent, child, PROCESS__PTRACE);
}
static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
@@ -1879,6 +1900,22 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
return __vm_enough_memory(mm, pages, cap_sys_admin);
}
+/**
+ * task_tracer_task - return the task that is tracing the given task
+ * @task: task to consider
+ *
+ * Returns NULL if noone is tracing @task, or the &struct task_struct
+ * pointer to its tracer.
+ *
+ * Must be called under rcu_read_lock().
+ */
+static struct task_struct *task_tracer_task(struct task_struct *task)
+{
+ if (task->ptrace & PT_PTRACED)
+ return rcu_dereference(task->parent);
+ return NULL;
+}
+
/* binprm security operations */
static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
@@ -1889,7 +1926,6 @@ static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
if (!bsec)
return -ENOMEM;
- bsec->bprm = bprm;
bsec->sid = SECINITSID_UNLABELED;
bsec->set = 0;
@@ -2126,12 +2162,25 @@ static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
/* Check for ptracing, and update the task SID if ok.
Otherwise, leave SID unchanged and kill. */
if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
- rc = avc_has_perm(tsec->ptrace_sid, sid,
- SECCLASS_PROCESS, PROCESS__PTRACE,
- NULL);
- if (rc) {
- bsec->unsafe = 1;
- return;
+ struct task_struct *tracer;
+ struct task_security_struct *sec;
+ u32 ptsid = 0;
+
+ rcu_read_lock();
+ tracer = task_tracer_task(current);
+ if (likely(tracer != NULL)) {
+ sec = tracer->security;
+ ptsid = sec->sid;
+ }
+ rcu_read_unlock();
+
+ if (ptsid != 0) {
+ rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
+ PROCESS__PTRACE, NULL);
+ if (rc) {
+ bsec->unsafe = 1;
+ return;
+ }
}
}
tsec->sid = sid;
@@ -2239,10 +2288,10 @@ static inline int match_prefix(char *prefix, int plen, char *option, int olen)
static inline int selinux_option(char *option, int len)
{
- return (match_prefix("context=", sizeof("context=")-1, option, len) ||
- match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) ||
- match_prefix("defcontext=", sizeof("defcontext=")-1, option, len) ||
- match_prefix("rootcontext=", sizeof("rootcontext=")-1, option, 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));
}
static inline void take_option(char **to, char *from, int *first, int len)
@@ -2412,7 +2461,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
printk(KERN_WARNING "%s: "
"security_transition_sid failed, rc=%d (dev=%s "
"ino=%ld)\n",
- __FUNCTION__,
+ __func__,
-rc, inode->i_sb->s_id, inode->i_ino);
return rc;
}
@@ -2536,7 +2585,7 @@ static int selinux_inode_permission(struct inode *inode, int mask,
}
return inode_has_perm(current, inode,
- file_mask_to_av(inode->i_mode, mask), NULL);
+ open_file_mask_to_av(inode->i_mode, mask), NULL);
}
static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@ -2646,7 +2695,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, char *name,
rc = security_context_to_sid(value, size, &newsid);
if (rc) {
printk(KERN_WARNING "%s: unable to obtain SID for context "
- "%s, rc=%d\n", __FUNCTION__, (char*)value, -rc);
+ "%s, rc=%d\n", __func__, (char *)value, -rc);
return;
}
@@ -3087,11 +3136,6 @@ static int selinux_task_alloc_security(struct task_struct *tsk)
tsec2->keycreate_sid = tsec1->keycreate_sid;
tsec2->sockcreate_sid = tsec1->sockcreate_sid;
- /* Retain ptracer SID across fork, if any.
- This will be reset by the ptrace hook upon any
- subsequent ptrace_attach operations. */
- tsec2->ptrace_sid = tsec1->ptrace_sid;
-
return 0;
}
@@ -3627,10 +3671,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
inet_get_local_port_range(&low, &high);
if (snum < max(PROT_SOCK, low) || snum > high) {
- err = security_port_sid(sk->sk_family,
- sk->sk_type,
- sk->sk_protocol, snum,
- &sid);
+ err = sel_netport_sid(sk->sk_protocol,
+ snum, &sid);
if (err)
goto out;
AVC_AUDIT_DATA_INIT(&ad,NET);
@@ -3718,8 +3760,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
snum = ntohs(addr6->sin6_port);
}
- err = security_port_sid(sk->sk_family, sk->sk_type,
- sk->sk_protocol, snum, &sid);
+ err = sel_netport_sid(sk->sk_protocol, snum, &sid);
if (err)
goto out;
@@ -3950,9 +3991,8 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
if (!recv_perm)
return 0;
- err = security_port_sid(sk->sk_family, sk->sk_type,
- sk->sk_protocol, ntohs(ad->u.net.sport),
- &port_sid);
+ err = sel_netport_sid(sk->sk_protocol,
+ ntohs(ad->u.net.sport), &port_sid);
if (unlikely(err)) {
printk(KERN_WARNING
"SELinux: failure in"
@@ -4139,7 +4179,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_clone(ssec, newssec);
+ selinux_netlbl_sk_security_reset(newssec, newsk->sk_family);
}
static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
@@ -4373,9 +4413,8 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk,
if (send_perm != 0)
return 0;
- err = security_port_sid(sk->sk_family, sk->sk_type,
- sk->sk_protocol, ntohs(ad->u.net.dport),
- &port_sid);
+ err = sel_netport_sid(sk->sk_protocol,
+ ntohs(ad->u.net.dport), &port_sid);
if (unlikely(err)) {
printk(KERN_WARNING
"SELinux: failure in"
@@ -4561,7 +4600,6 @@ static int ipc_alloc_security(struct task_struct *task,
return -ENOMEM;
isec->sclass = sclass;
- isec->ipc_perm = perm;
isec->sid = tsec->sid;
perm->security = isec;
@@ -4583,7 +4621,6 @@ static int msg_msg_alloc_security(struct msg_msg *msg)
if (!msec)
return -ENOMEM;
- msec->msg = msg;
msec->sid = SECINITSID_UNLABELED;
msg->security = msec;
@@ -4994,14 +5031,14 @@ static int selinux_register_security (const char *name, struct security_operatio
{
if (secondary_ops != original_ops) {
printk(KERN_ERR "%s: There is already a secondary security "
- "module registered.\n", __FUNCTION__);
+ "module registered.\n", __func__);
return -EINVAL;
}
secondary_ops = ops;
printk(KERN_INFO "%s: Registering secondary module %s\n",
- __FUNCTION__,
+ __func__,
name);
return 0;
@@ -5057,6 +5094,7 @@ static int selinux_setprocattr(struct task_struct *p,
char *name, void *value, size_t size)
{
struct task_security_struct *tsec;
+ struct task_struct *tracer;
u32 sid = 0;
int error;
char *str = value;
@@ -5145,18 +5183,24 @@ static int selinux_setprocattr(struct task_struct *p,
/* Check for ptracing, and update the task SID if ok.
Otherwise, leave SID unchanged and fail. */
task_lock(p);
- if (p->ptrace & PT_PTRACED) {
- error = avc_has_perm_noaudit(tsec->ptrace_sid, sid,
+ rcu_read_lock();
+ tracer = task_tracer_task(p);
+ if (tracer != NULL) {
+ struct task_security_struct *ptsec = tracer->security;
+ u32 ptsid = ptsec->sid;
+ rcu_read_unlock();
+ error = avc_has_perm_noaudit(ptsid, sid,
SECCLASS_PROCESS,
PROCESS__PTRACE, 0, &avd);
if (!error)
tsec->sid = sid;
task_unlock(p);
- avc_audit(tsec->ptrace_sid, sid, SECCLASS_PROCESS,
+ avc_audit(ptsid, sid, SECCLASS_PROCESS,
PROCESS__PTRACE, &avd, error, NULL);
if (error)
return error;
} else {
+ rcu_read_unlock();
tsec->sid = sid;
task_unlock(p);
}
@@ -5194,7 +5238,6 @@ static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
if (!ksec)
return -ENOMEM;
- ksec->obj = k;
if (tsec->keycreate_sid)
ksec->sid = tsec->keycreate_sid;
else
@@ -5631,5 +5674,3 @@ int selinux_disable(void)
return 0;
}
#endif
-
-
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index d5696690d3a2..1223b4ff9bee 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -14,12 +14,17 @@
S_(SECCLASS_DIR, DIR__REPARENT, "reparent")
S_(SECCLASS_DIR, DIR__SEARCH, "search")
S_(SECCLASS_DIR, DIR__RMDIR, "rmdir")
+ S_(SECCLASS_DIR, DIR__OPEN, "open")
S_(SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, "execute_no_trans")
S_(SECCLASS_FILE, FILE__ENTRYPOINT, "entrypoint")
S_(SECCLASS_FILE, FILE__EXECMOD, "execmod")
+ S_(SECCLASS_FILE, FILE__OPEN, "open")
S_(SECCLASS_CHR_FILE, CHR_FILE__EXECUTE_NO_TRANS, "execute_no_trans")
S_(SECCLASS_CHR_FILE, CHR_FILE__ENTRYPOINT, "entrypoint")
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_FIFO_FILE, FIFO_FILE__OPEN, "open")
S_(SECCLASS_FD, FD__USE, "use")
S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__CONNECTTO, "connectto")
S_(SECCLASS_TCP_SOCKET, TCP_SOCKET__NEWCONN, "newconn")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index 75b41311ab86..c4c51165c505 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -79,6 +79,7 @@
#define DIR__REPARENT 0x00080000UL
#define DIR__SEARCH 0x00100000UL
#define DIR__RMDIR 0x00200000UL
+#define DIR__OPEN 0x00400000UL
#define FILE__IOCTL 0x00000001UL
#define FILE__READ 0x00000002UL
#define FILE__WRITE 0x00000004UL
@@ -99,6 +100,7 @@
#define FILE__EXECUTE_NO_TRANS 0x00020000UL
#define FILE__ENTRYPOINT 0x00040000UL
#define FILE__EXECMOD 0x00080000UL
+#define FILE__OPEN 0x00100000UL
#define LNK_FILE__IOCTL 0x00000001UL
#define LNK_FILE__READ 0x00000002UL
#define LNK_FILE__WRITE 0x00000004UL
@@ -136,6 +138,7 @@
#define CHR_FILE__EXECUTE_NO_TRANS 0x00020000UL
#define CHR_FILE__ENTRYPOINT 0x00040000UL
#define CHR_FILE__EXECMOD 0x00080000UL
+#define CHR_FILE__OPEN 0x00100000UL
#define BLK_FILE__IOCTL 0x00000001UL
#define BLK_FILE__READ 0x00000002UL
#define BLK_FILE__WRITE 0x00000004UL
@@ -153,6 +156,7 @@
#define BLK_FILE__SWAPON 0x00004000UL
#define BLK_FILE__QUOTAON 0x00008000UL
#define BLK_FILE__MOUNTON 0x00010000UL
+#define BLK_FILE__OPEN 0x00020000UL
#define SOCK_FILE__IOCTL 0x00000001UL
#define SOCK_FILE__READ 0x00000002UL
#define SOCK_FILE__WRITE 0x00000004UL
@@ -187,6 +191,7 @@
#define FIFO_FILE__SWAPON 0x00004000UL
#define FIFO_FILE__QUOTAON 0x00008000UL
#define FIFO_FILE__MOUNTON 0x00010000UL
+#define FIFO_FILE__OPEN 0x00020000UL
#define FD__USE 0x00000001UL
#define SOCKET__IOCTL 0x00000001UL
#define SOCKET__READ 0x00000002UL
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h
index 00a2809c8506..9a9e7cd9a379 100644
--- a/security/selinux/include/netlabel.h
+++ b/security/selinux/include/netlabel.h
@@ -41,10 +41,6 @@ void selinux_netlbl_cache_invalidate(void);
void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
int family);
-void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
- int family);
-void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
- struct sk_security_struct *newssec);
int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
u16 family,
@@ -73,18 +69,6 @@ static inline void selinux_netlbl_sk_security_reset(
{
return;
}
-static inline void selinux_netlbl_sk_security_init(
- struct sk_security_struct *ssec,
- int family)
-{
- return;
-}
-static inline void selinux_netlbl_sk_security_clone(
- struct sk_security_struct *ssec,
- struct sk_security_struct *newssec)
-{
- return;
-}
static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
u16 family,
diff --git a/security/selinux/include/netport.h b/security/selinux/include/netport.h
new file mode 100644
index 000000000000..8991752eaf93
--- /dev/null
+++ b/security/selinux/include/netport.h
@@ -0,0 +1,31 @@
+/*
+ * Network port table
+ *
+ * SELinux must keep a mapping of network ports to labels/SIDs. This
+ * mapping is maintained as part of the normal policy but a fast cache is
+ * needed to reduce the lookup overhead.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _SELINUX_NETPORT_H
+#define _SELINUX_NETPORT_H
+
+int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid);
+
+#endif
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index c6c2bb4ebacc..300b61bad7b3 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -28,14 +28,12 @@
#include "avc.h"
struct task_security_struct {
- struct task_struct *task; /* back pointer to task object */
u32 osid; /* SID prior to last execve */
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 */
};
struct inode_security_struct {
@@ -50,7 +48,6 @@ struct inode_security_struct {
};
struct file_security_struct {
- struct file *file; /* back pointer to file object */
u32 sid; /* SID of open file description */
u32 fown_sid; /* SID of file owner (for SIGIO) */
u32 isid; /* SID of inode at the time of file open */
@@ -73,18 +70,15 @@ struct superblock_security_struct {
};
struct msg_security_struct {
- struct msg_msg *msg; /* back pointer */
u32 sid; /* SID of message */
};
struct ipc_security_struct {
- struct kern_ipc_perm *ipc_perm; /* back pointer */
u16 sclass; /* security class of this object */
u32 sid; /* SID of IPC resource */
};
struct bprm_security_struct {
- struct linux_binprm *bprm; /* back pointer to bprm object */
u32 sid; /* SID for transformed process */
unsigned char set;
@@ -109,8 +103,13 @@ struct netnode_security_struct {
u16 family; /* address family */
};
+struct netport_security_struct {
+ u32 sid; /* SID for this node */
+ u16 port; /* port number */
+ u8 protocol; /* transport protocol */
+};
+
struct sk_security_struct {
- struct sock *sk; /* back pointer to sk object */
u32 sid; /* SID of this object */
u32 peer_sid; /* SID of peer */
u16 sclass; /* sock security class */
@@ -120,12 +119,10 @@ struct sk_security_struct {
NLBL_REQUIRE,
NLBL_LABELED,
} nlbl_state;
- spinlock_t nlbl_lock; /* protects nlbl_state */
#endif
};
struct key_security_struct {
- struct key *obj; /* back pointer */
u32 sid; /* SID of key */
};
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 44e12ec88090..1904c462a605 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -26,13 +26,14 @@
#define POLICYDB_VERSION_AVTAB 20
#define POLICYDB_VERSION_RANGETRANS 21
#define POLICYDB_VERSION_POLCAP 22
+#define POLICYDB_VERSION_PERMISSIVE 23
/* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
#else
-#define POLICYDB_VERSION_MAX POLICYDB_VERSION_POLCAP
+#define POLICYDB_VERSION_MAX POLICYDB_VERSION_PERMISSIVE
#endif
#define CONTEXT_MNT 0x01
@@ -40,6 +41,11 @@
#define ROOTCONTEXT_MNT 0x04
#define DEFCONTEXT_MNT 0x08
+#define CONTEXT_STR "context="
+#define FSCONTEXT_STR "fscontext="
+#define ROOTCONTEXT_STR "rootcontext="
+#define DEFCONTEXT_STR "defcontext="
+
struct netlbl_lsm_secattr;
extern int selinux_enabled;
@@ -48,11 +54,13 @@ extern int selinux_mls_enabled;
/* Policy capabilities */
enum {
POLICYDB_CAPABILITY_NETPEER,
+ POLICYDB_CAPABILITY_OPENPERM,
__POLICYDB_CAPABILITY_MAX
};
#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
extern int selinux_policycap_netpeer;
+extern int selinux_policycap_openperm;
int security_load_policy(void * data, size_t len);
@@ -67,6 +75,8 @@ struct av_decision {
u32 seqno;
};
+int security_permissive_sid(u32 sid);
+
int security_compute_av(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct av_decision *avd);
@@ -92,8 +102,7 @@ int security_context_to_sid_default(char *scontext, u32 scontext_len,
int security_get_user_sids(u32 callsid, char *username,
u32 **sids, u32 *nel);
-int security_port_sid(u16 domain, u16 type, u8 protocol, u16 port,
- u32 *out_sid);
+int security_port_sid(u8 protocol, u16 port, u32 *out_sid);
int security_netif_sid(char *name, u32 *if_sid);
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 0fa2be4149e8..e8ee91ac12ef 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -34,6 +34,7 @@
#include "objsec.h"
#include "security.h"
+#include "netlabel.h"
/**
* selinux_netlbl_sidlookup_cached - Cache a SID lookup
@@ -69,9 +70,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
*
* Description:
* Attempt to label a socket using the NetLabel mechanism using the given
- * SID. Returns zero values on success, negative values on failure. The
- * caller is responsibile for calling rcu_read_lock() before calling this
- * this function and rcu_read_unlock() after this function returns.
+ * SID. Returns zero values on success, negative values on failure.
*
*/
static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid)
@@ -86,11 +85,8 @@ static int selinux_netlbl_sock_setsid(struct sock *sk, u32 sid)
if (rc != 0)
goto sock_setsid_return;
rc = netlbl_sock_setattr(sk, &secattr);
- if (rc == 0) {
- spin_lock_bh(&sksec->nlbl_lock);
+ if (rc == 0)
sksec->nlbl_state = NLBL_LABELED;
- spin_unlock_bh(&sksec->nlbl_lock);
- }
sock_setsid_return:
netlbl_secattr_destroy(&secattr);
@@ -129,45 +125,6 @@ void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec,
}
/**
- * selinux_netlbl_sk_security_init - Setup the NetLabel fields
- * @ssec: the sk_security_struct
- * @family: the socket family
- *
- * Description:
- * Called when a new sk_security_struct is allocated to initialize the NetLabel
- * fields.
- *
- */
-void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
- int family)
-{
- /* No locking needed, we are the only one who has access to ssec */
- selinux_netlbl_sk_security_reset(ssec, family);
- spin_lock_init(&ssec->nlbl_lock);
-}
-
-/**
- * selinux_netlbl_sk_security_clone - Copy the NetLabel fields
- * @ssec: the original sk_security_struct
- * @newssec: the cloned sk_security_struct
- *
- * Description:
- * Clone the NetLabel specific sk_security_struct fields from @ssec to
- * @newssec.
- *
- */
-void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
- struct sk_security_struct *newssec)
-{
- /* We don't need to take newssec->nlbl_lock because we are the only
- * thread with access to newssec, but we do need to take the RCU read
- * lock as other threads could have access to ssec */
- rcu_read_lock();
- selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family);
- rcu_read_unlock();
-}
-
-/**
* selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
* @skb: the packet
* @family: protocol family
@@ -221,12 +178,8 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
struct netlbl_lsm_secattr secattr;
u32 nlbl_peer_sid;
- rcu_read_lock();
-
- if (sksec->nlbl_state != NLBL_REQUIRE) {
- rcu_read_unlock();
+ if (sksec->nlbl_state != NLBL_REQUIRE)
return;
- }
netlbl_secattr_init(&secattr);
if (netlbl_sock_getattr(sk, &secattr) == 0 &&
@@ -239,8 +192,6 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
* here we will pick up the pieces in later calls to
* selinux_netlbl_inode_permission(). */
selinux_netlbl_sock_setsid(sk, sksec->sid);
-
- rcu_read_unlock();
}
/**
@@ -254,16 +205,13 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
*/
int selinux_netlbl_socket_post_create(struct socket *sock)
{
- int rc = 0;
struct sock *sk = sock->sk;
struct sk_security_struct *sksec = sk->sk_security;
- rcu_read_lock();
- if (sksec->nlbl_state == NLBL_REQUIRE)
- rc = selinux_netlbl_sock_setsid(sk, sksec->sid);
- rcu_read_unlock();
+ if (sksec->nlbl_state != NLBL_REQUIRE)
+ return 0;
- return rc;
+ return selinux_netlbl_sock_setsid(sk, sksec->sid);
}
/**
@@ -288,21 +236,21 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
if (!S_ISSOCK(inode->i_mode) ||
((mask & (MAY_WRITE | MAY_APPEND)) == 0))
return 0;
+
sock = SOCKET_I(inode);
sk = sock->sk;
sksec = sk->sk_security;
-
- rcu_read_lock();
- if (sksec->nlbl_state != NLBL_REQUIRE) {
- rcu_read_unlock();
+ if (sksec->nlbl_state != NLBL_REQUIRE)
return 0;
- }
+
local_bh_disable();
bh_lock_sock_nested(sk);
- rc = selinux_netlbl_sock_setsid(sk, sksec->sid);
+ if (likely(sksec->nlbl_state == NLBL_REQUIRE))
+ rc = selinux_netlbl_sock_setsid(sk, sksec->sid);
+ else
+ rc = 0;
bh_unlock_sock(sk);
local_bh_enable();
- rcu_read_unlock();
return rc;
}
@@ -385,7 +333,6 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
struct sk_security_struct *sksec = sk->sk_security;
struct netlbl_lsm_secattr secattr;
- rcu_read_lock();
if (level == IPPROTO_IP && optname == IP_OPTIONS &&
sksec->nlbl_state == NLBL_LABELED) {
netlbl_secattr_init(&secattr);
@@ -396,7 +343,6 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
rc = -EACCES;
netlbl_secattr_destroy(&secattr);
}
- rcu_read_unlock();
return rc;
}
diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c
index b59871d74dad..6214a7a73149 100644
--- a/security/selinux/netlink.c
+++ b/security/selinux/netlink.c
@@ -89,7 +89,7 @@ out:
nlmsg_failure:
kfree_skb(skb);
oom:
- printk(KERN_ERR "SELinux: OOM in %s\n", __FUNCTION__);
+ printk(KERN_ERR "SELinux: OOM in %s\n", __func__);
goto out;
}
diff --git a/security/selinux/netport.c b/security/selinux/netport.c
new file mode 100644
index 000000000000..68ede3c498ab
--- /dev/null
+++ b/security/selinux/netport.c
@@ -0,0 +1,286 @@
+/*
+ * Network port table
+ *
+ * SELinux must keep a mapping of network ports to labels/SIDs. This
+ * mapping is maintained as part of the normal policy but a fast cache is
+ * needed to reduce the lookup overhead.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ * This code is heavily based on the "netif" concept originally developed by
+ * James Morris <jmorris@redhat.com>
+ * (see security/selinux/netif.c for more information)
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <asm/bug.h>
+
+#include "netport.h"
+#include "objsec.h"
+
+#define SEL_NETPORT_HASH_SIZE 256
+#define SEL_NETPORT_HASH_BKT_LIMIT 16
+
+struct sel_netport_bkt {
+ int size;
+ struct list_head list;
+};
+
+struct sel_netport {
+ struct netport_security_struct psec;
+
+ struct list_head list;
+ struct rcu_head rcu;
+};
+
+/* NOTE: we are using a combined hash table for both IPv4 and IPv6, the reason
+ * for this is that I suspect most users will not make heavy use of both
+ * address families at the same time so one table will usually end up wasted,
+ * if this becomes a problem we can always add a hash table for each address
+ * family later */
+
+static LIST_HEAD(sel_netport_list);
+static DEFINE_SPINLOCK(sel_netport_lock);
+static struct sel_netport_bkt sel_netport_hash[SEL_NETPORT_HASH_SIZE];
+
+/**
+ * sel_netport_free - Frees a port entry
+ * @p: the entry's RCU field
+ *
+ * Description:
+ * This function is designed to be used as a callback to the call_rcu()
+ * function so that memory allocated to a hash table port entry can be
+ * released safely.
+ *
+ */
+static void sel_netport_free(struct rcu_head *p)
+{
+ struct sel_netport *port = container_of(p, struct sel_netport, rcu);
+ kfree(port);
+}
+
+/**
+ * sel_netport_hashfn - Hashing function for the port table
+ * @pnum: port number
+ *
+ * Description:
+ * This is the hashing function for the port table, it returns the bucket
+ * number for the given port.
+ *
+ */
+static unsigned int sel_netport_hashfn(u16 pnum)
+{
+ return (pnum & (SEL_NETPORT_HASH_SIZE - 1));
+}
+
+/**
+ * sel_netport_find - Search for a port record
+ * @protocol: protocol
+ * @port: pnum
+ *
+ * Description:
+ * Search the network port table and return the matching record. If an entry
+ * can not be found in the table return NULL.
+ *
+ */
+static struct sel_netport *sel_netport_find(u8 protocol, u16 pnum)
+{
+ unsigned int idx;
+ struct sel_netport *port;
+
+ idx = sel_netport_hashfn(pnum);
+ list_for_each_entry_rcu(port, &sel_netport_hash[idx].list, list)
+ if (port->psec.port == pnum &&
+ port->psec.protocol == protocol)
+ return port;
+
+ return NULL;
+}
+
+/**
+ * sel_netport_insert - Insert a new port into the table
+ * @port: the new port record
+ *
+ * Description:
+ * Add a new port record to the network address hash table. Returns zero on
+ * success, negative values on failure.
+ *
+ */
+static int sel_netport_insert(struct sel_netport *port)
+{
+ unsigned int idx;
+
+ /* we need to impose a limit on the growth of the hash table so check
+ * this bucket to make sure it is within the specified bounds */
+ idx = sel_netport_hashfn(port->psec.port);
+ list_add_rcu(&port->list, &sel_netport_hash[idx].list);
+ if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) {
+ struct sel_netport *tail;
+ tail = list_entry(port->list.prev, struct sel_netport, list);
+ list_del_rcu(port->list.prev);
+ call_rcu(&tail->rcu, sel_netport_free);
+ } else
+ sel_netport_hash[idx].size++;
+
+ return 0;
+}
+
+/**
+ * sel_netport_sid_slow - Lookup the SID of a network address using the policy
+ * @protocol: protocol
+ * @pnum: port
+ * @sid: port SID
+ *
+ * Description:
+ * This function determines the SID of a network port by quering the security
+ * policy. The result is added to the network port table to speedup future
+ * queries. Returns zero on success, negative values on failure.
+ *
+ */
+static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
+{
+ int ret;
+ struct sel_netport *port;
+ struct sel_netport *new = NULL;
+
+ spin_lock_bh(&sel_netport_lock);
+ port = sel_netport_find(protocol, pnum);
+ if (port != NULL) {
+ *sid = port->psec.sid;
+ ret = 0;
+ goto out;
+ }
+ new = kzalloc(sizeof(*new), GFP_ATOMIC);
+ if (new == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = security_port_sid(protocol, pnum, &new->psec.sid);
+ if (ret != 0)
+ goto out;
+ new->psec.port = pnum;
+ new->psec.protocol = protocol;
+ ret = sel_netport_insert(new);
+ if (ret != 0)
+ goto out;
+ *sid = new->psec.sid;
+
+out:
+ spin_unlock_bh(&sel_netport_lock);
+ if (unlikely(ret)) {
+ printk(KERN_WARNING
+ "SELinux: failure in sel_netport_sid_slow(),"
+ " unable to determine network port label\n");
+ kfree(new);
+ }
+ return ret;
+}
+
+/**
+ * sel_netport_sid - Lookup the SID of a network port
+ * @protocol: protocol
+ * @pnum: port
+ * @sid: port SID
+ *
+ * Description:
+ * This function determines the SID of a network port using the fastest method
+ * possible. First the port table is queried, but if an entry can't be found
+ * then the policy is queried and the result is added to the table to speedup
+ * future queries. Returns zero on success, negative values on failure.
+ *
+ */
+int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid)
+{
+ struct sel_netport *port;
+
+ rcu_read_lock();
+ port = sel_netport_find(protocol, pnum);
+ if (port != NULL) {
+ *sid = port->psec.sid;
+ rcu_read_unlock();
+ return 0;
+ }
+ rcu_read_unlock();
+
+ return sel_netport_sid_slow(protocol, pnum, sid);
+}
+
+/**
+ * sel_netport_flush - Flush the entire network port table
+ *
+ * Description:
+ * Remove all entries from the network address table.
+ *
+ */
+static void sel_netport_flush(void)
+{
+ unsigned int idx;
+ struct sel_netport *port;
+
+ spin_lock_bh(&sel_netport_lock);
+ for (idx = 0; idx < SEL_NETPORT_HASH_SIZE; idx++) {
+ list_for_each_entry(port, &sel_netport_hash[idx].list, list) {
+ list_del_rcu(&port->list);
+ call_rcu(&port->rcu, sel_netport_free);
+ }
+ sel_netport_hash[idx].size = 0;
+ }
+ spin_unlock_bh(&sel_netport_lock);
+}
+
+static int sel_netport_avc_callback(u32 event, u32 ssid, u32 tsid,
+ u16 class, u32 perms, u32 *retained)
+{
+ if (event == AVC_CALLBACK_RESET) {
+ sel_netport_flush();
+ synchronize_net();
+ }
+ return 0;
+}
+
+static __init int sel_netport_init(void)
+{
+ int iter;
+ int ret;
+
+ if (!selinux_enabled)
+ return 0;
+
+ for (iter = 0; iter < SEL_NETPORT_HASH_SIZE; iter++) {
+ INIT_LIST_HEAD(&sel_netport_hash[iter].list);
+ sel_netport_hash[iter].size = 0;
+ }
+
+ ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET,
+ SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
+ if (ret != 0)
+ panic("avc_add_callback() failed, error %d\n", ret);
+
+ return ret;
+}
+
+__initcall(sel_netport_init);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 0341567665b3..26fabad09769 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -42,7 +42,8 @@
/* Policy capability filenames */
static char *policycap_names[] = {
- "network_peer_controls"
+ "network_peer_controls",
+ "open_perms"
};
unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
@@ -391,7 +392,7 @@ static ssize_t sel_write_context(struct file * file, char *buf, size_t size)
if (len > SIMPLE_TRANSACTION_LIMIT) {
printk(KERN_ERR "%s: context size (%u) exceeds payload "
- "max\n", __FUNCTION__, len);
+ "max\n", __func__, len);
length = -ERANGE;
goto out;
}
@@ -644,7 +645,7 @@ static ssize_t sel_write_create(struct file * file, char *buf, size_t size)
if (len > SIMPLE_TRANSACTION_LIMIT) {
printk(KERN_ERR "%s: context size (%u) exceeds payload "
- "max\n", __FUNCTION__, len);
+ "max\n", __func__, len);
length = -ERANGE;
goto out3;
}
@@ -821,7 +822,7 @@ static ssize_t sel_write_member(struct file * file, char *buf, size_t size)
if (len > SIMPLE_TRANSACTION_LIMIT) {
printk(KERN_ERR "%s: context size (%u) exceeds payload "
- "max\n", __FUNCTION__, len);
+ "max\n", __func__, len);
length = -ERANGE;
goto out3;
}
@@ -1760,7 +1761,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
out:
return ret;
err:
- printk(KERN_ERR "%s: failed while creating inodes\n", __FUNCTION__);
+ printk(KERN_ERR "%s: failed while creating inodes\n", __func__);
goto out;
}
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index cd10e27fc9e6..916e73a18bc5 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -280,8 +280,8 @@ int avtab_alloc(struct avtab *h, u32 nrules)
h->nel = 0;
h->nslot = nslot;
h->mask = mask;
- printk(KERN_DEBUG "SELinux:%d avtab hash slots allocated. "
- "Num of rules:%d\n", h->nslot, nrules);
+ printk(KERN_DEBUG "SELinux: %d avtab hash slots, %d rules.\n",
+ h->nslot, nrules);
return 0;
}
@@ -345,18 +345,18 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
if (vers < POLICYDB_VERSION_AVTAB) {
rc = next_entry(buf32, fp, sizeof(u32));
if (rc < 0) {
- printk(KERN_ERR "security: avtab: truncated entry\n");
+ printk(KERN_ERR "SELinux: avtab: truncated entry\n");
return -1;
}
items2 = le32_to_cpu(buf32[0]);
if (items2 > ARRAY_SIZE(buf32)) {
- printk(KERN_ERR "security: avtab: entry overflow\n");
+ printk(KERN_ERR "SELinux: avtab: entry overflow\n");
return -1;
}
rc = next_entry(buf32, fp, sizeof(u32)*items2);
if (rc < 0) {
- printk(KERN_ERR "security: avtab: truncated entry\n");
+ printk(KERN_ERR "SELinux: avtab: truncated entry\n");
return -1;
}
items = 0;
@@ -364,19 +364,19 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
val = le32_to_cpu(buf32[items++]);
key.source_type = (u16)val;
if (key.source_type != val) {
- printk("security: avtab: truncated source type\n");
+ printk("SELinux: avtab: truncated source type\n");
return -1;
}
val = le32_to_cpu(buf32[items++]);
key.target_type = (u16)val;
if (key.target_type != val) {
- printk("security: avtab: truncated target type\n");
+ printk("SELinux: avtab: truncated target type\n");
return -1;
}
val = le32_to_cpu(buf32[items++]);
key.target_class = (u16)val;
if (key.target_class != val) {
- printk("security: avtab: truncated target class\n");
+ printk("SELinux: avtab: truncated target class\n");
return -1;
}
@@ -384,12 +384,12 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0;
if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
- printk("security: avtab: null entry\n");
+ printk("SELinux: avtab: null entry\n");
return -1;
}
if ((val & AVTAB_AV) &&
(val & AVTAB_TYPE)) {
- printk("security: avtab: entry has both access vectors and types\n");
+ printk("SELinux: avtab: entry has both access vectors and types\n");
return -1;
}
@@ -403,7 +403,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
}
if (items != items2) {
- printk("security: avtab: entry only had %d items, expected %d\n", items2, items);
+ printk("SELinux: avtab: entry only had %d items, expected %d\n", items2, items);
return -1;
}
return 0;
@@ -411,7 +411,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
rc = next_entry(buf16, fp, sizeof(u16)*4);
if (rc < 0) {
- printk("security: avtab: truncated entry\n");
+ printk("SELinux: avtab: truncated entry\n");
return -1;
}
@@ -424,7 +424,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
if (!policydb_type_isvalid(pol, key.source_type) ||
!policydb_type_isvalid(pol, key.target_type) ||
!policydb_class_isvalid(pol, key.target_class)) {
- printk(KERN_WARNING "security: avtab: invalid type or class\n");
+ printk(KERN_WARNING "SELinux: avtab: invalid type or class\n");
return -1;
}
@@ -435,19 +435,19 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
}
if (!set || set > 1) {
printk(KERN_WARNING
- "security: avtab: more than one specifier\n");
+ "SELinux: avtab: more than one specifier\n");
return -1;
}
rc = next_entry(buf32, fp, sizeof(u32));
if (rc < 0) {
- printk("security: avtab: truncated entry\n");
+ printk("SELinux: avtab: truncated entry\n");
return -1;
}
datum.data = le32_to_cpu(*buf32);
if ((key.specified & AVTAB_TYPE) &&
!policydb_type_isvalid(pol, datum.data)) {
- printk(KERN_WARNING "security: avtab: invalid type\n");
+ printk(KERN_WARNING "SELinux: avtab: invalid type\n");
return -1;
}
return insertf(a, &key, &datum, p);
@@ -468,12 +468,12 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
rc = next_entry(buf, fp, sizeof(u32));
if (rc < 0) {
- printk(KERN_ERR "security: avtab: truncated table\n");
+ printk(KERN_ERR "SELinux: avtab: truncated table\n");
goto bad;
}
nel = le32_to_cpu(buf[0]);
if (!nel) {
- printk(KERN_ERR "security: avtab: table is empty\n");
+ printk(KERN_ERR "SELinux: avtab: table is empty\n");
rc = -EINVAL;
goto bad;
}
@@ -486,9 +486,9 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL);
if (rc) {
if (rc == -ENOMEM)
- printk(KERN_ERR "security: avtab: out of memory\n");
+ printk(KERN_ERR "SELinux: avtab: out of memory\n");
else if (rc == -EEXIST)
- printk(KERN_ERR "security: avtab: duplicate entry\n");
+ printk(KERN_ERR "SELinux: avtab: duplicate entry\n");
else
rc = -EINVAL;
goto bad;
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index 50ad85d4b77c..a996cf1d378a 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -96,7 +96,7 @@ int evaluate_cond_node(struct policydb *p, struct cond_node *node)
if (new_state != node->cur_state) {
node->cur_state = new_state;
if (new_state == -1)
- printk(KERN_ERR "security: expression result was undefined - disabling all rules.\n");
+ printk(KERN_ERR "SELinux: expression result was undefined - disabling all rules.\n");
/* turn the rules on or off */
for (cur = node->true_list; cur != NULL; cur = cur->next) {
if (new_state <= 0) {
@@ -276,7 +276,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
*/
if (k->specified & AVTAB_TYPE) {
if (avtab_search(&p->te_avtab, k)) {
- printk("security: type rule already exists outside of a conditional.");
+ printk("SELinux: type rule already exists outside of a conditional.");
goto err;
}
/*
@@ -291,7 +291,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
node_ptr = avtab_search_node(&p->te_cond_avtab, k);
if (node_ptr) {
if (avtab_search_node_next(node_ptr, k->specified)) {
- printk("security: too many conflicting type rules.");
+ printk("SELinux: too many conflicting type rules.");
goto err;
}
found = 0;
@@ -302,13 +302,13 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
}
}
if (!found) {
- printk("security: conflicting type rules.\n");
+ printk("SELinux: conflicting type rules.\n");
goto err;
}
}
} else {
if (avtab_search(&p->te_cond_avtab, k)) {
- printk("security: conflicting type rules when adding type rule for true.\n");
+ printk("SELinux: conflicting type rules when adding type rule for true.\n");
goto err;
}
}
@@ -316,7 +316,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
if (!node_ptr) {
- printk("security: could not insert rule.");
+ printk("SELinux: could not insert rule.");
goto err;
}
@@ -376,12 +376,12 @@ static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list *
static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
{
if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
- printk("security: conditional expressions uses unknown operator.\n");
+ printk("SELinux: conditional expressions uses unknown operator.\n");
return 0;
}
if (expr->bool > p->p_bools.nprim) {
- printk("security: conditional expressions uses unknown bool.\n");
+ printk("SELinux: conditional expressions uses unknown bool.\n");
return 0;
}
return 1;
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index 920b5e36a1af..e499af474b35 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -364,7 +364,7 @@ int ebitmap_read(struct ebitmap *e, void *fp)
count = le32_to_cpu(buf[2]);
if (mapunit != sizeof(u64) * 8) {
- printk(KERN_ERR "security: ebitmap: map size %u does not "
+ printk(KERN_ERR "SELinux: ebitmap: map size %u does not "
"match my size %Zd (high bit was %d)\n",
mapunit, sizeof(u64) * 8, e->highbit);
goto bad;
@@ -382,19 +382,19 @@ int ebitmap_read(struct ebitmap *e, void *fp)
for (i = 0; i < count; i++) {
rc = next_entry(&startbit, fp, sizeof(u32));
if (rc < 0) {
- printk(KERN_ERR "security: ebitmap: truncated map\n");
+ printk(KERN_ERR "SELinux: ebitmap: truncated map\n");
goto bad;
}
startbit = le32_to_cpu(startbit);
if (startbit & (mapunit - 1)) {
- printk(KERN_ERR "security: ebitmap start bit (%d) is "
+ printk(KERN_ERR "SELinux: ebitmap start bit (%d) is "
"not a multiple of the map unit size (%u)\n",
startbit, mapunit);
goto bad;
}
if (startbit > e->highbit - mapunit) {
- printk(KERN_ERR "security: ebitmap start bit (%d) is "
+ printk(KERN_ERR "SELinux: ebitmap start bit (%d) is "
"beyond the end of the bitmap (%u)\n",
startbit, (e->highbit - mapunit));
goto bad;
@@ -405,7 +405,7 @@ int ebitmap_read(struct ebitmap *e, void *fp)
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp) {
printk(KERN_ERR
- "security: ebitmap: out of memory\n");
+ "SELinux: ebitmap: out of memory\n");
rc = -ENOMEM;
goto bad;
}
@@ -418,7 +418,7 @@ int ebitmap_read(struct ebitmap *e, void *fp)
}
n = tmp;
} else if (startbit <= n->startbit) {
- printk(KERN_ERR "security: ebitmap: start bit %d"
+ printk(KERN_ERR "SELinux: ebitmap: start bit %d"
" comes after start bit %d\n",
startbit, n->startbit);
goto bad;
@@ -426,7 +426,7 @@ int ebitmap_read(struct ebitmap *e, void *fp)
rc = next_entry(&map, fp, sizeof(u64));
if (rc < 0) {
- printk(KERN_ERR "security: ebitmap: truncated map\n");
+ printk(KERN_ERR "SELinux: ebitmap: truncated map\n");
goto bad;
}
map = le64_to_cpu(map);
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index bd7d6a00342d..6bdb0ff6a927 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -111,6 +111,11 @@ static struct policydb_compat_info policydb_compat[] = {
.version = POLICYDB_VERSION_POLCAP,
.sym_num = SYM_NUM,
.ocon_num = OCON_NUM,
+ },
+ {
+ .version = POLICYDB_VERSION_PERMISSIVE,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
}
};
@@ -194,6 +199,7 @@ static int policydb_init(struct policydb *p)
goto out_free_symtab;
ebitmap_init(&p->policycaps);
+ ebitmap_init(&p->permissive_map);
out:
return rc;
@@ -401,14 +407,14 @@ static int policydb_index_others(struct policydb *p)
{
int i, rc = 0;
- printk(KERN_DEBUG "security: %d users, %d roles, %d types, %d bools",
+ printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools",
p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
if (selinux_mls_enabled)
printk(", %d sens, %d cats", p->p_levels.nprim,
p->p_cats.nprim);
printk("\n");
- printk(KERN_DEBUG "security: %d classes, %d rules\n",
+ printk(KERN_DEBUG "SELinux: %d classes, %d rules\n",
p->p_classes.nprim, p->te_avtab.nel);
#ifdef DEBUG_HASHES
@@ -687,6 +693,7 @@ void policydb_destroy(struct policydb *p)
kfree(p->type_attr_map);
kfree(p->undefined_perms);
ebitmap_destroy(&p->policycaps);
+ ebitmap_destroy(&p->permissive_map);
return;
}
@@ -702,20 +709,20 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s)
rc = sidtab_init(s);
if (rc) {
- printk(KERN_ERR "security: out of memory on SID table init\n");
+ printk(KERN_ERR "SELinux: out of memory on SID table init\n");
goto out;
}
head = p->ocontexts[OCON_ISID];
for (c = head; c; c = c->next) {
if (!c->context[0].user) {
- printk(KERN_ERR "security: SID %s was never "
+ printk(KERN_ERR "SELinux: SID %s was never "
"defined.\n", c->u.name);
rc = -EINVAL;
goto out;
}
if (sidtab_insert(s, c->sid[0], &c->context[0])) {
- printk(KERN_ERR "security: unable to load initial "
+ printk(KERN_ERR "SELinux: unable to load initial "
"SID %s.\n", c->u.name);
rc = -EINVAL;
goto out;
@@ -809,13 +816,13 @@ static int mls_read_range_helper(struct mls_range *r, void *fp)
items = le32_to_cpu(buf[0]);
if (items > ARRAY_SIZE(buf)) {
- printk(KERN_ERR "security: mls: range overflow\n");
+ printk(KERN_ERR "SELinux: mls: range overflow\n");
rc = -EINVAL;
goto out;
}
rc = next_entry(buf, fp, sizeof(u32) * items);
if (rc < 0) {
- printk(KERN_ERR "security: mls: truncated range\n");
+ printk(KERN_ERR "SELinux: mls: truncated range\n");
goto out;
}
r->level[0].sens = le32_to_cpu(buf[0]);
@@ -826,21 +833,21 @@ static int mls_read_range_helper(struct mls_range *r, void *fp)
rc = ebitmap_read(&r->level[0].cat, fp);
if (rc) {
- printk(KERN_ERR "security: mls: error reading low "
+ printk(KERN_ERR "SELinux: mls: error reading low "
"categories\n");
goto out;
}
if (items > 1) {
rc = ebitmap_read(&r->level[1].cat, fp);
if (rc) {
- printk(KERN_ERR "security: mls: error reading high "
+ printk(KERN_ERR "SELinux: mls: error reading high "
"categories\n");
goto bad_high;
}
} else {
rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
if (rc) {
- printk(KERN_ERR "security: mls: out of memory\n");
+ printk(KERN_ERR "SELinux: mls: out of memory\n");
goto bad_high;
}
}
@@ -866,7 +873,7 @@ static int context_read_and_validate(struct context *c,
rc = next_entry(buf, fp, sizeof buf);
if (rc < 0) {
- printk(KERN_ERR "security: context truncated\n");
+ printk(KERN_ERR "SELinux: context truncated\n");
goto out;
}
c->user = le32_to_cpu(buf[0]);
@@ -874,7 +881,7 @@ static int context_read_and_validate(struct context *c,
c->type = le32_to_cpu(buf[2]);
if (p->policyvers >= POLICYDB_VERSION_MLS) {
if (mls_read_range_helper(&c->range, fp)) {
- printk(KERN_ERR "security: error reading MLS range of "
+ printk(KERN_ERR "SELinux: error reading MLS range of "
"context\n");
rc = -EINVAL;
goto out;
@@ -882,7 +889,7 @@ static int context_read_and_validate(struct context *c,
}
if (!policydb_context_isvalid(p, c)) {
- printk(KERN_ERR "security: invalid security context\n");
+ printk(KERN_ERR "SELinux: invalid security context\n");
context_destroy(c);
rc = -EINVAL;
}
@@ -1128,7 +1135,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
cladatum->comdatum = hashtab_search(p->p_commons.table,
cladatum->comkey);
if (!cladatum->comdatum) {
- printk(KERN_ERR "security: unknown common %s\n",
+ printk(KERN_ERR "SELinux: unknown common %s\n",
cladatum->comkey);
rc = -EINVAL;
goto bad;
@@ -1283,13 +1290,13 @@ static int mls_read_level(struct mls_level *lp, void *fp)
rc = next_entry(buf, fp, sizeof buf);
if (rc < 0) {
- printk(KERN_ERR "security: mls: truncated level\n");
+ printk(KERN_ERR "SELinux: mls: truncated level\n");
goto bad;
}
lp->sens = le32_to_cpu(buf[0]);
if (ebitmap_read(&lp->cat, fp)) {
- printk(KERN_ERR "security: mls: error reading level "
+ printk(KERN_ERR "SELinux: mls: error reading level "
"categories\n");
goto bad;
}
@@ -1491,7 +1498,7 @@ int policydb_read(struct policydb *p, void *fp)
goto bad;
if (le32_to_cpu(buf[0]) != POLICYDB_MAGIC) {
- printk(KERN_ERR "security: policydb magic number 0x%x does "
+ printk(KERN_ERR "SELinux: policydb magic number 0x%x does "
"not match expected magic number 0x%x\n",
le32_to_cpu(buf[0]), POLICYDB_MAGIC);
goto bad;
@@ -1499,27 +1506,27 @@ int policydb_read(struct policydb *p, void *fp)
len = le32_to_cpu(buf[1]);
if (len != strlen(POLICYDB_STRING)) {
- printk(KERN_ERR "security: policydb string length %d does not "
+ printk(KERN_ERR "SELinux: policydb string length %d does not "
"match expected length %Zu\n",
len, strlen(POLICYDB_STRING));
goto bad;
}
policydb_str = kmalloc(len + 1,GFP_KERNEL);
if (!policydb_str) {
- printk(KERN_ERR "security: unable to allocate memory for policydb "
+ printk(KERN_ERR "SELinux: unable to allocate memory for policydb "
"string of length %d\n", len);
rc = -ENOMEM;
goto bad;
}
rc = next_entry(policydb_str, fp, len);
if (rc < 0) {
- printk(KERN_ERR "security: truncated policydb string identifier\n");
+ printk(KERN_ERR "SELinux: truncated policydb string identifier\n");
kfree(policydb_str);
goto bad;
}
policydb_str[len] = 0;
if (strcmp(policydb_str, POLICYDB_STRING)) {
- printk(KERN_ERR "security: policydb string %s does not match "
+ printk(KERN_ERR "SELinux: policydb string %s does not match "
"my string %s\n", policydb_str, POLICYDB_STRING);
kfree(policydb_str);
goto bad;
@@ -1536,7 +1543,7 @@ int policydb_read(struct policydb *p, void *fp)
p->policyvers = le32_to_cpu(buf[0]);
if (p->policyvers < POLICYDB_VERSION_MIN ||
p->policyvers > POLICYDB_VERSION_MAX) {
- printk(KERN_ERR "security: policydb version %d does not match "
+ printk(KERN_ERR "SELinux: policydb version %d does not match "
"my version range %d-%d\n",
le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
goto bad;
@@ -1570,16 +1577,20 @@ int policydb_read(struct policydb *p, void *fp)
ebitmap_read(&p->policycaps, fp) != 0)
goto bad;
+ if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE &&
+ ebitmap_read(&p->permissive_map, fp) != 0)
+ goto bad;
+
info = policydb_lookup_compat(p->policyvers);
if (!info) {
- printk(KERN_ERR "security: unable to find policy compat info "
+ printk(KERN_ERR "SELinux: unable to find policy compat info "
"for version %d\n", p->policyvers);
goto bad;
}
if (le32_to_cpu(buf[2]) != info->sym_num ||
le32_to_cpu(buf[3]) != info->ocon_num) {
- printk(KERN_ERR "security: policydb table sizes (%d,%d) do "
+ printk(KERN_ERR "SELinux: policydb table sizes (%d,%d) do "
"not match mine (%d,%d)\n", le32_to_cpu(buf[2]),
le32_to_cpu(buf[3]),
info->sym_num, info->ocon_num);
@@ -1823,7 +1834,7 @@ int policydb_read(struct policydb *p, void *fp)
for (genfs_p = NULL, genfs = p->genfs; genfs;
genfs_p = genfs, genfs = genfs->next) {
if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
- printk(KERN_ERR "security: dup genfs "
+ printk(KERN_ERR "SELinux: dup genfs "
"fstype %s\n", newgenfs->fstype);
kfree(newgenfs->fstype);
kfree(newgenfs);
@@ -1873,7 +1884,7 @@ int policydb_read(struct policydb *p, void *fp)
if (!strcmp(newc->u.name, c->u.name) &&
(!c->v.sclass || !newc->v.sclass ||
newc->v.sclass == c->v.sclass)) {
- printk(KERN_ERR "security: dup genfs "
+ printk(KERN_ERR "SELinux: dup genfs "
"entry (%s,%s)\n",
newgenfs->fstype, c->u.name);
goto bad_newc;
@@ -1931,7 +1942,7 @@ int policydb_read(struct policydb *p, void *fp)
if (rc)
goto bad;
if (!mls_range_isvalid(p, &rt->target_range)) {
- printk(KERN_WARNING "security: rangetrans: invalid range\n");
+ printk(KERN_WARNING "SELinux: rangetrans: invalid range\n");
goto bad;
}
lrt = rt;
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index c4ce996e202c..ba593a3da877 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -243,6 +243,8 @@ struct policydb {
struct ebitmap policycaps;
+ struct ebitmap permissive_map;
+
unsigned int policyvers;
unsigned int reject_unknown : 1;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 5fd54f2bbaac..33425b1ac8d6 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -40,6 +40,7 @@
#include <linux/sched.h>
#include <linux/audit.h>
#include <linux/mutex.h>
+#include <linux/selinux.h>
#include <net/netlabel.h>
#include "flask.h"
@@ -61,6 +62,7 @@ extern void selnl_notify_policyload(u32 seqno);
unsigned int policydb_loaded_version;
int selinux_policycap_netpeer;
+int selinux_policycap_openperm;
/*
* This is declared in avc.c
@@ -412,10 +414,35 @@ static int context_struct_compute_av(struct context *scontext,
return 0;
inval_class:
- printk(KERN_ERR "%s: unrecognized class %d\n", __FUNCTION__, tclass);
+ printk(KERN_ERR "%s: unrecognized class %d\n", __func__, tclass);
return -EINVAL;
}
+/*
+ * Given a sid find if the type has the permissive flag set
+ */
+int security_permissive_sid(u32 sid)
+{
+ struct context *context;
+ u32 type;
+ int rc;
+
+ POLICY_RDLOCK;
+
+ context = sidtab_search(&sidtab, sid);
+ BUG_ON(!context);
+
+ type = context->type;
+ /*
+ * we are intentionally using type here, not type-1, the 0th bit may
+ * someday indicate that we are globally setting permissive in policy.
+ */
+ rc = ebitmap_get_bit(&policydb.permissive_map, type);
+
+ POLICY_RDUNLOCK;
+ return rc;
+}
+
static int security_validtrans_handle_fail(struct context *ocontext,
struct context *ncontext,
struct context *tcontext,
@@ -1096,7 +1123,7 @@ static int validate_classes(struct policydb *p)
continue;
if (i > p->p_classes.nprim) {
printk(KERN_INFO
- "security: class %s not defined in policy\n",
+ "SELinux: class %s not defined in policy\n",
def_class);
if (p->reject_unknown)
return -EINVAL;
@@ -1107,7 +1134,7 @@ static int validate_classes(struct policydb *p)
pol_class = p->p_class_val_to_name[i-1];
if (strcmp(pol_class, def_class)) {
printk(KERN_ERR
- "security: class %d is incorrect, found %s but should be %s\n",
+ "SELinux: class %d is incorrect, found %s but should be %s\n",
i, pol_class, def_class);
return -EINVAL;
}
@@ -1125,7 +1152,7 @@ static int validate_classes(struct policydb *p)
nprim = 1 << (perms->nprim - 1);
if (perm_val > nprim) {
printk(KERN_INFO
- "security: permission %s in class %s not defined in policy\n",
+ "SELinux: permission %s in class %s not defined in policy\n",
def_perm, pol_class);
if (p->reject_unknown)
return -EINVAL;
@@ -1136,14 +1163,14 @@ static int validate_classes(struct policydb *p)
perdatum = hashtab_search(perms->table, def_perm);
if (perdatum == NULL) {
printk(KERN_ERR
- "security: permission %s in class %s not found in policy, bad policy\n",
+ "SELinux: permission %s in class %s not found in policy, bad policy\n",
def_perm, pol_class);
return -EINVAL;
}
pol_val = 1 << (perdatum->value - 1);
if (pol_val != perm_val) {
printk(KERN_ERR
- "security: permission %s in class %s has incorrect value\n",
+ "SELinux: permission %s in class %s has incorrect value\n",
def_perm, pol_class);
return -EINVAL;
}
@@ -1157,7 +1184,7 @@ static int validate_classes(struct policydb *p)
BUG_ON(!cladatum);
if (!cladatum->comdatum) {
printk(KERN_ERR
- "security: class %s should have an inherits clause but does not\n",
+ "SELinux: class %s should have an inherits clause but does not\n",
pol_class);
return -EINVAL;
}
@@ -1172,7 +1199,7 @@ static int validate_classes(struct policydb *p)
def_perm = kdefs->av_inherit[i].common_pts[j];
if (j >= perms->nprim) {
printk(KERN_INFO
- "security: permission %s in class %s not defined in policy\n",
+ "SELinux: permission %s in class %s not defined in policy\n",
def_perm, pol_class);
if (p->reject_unknown)
return -EINVAL;
@@ -1183,13 +1210,13 @@ static int validate_classes(struct policydb *p)
perdatum = hashtab_search(perms->table, def_perm);
if (perdatum == NULL) {
printk(KERN_ERR
- "security: permission %s in class %s not found in policy, bad policy\n",
+ "SELinux: permission %s in class %s not found in policy, bad policy\n",
def_perm, pol_class);
return -EINVAL;
}
if (perdatum->value != j + 1) {
printk(KERN_ERR
- "security: permission %s in class %s has incorrect value\n",
+ "SELinux: permission %s in class %s has incorrect value\n",
def_perm, pol_class);
return -EINVAL;
}
@@ -1219,7 +1246,7 @@ static inline int convert_context_handle_invalid_context(struct context *context
u32 len;
context_struct_to_string(context, &s, &len);
- printk(KERN_ERR "security: context %s is invalid\n", s);
+ printk(KERN_ERR "SELinux: context %s is invalid\n", s);
kfree(s);
}
return rc;
@@ -1299,7 +1326,7 @@ out:
bad:
context_struct_to_string(&oldc, &s, &len);
context_destroy(&oldc);
- printk(KERN_ERR "security: invalidating context %s\n", s);
+ printk(KERN_ERR "SELinux: invalidating context %s\n", s);
kfree(s);
goto out;
}
@@ -1308,6 +1335,8 @@ static void security_load_policycaps(void)
{
selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps,
POLICYDB_CAPABILITY_NETPEER);
+ selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps,
+ POLICYDB_CAPABILITY_OPENPERM);
}
extern void selinux_complete_init(void);
@@ -1350,7 +1379,7 @@ int security_load_policy(void *data, size_t len)
/* Verify that the kernel defined classes are correct. */
if (validate_classes(&policydb)) {
printk(KERN_ERR
- "security: the definition of a class is incorrect\n");
+ "SELinux: the definition of a class is incorrect\n");
LOAD_UNLOCK;
sidtab_destroy(&sidtab);
policydb_destroy(&policydb);
@@ -1384,14 +1413,14 @@ int security_load_policy(void *data, size_t len)
/* Verify that the kernel defined classes are correct. */
if (validate_classes(&newpolicydb)) {
printk(KERN_ERR
- "security: the definition of a class is incorrect\n");
+ "SELinux: the definition of a class is incorrect\n");
rc = -EINVAL;
goto err;
}
rc = security_preserve_bools(&newpolicydb);
if (rc) {
- printk(KERN_ERR "security: unable to preserve booleans\n");
+ printk(KERN_ERR "SELinux: unable to preserve booleans\n");
goto err;
}
@@ -1443,17 +1472,11 @@ err:
/**
* security_port_sid - Obtain the SID for a port.
- * @domain: communication domain aka address family
- * @type: socket type
* @protocol: protocol number
* @port: port number
* @out_sid: security identifier
*/
-int security_port_sid(u16 domain,
- u16 type,
- u8 protocol,
- u16 port,
- u32 *out_sid)
+int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
{
struct ocontext *c;
int rc = 0;
@@ -2203,7 +2226,7 @@ int security_get_permissions(char *class, char ***perms, int *nperms)
match = hashtab_search(policydb.p_classes.table, class);
if (!match) {
printk(KERN_ERR "%s: unrecognized class %s\n",
- __FUNCTION__, class);
+ __func__, class);
rc = -EINVAL;
goto out;
}