#define SO_TIMESTAMP 29
#define SCM_TIMESTAMP SO_TIMESTAMP
+#define SO_PEERSEC 30
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 19
#define SO_SECURITY_ENCRYPTION_TRANSPORT 20
#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+
/* Nast libc5 fixup - bletch */
#if defined(__KERNEL__)
/* Socket types. */
#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+
/* Nast libc5 fixup - bletch */
#if defined(__KERNEL__)
/* Socket types. */
#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+
#if defined(__KERNEL__)
/* Socket types. */
#define SOCK_STREAM 1 /* stream (connection) socket */
#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+
/* Nast libc5 fixup - bletch */
#if defined(__KERNEL__)
/* Socket types. */
#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+
/* Nasty libc5 fixup - bletch */
#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
/* Socket types. */
#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+
/* Nast libc5 fixup - bletch */
#if defined(__KERNEL__)
/* Socket types. */
#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+
/* Nast libc5 fixup - bletch */
#if defined(__KERNEL__)
/* Socket types. */
#define SO_TIMESTAMP 29
#define SCM_TIMESTAMP SO_TIMESTAMP
+#define SO_PEERSEC 30
+
/* Nast libc5 fixup - bletch */
#if defined(__KERNEL__)
/* Socket types. */
#define SO_ACCEPTCONN 0x401c
+#define SO_PEERSEC 0x401d
+
#if defined(__KERNEL__)
#define SOCK_STREAM 1 /* stream (connection) socket */
#define SOCK_DGRAM 2 /* datagram (conn.less) socket */
#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+
/* Nast libc5 fixup - bletch */
#if defined(__KERNEL__)
/* Socket types. */
#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+
/* Nast libc5 fixup - bletch */
#if defined(__KERNEL__)
/* Socket types. */
#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+
/* Nast libc5 fixup - bletch */
#if defined(__KERNEL__)
/* Socket types. */
#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+
/* Nast libc5 fixup - bletch */
#if defined(__KERNEL__)
/* Socket types. */
#define SO_TIMESTAMP 0x001d
#define SCM_TIMESTAMP SO_TIMESTAMP
+#define SO_PEERSEC 0x100e
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
#define SO_TIMESTAMP 0x001d
#define SCM_TIMESTAMP SO_TIMESTAMP
+#define SO_PEERSEC 0x001e
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+
/* Nast libc5 fixup - bletch */
#if defined(__KERNEL__)
/* Socket types. */
#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+
/* Nasty libc5 fixup - bletch */
#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
/* Socket types. */
* incoming sk_buff @skb has been associated with a particular socket, @sk.
* @sk contains the sock (not socket) associated with the incoming sk_buff.
* @skb contains the incoming network data.
+ * @socket_getpeersec:
+ * This hook allows the security module to provide peer socket security
+ * state to userspace via getsockopt SO_GETPEERSEC.
+ * @sock is the local socket.
+ * @optval userspace memory where the security state is to be copied.
+ * @optlen userspace int where the module should copy the actual length
+ * of the security state.
+ * @len as input is the maximum length to copy to userspace provided
+ * by the caller.
+ * Return 0 if all is well, otherwise, typical getsockopt return
+ * values.
+ * @sk_alloc_security:
+ * Allocate and attach a security structure to the sk->sk_security field,
+ * which is used to copy security attributes between local stream sockets.
+ * @sk_free_security:
+ * Deallocate security structure.
*
* Security hooks affecting all System V IPC operations.
*
int (*socket_setsockopt) (struct socket * sock, int level, int optname);
int (*socket_shutdown) (struct socket * sock, int how);
int (*socket_sock_rcv_skb) (struct sock * sk, struct sk_buff * skb);
+ int (*socket_getpeersec) (struct socket *sock, char __user *optval, int __user *optlen, unsigned len);
+ int (*sk_alloc_security) (struct sock *sk, int family, int priority);
+ void (*sk_free_security) (struct sock *sk);
#endif /* CONFIG_SECURITY_NETWORK */
};
{
return security_ops->socket_sock_rcv_skb (sk, skb);
}
+
+static inline int security_socket_getpeersec(struct socket *sock, char __user *optval,
+ int __user *optlen, unsigned len)
+{
+ return security_ops->socket_getpeersec(sock, optval, optlen, len);
+}
+
+static inline int security_sk_alloc(struct sock *sk, int family, int priority)
+{
+ return security_ops->sk_alloc_security(sk, family, priority);
+}
+
+static inline void security_sk_free(struct sock *sk)
+{
+ return security_ops->sk_free_security(sk);
+}
#else /* CONFIG_SECURITY_NETWORK */
static inline int security_unix_stream_connect(struct socket * sock,
struct socket * other,
{
return 0;
}
+
+static inline int security_socket_getpeersec(struct socket *sock, char __user *optval,
+ int __user *optlen, unsigned len)
+{
+ return -ENOPROTOOPT;
+}
+
+static inline int security_sk_alloc(struct sock *sk, int family, int priority)
+{
+ return 0;
+}
+
+static inline void security_sk_free(struct sock *sk)
+{
+}
#endif /* CONFIG_SECURITY_NETWORK */
#endif /* ! __LINUX_SECURITY_H */
struct socket *sk_socket;
void *sk_user_data;
struct module *sk_owner;
+ void *sk_security;
void (*sk_state_change)(struct sock *sk);
void (*sk_data_ready)(struct sock *sk, int bytes);
void (*sk_write_space)(struct sock *sk);
v.val = sk->sk_state == TCP_LISTEN;
break;
+ case SO_PEERSEC:
+ return security_socket_getpeersec(sock, optval, optlen, len);
+
default:
return(-ENOPROTOOPT);
}
sock_lock_init(sk);
}
sk->sk_slab = slab;
+
+ if (security_sk_alloc(sk, family, priority)) {
+ kmem_cache_free(slab, sk);
+ sk = NULL;
+ }
}
return sk;
}
printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n",
__FUNCTION__, atomic_read(&sk->sk_omem_alloc));
+ security_sk_free(sk);
kmem_cache_free(sk->sk_slab, sk);
module_put(owner);
}
{
return 0;
}
+
+static int dummy_socket_getpeersec(struct socket *sock, char __user *optval,
+ int __user *optlen, unsigned len)
+{
+ return -ENOPROTOOPT;
+}
+
+static inline int dummy_sk_alloc_security (struct sock *sk, int family, int priority)
+{
+ return 0;
+}
+
+static inline void dummy_sk_free_security (struct sock *sk)
+{
+}
#endif /* CONFIG_SECURITY_NETWORK */
static int dummy_register_security (const char *name, struct security_operations *ops)
set_to_dummy_if_null(ops, socket_getsockopt);
set_to_dummy_if_null(ops, socket_shutdown);
set_to_dummy_if_null(ops, socket_sock_rcv_skb);
+ set_to_dummy_if_null(ops, socket_getpeersec);
+ set_to_dummy_if_null(ops, sk_alloc_security);
+ set_to_dummy_if_null(ops, sk_free_security);
#endif /* CONFIG_SECURITY_NETWORK */
}
kfree(sbsec);
}
+#ifdef CONFIG_SECURITY_NETWORK
+static int sk_alloc_security(struct sock *sk, int family, int priority)
+{
+ struct sk_security_struct *ssec;
+
+ if (family != PF_UNIX)
+ return 0;
+
+ ssec = kmalloc(sizeof(*ssec), priority);
+ if (!ssec)
+ return -ENOMEM;
+
+ memset(ssec, 0, sizeof(*ssec));
+ ssec->magic = SELINUX_MAGIC;
+ ssec->sk = sk;
+ ssec->peer_sid = SECINITSID_UNLABELED;
+ sk->sk_security = ssec;
+
+ return 0;
+}
+
+static void sk_free_security(struct sock *sk)
+{
+ struct task_security_struct *ssec = sk->sk_security;
+
+ if (sk->sk_family != PF_UNIX || ssec->magic != SELINUX_MAGIC)
+ return;
+
+ sk->sk_security = NULL;
+ kfree(ssec);
+}
+#endif /* CONFIG_SECURITY_NETWORK */
+
/* The security server must be initialized before
any labeling or access decisions can be provided. */
extern int ss_initialized;
struct socket *other,
struct sock *newsk)
{
+ struct sk_security_struct *ssec;
struct inode_security_struct *isec;
struct inode_security_struct *other_isec;
struct avc_audit_data ad;
if (err)
return err;
+ /* connecting socket */
+ ssec = sock->sk->sk_security;
+ ssec->peer_sid = other_isec->sid;
+
+ /* server child socket */
+ ssec = newsk->sk_security;
+ ssec->peer_sid = isec->sid;
+
return 0;
}
return err;
}
+static int selinux_socket_getpeersec(struct socket *sock, char __user *optval,
+ int __user *optlen, unsigned len)
+{
+ int err = 0;
+ char *scontext;
+ u32 scontext_len;
+ struct sk_security_struct *ssec;
+ struct inode_security_struct *isec;
+
+ isec = SOCK_INODE(sock)->i_security;
+ if (isec->sclass != SECCLASS_UNIX_STREAM_SOCKET) {
+ err = -ENOPROTOOPT;
+ goto out;
+ }
+
+ ssec = sock->sk->sk_security;
+
+ err = security_sid_to_context(ssec->peer_sid, &scontext, &scontext_len);
+ if (err)
+ goto out;
+
+ if (scontext_len > len) {
+ err = -ERANGE;
+ goto out_len;
+ }
+
+ if (copy_to_user(optval, scontext, scontext_len))
+ err = -EFAULT;
+
+out_len:
+ if (put_user(scontext_len, optlen))
+ err = -EFAULT;
+
+ kfree(scontext);
+out:
+ return err;
+}
+
+static int selinux_sk_alloc_security(struct sock *sk, int family, int priority)
+{
+ return sk_alloc_security(sk, family, priority);
+}
+
+static void selinux_sk_free_security(struct sock *sk)
+{
+ sk_free_security(sk);
+}
+
#ifdef CONFIG_NETFILTER
static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
struct sk_buff **pskb,
out:
return err;
}
+
#endif /* CONFIG_NETFILTER */
#endif /* CONFIG_SECURITY_NETWORK */
.socket_setsockopt = selinux_socket_setsockopt,
.socket_shutdown = selinux_socket_shutdown,
.socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
+ .socket_getpeersec = selinux_socket_getpeersec,
+ .sk_alloc_security = selinux_sk_alloc_security,
+ .sk_free_security = selinux_sk_free_security,
#endif
};
struct avc_entry_ref avcr; /* reference to permissions */
};
+struct sk_security_struct {
+ unsigned long magic; /* magic number for this module */
+ struct sock *sk; /* back pointer to sk object */
+ u32 peer_sid; /* SID of peer */
+};
+
extern int inode_security_set_sid(struct inode *inode, u32 sid);
#endif /* _SELINUX_OBJSEC_H_ */