#include "avc.h"
#include "objsec.h"
#include "netif.h"
+#include "xfrm.h"
#define XATTR_SELINUX_SUFFIX "selinux"
#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
{
struct task_security_struct *tsec;
- tsec = kmalloc(sizeof(struct task_security_struct), GFP_KERNEL);
+ tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
if (!tsec)
return -ENOMEM;
- memset(tsec, 0, sizeof(struct task_security_struct));
tsec->magic = SELINUX_MAGIC;
tsec->task = task;
tsec->osid = tsec->sid = tsec->ptrace_sid = SECINITSID_UNLABELED;
struct task_security_struct *tsec = current->security;
struct inode_security_struct *isec;
- isec = kmalloc(sizeof(struct inode_security_struct), GFP_KERNEL);
+ isec = kzalloc(sizeof(struct inode_security_struct), GFP_KERNEL);
if (!isec)
return -ENOMEM;
- memset(isec, 0, sizeof(struct inode_security_struct));
init_MUTEX(&isec->sem);
INIT_LIST_HEAD(&isec->list);
isec->magic = SELINUX_MAGIC;
struct task_security_struct *tsec = current->security;
struct file_security_struct *fsec;
- fsec = kmalloc(sizeof(struct file_security_struct), GFP_ATOMIC);
+ fsec = kzalloc(sizeof(struct file_security_struct), GFP_ATOMIC);
if (!fsec)
return -ENOMEM;
- memset(fsec, 0, sizeof(struct file_security_struct));
fsec->magic = SELINUX_MAGIC;
fsec->file = file;
if (tsec && tsec->magic == SELINUX_MAGIC) {
{
struct superblock_security_struct *sbsec;
- sbsec = kmalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
+ sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
if (!sbsec)
return -ENOMEM;
- memset(sbsec, 0, sizeof(struct superblock_security_struct));
init_MUTEX(&sbsec->sem);
INIT_LIST_HEAD(&sbsec->list);
INIT_LIST_HEAD(&sbsec->isec_head);
}
#ifdef CONFIG_SECURITY_NETWORK
-static int sk_alloc_security(struct sock *sk, int family, int priority)
+static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
{
struct sk_security_struct *ssec;
if (family != PF_UNIX)
return 0;
- ssec = kmalloc(sizeof(*ssec), priority);
+ ssec = kzalloc(sizeof(*ssec), priority);
if (!ssec)
return -ENOMEM;
- memset(ssec, 0, sizeof(*ssec));
ssec->magic = SELINUX_MAGIC;
ssec->sk = sk;
ssec->peer_sid = SECINITSID_UNLABELED;
return SECCLASS_FILE;
}
+static inline int default_protocol_stream(int protocol)
+{
+ return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
+}
+
+static inline int default_protocol_dgram(int protocol)
+{
+ return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
+}
+
static inline u16 socket_type_to_security_class(int family, int type, int protocol)
{
switch (family) {
case PF_INET6:
switch (type) {
case SOCK_STREAM:
- return SECCLASS_TCP_SOCKET;
+ if (default_protocol_stream(protocol))
+ return SECCLASS_TCP_SOCKET;
+ else
+ return SECCLASS_RAWIP_SOCKET;
case SOCK_DGRAM:
- return SECCLASS_UDP_SOCKET;
- case SOCK_RAW:
+ if (default_protocol_dgram(protocol))
+ return SECCLASS_UDP_SOCKET;
+ else
+ return SECCLASS_RAWIP_SOCKET;
+ default:
return SECCLASS_RAWIP_SOCKET;
}
break;
{
struct bprm_security_struct *bsec;
- bsec = kmalloc(sizeof(struct bprm_security_struct), GFP_KERNEL);
+ bsec = kzalloc(sizeof(struct bprm_security_struct), GFP_KERNEL);
if (!bsec)
return -ENOMEM;
- memset(bsec, 0, sizeof *bsec);
bsec->magic = SELINUX_MAGIC;
bsec->bprm = bprm;
bsec->sid = SECINITSID_UNLABELED;
struct avc_audit_data ad;
struct file *file, *devnull = NULL;
struct tty_struct *tty = current->signal->tty;
+ struct fdtable *fdt;
long j = -1;
if (tty) {
file_list_lock();
- file = list_entry(tty->tty_files.next, typeof(*file), f_list);
+ file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list);
if (file) {
/* Revalidate access to controlling tty.
Use inode_has_perm on the tty inode directly rather
j++;
i = j * __NFDBITS;
- if (i >= files->max_fds || i >= files->max_fdset)
+ fdt = files_fdtable(files);
+ if (i >= fdt->max_fds || i >= fdt->max_fdset)
break;
- set = files->open_fds->fds_bits[j];
+ set = fdt->open_fds->fds_bits[j];
if (!set)
continue;
spin_unlock(&files->file_lock);
continue;
}
if (devnull) {
- atomic_inc(&devnull->f_count);
+ get_file(devnull);
} else {
devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR);
if (!devnull) {
inode_security_set_sid(inode, newsid);
+ if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
+ return -EOPNOTSUPP;
+
if (name) {
namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_KERNEL);
if (!namep)
static int selinux_inode_getxattr (struct dentry *dentry, char *name)
{
- struct inode *inode = dentry->d_inode;
- struct superblock_security_struct *sbsec = inode->i_sb->s_security;
-
- if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
- return -EOPNOTSUPP;
-
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
}
return -EACCES;
}
-static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
+/*
+ * Copy the in-core inode security context value to the user. If the
+ * getxattr() prior to this succeeded, check to see if we need to
+ * canonicalize the value to be finally returned to the user.
+ *
+ * Permission check is handled by selinux_inode_getxattr hook.
+ */
+static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
{
struct inode_security_struct *isec = inode->i_security;
char *context;
unsigned len;
int rc;
- /* Permission check handled by selinux_inode_getxattr hook.*/
-
- if (strcmp(name, XATTR_SELINUX_SUFFIX))
- return -EOPNOTSUPP;
+ if (strcmp(name, XATTR_SELINUX_SUFFIX)) {
+ rc = -EOPNOTSUPP;
+ goto out;
+ }
rc = security_sid_to_context(isec->sid, &context, &len);
if (rc)
- return rc;
+ goto out;
+ /* Probe for required buffer size */
if (!buffer || !size) {
- kfree(context);
- return len;
+ rc = len;
+ goto out_free;
}
+
if (size < len) {
- kfree(context);
- return -ERANGE;
+ rc = -ERANGE;
+ goto out_free;
+ }
+
+ if (err > 0) {
+ if ((len == err) && !(memcmp(context, buffer, len))) {
+ /* Don't need to canonicalize value */
+ rc = err;
+ goto out_free;
+ }
+ memset(buffer, 0, size);
}
memcpy(buffer, context, len);
+ rc = len;
+out_free:
kfree(context);
- return len;
+out:
+ return rc;
}
static int selinux_inode_setsecurity(struct inode *inode, const char *name,
if (rc)
return rc;
- if (info && ((unsigned long)info == 1 ||
- (unsigned long)info == 2 || SI_FROMKERNEL(info)))
+ if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info)))
return 0;
if (!sig)
/*
* If PF_INET or PF_INET6, check name_bind permission for the port.
+ * Multiple address binding for SCTP is not supported yet: we just
+ * check the first address now.
*/
family = sock->sk->sk_family;
if (family == PF_INET || family == PF_INET6) {
goto out;
}
- switch(sk->sk_protocol) {
- case IPPROTO_TCP:
+ switch(isec->sclass) {
+ case SECCLASS_TCP_SOCKET:
node_perm = TCP_SOCKET__NODE_BIND;
break;
- case IPPROTO_UDP:
+ case SECCLASS_UDP_SOCKET:
node_perm = UDP_SOCKET__NODE_BIND;
break;
err = avc_has_perm(sock_sid, port_sid,
sock_class, recv_perm, &ad);
}
+
+ if (!err)
+ err = selinux_xfrm_sock_rcv_skb(sock_sid, skb);
+
out:
return err;
}
return err;
}
-static int selinux_sk_alloc_security(struct sock *sk, int family, int priority)
+static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
{
return sk_alloc_security(sk, family, priority);
}
sk_free_security(sk);
}
+static unsigned int selinux_sk_getsid_security(struct sock *sk, struct flowi *fl, u8 dir)
+{
+ struct inode_security_struct *isec;
+ u32 sock_sid = SECINITSID_ANY_SOCKET;
+
+ if (!sk)
+ return selinux_no_sk_sid(fl);
+
+ read_lock_bh(&sk->sk_callback_lock);
+ isec = get_sock_isec(sk);
+
+ if (isec)
+ sock_sid = isec->sid;
+
+ read_unlock_bh(&sk->sk_callback_lock);
+ return sock_sid;
+}
+
static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
{
int err = 0;
err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
if (err) {
if (err == -EINVAL) {
- audit_log(current->audit_context, AUDIT_SELINUX_ERR,
+ audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
"SELinux: unrecognized netlink message"
" type=%hu for sclass=%hu\n",
nlh->nlmsg_type, isec->sclass);
send_perm, &ad) ? NF_DROP : NF_ACCEPT;
}
+ if (err != NF_ACCEPT)
+ goto out;
+
+ err = selinux_xfrm_postroute_last(isec->sid, skb);
+
out:
return err;
}
struct task_security_struct *tsec = task->security;
struct ipc_security_struct *isec;
- isec = kmalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
+ isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
if (!isec)
return -ENOMEM;
- memset(isec, 0, sizeof(struct ipc_security_struct));
isec->magic = SELINUX_MAGIC;
isec->sclass = sclass;
isec->ipc_perm = perm;
{
struct msg_security_struct *msec;
- msec = kmalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
+ msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
if (!msec)
return -ENOMEM;
- memset(msec, 0, sizeof(struct msg_security_struct));
msec->magic = SELINUX_MAGIC;
msec->msg = msg;
msec->sid = SECINITSID_UNLABELED;
.socket_getpeersec = selinux_socket_getpeersec,
.sk_alloc_security = selinux_sk_alloc_security,
.sk_free_security = selinux_sk_free_security,
+ .sk_getsid = selinux_sk_getsid_security,
+#endif
+
+#ifdef CONFIG_SECURITY_NETWORK_XFRM
+ .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
+ .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
+ .xfrm_policy_free_security = selinux_xfrm_policy_free,
+ .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
+ .xfrm_state_free_security = selinux_xfrm_state_free,
+ .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
#endif
};
panic("SELinux: nf_register_hook for IPv6: error %d\n", err);
#endif /* IPV6 */
+
out:
return err;
}