These functions checks whether TOMOYO can do permission checks or not.
TOMOYO won't do permission checks if the process is a kernel thread
or the process is not permitted to sleep.
Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Toshiharu Harada <haradats@nttdata.co.jp>
Cc: linux-netdev <netdev@vger.kernel.org>
---
include/linux/tomoyo_socket.h | 419 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 419 insertions(+)
--- /dev/null
+++ linux-2.6.25-rc8-mm1/include/linux/tomoyo_socket.h
@@ -0,0 +1,419 @@
+/*
+ * include/linux/tomoyo_socket.h
+ *
+ * Implementation of the Domain-Based Mandatory Access Control.
+ *
+ * Copyright (C) 2005-2008 NTT DATA CORPORATION
+ *
+ * Version: 1.6.0 2008/04/01
+ *
+ */
+
+#ifndef _LINUX_TOMOYO_SOCKET_H
+#define _LINUX_TOMOYO_SOCKET_H
+
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/udp.h>
+#include <linux/uaccess.h>
+
+#if defined(CONFIG_TOMOYO)
+
+#define false 0
+#define true 1
+
+#define MAX_SOCK_ADDR 128 /* net/socket.c */
+
+/* Check permission for creating a socket. */
+static inline int ccs_socket_create_permission(int family, int type,
+ int protocol)
+{
+ int error = 0;
+ /* Nothing to do if I am a kernel service. */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return 0;
+ if (family == PF_PACKET && !ccs_capable(TOMOYO_USE_PACKET_SOCKET))
+ return -EPERM;
+ if (family == PF_ROUTE && !ccs_capable(TOMOYO_USE_ROUTE_SOCKET))
+ return -EPERM;
+ if (family != PF_INET && family != PF_INET6)
+ return 0;
+ switch (type) {
+ case SOCK_STREAM:
+ if (!ccs_capable(TOMOYO_INET_STREAM_SOCKET_CREATE))
+ error = -EPERM;
+ break;
+ case SOCK_DGRAM:
+ if (!ccs_capable(TOMOYO_USE_INET_DGRAM_SOCKET))
+ error = -EPERM;
+ break;
+ case SOCK_RAW:
+ if (!ccs_capable(TOMOYO_USE_INET_RAW_SOCKET))
+ error = -EPERM;
+ break;
+ }
+ return error;
+}
+
+/* Check permission for listening a TCP socket. */
+static inline int ccs_socket_listen_permission(struct socket *sock)
+{
+ int error = 0;
+ char addr[MAX_SOCK_ADDR];
+ int addr_len;
+ /* Nothing to do if I am a kernel service. */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return 0;
+ if (sock->type != SOCK_STREAM)
+ return 0;
+ switch (sock->sk->sk_family) {
+ case PF_INET:
+ case PF_INET6:
+ break;
+ default:
+ return 0;
+ }
+ if (!ccs_capable(TOMOYO_INET_STREAM_SOCKET_LISTEN))
+ return -EPERM;
+ if (sock->ops->getname(sock, (struct sockaddr *) addr, &addr_len, 0))
+ return -EPERM;
+ switch (((struct sockaddr *) addr)->sa_family) {
+ struct sockaddr_in6 *addr6;
+ struct sockaddr_in *addr4;
+ case AF_INET6:
+ addr6 = (struct sockaddr_in6 *) addr;
+ error = ccs_check_network_listen_acl(true,
+ addr6->sin6_addr.s6_addr,
+ addr6->sin6_port);
+ break;
+ case AF_INET:
+ addr4 = (struct sockaddr_in *) addr;
+ error = ccs_check_network_listen_acl(false,
+ (u8 *) &addr4->sin_addr,
+ addr4->sin_port);
+ break;
+ }
+ return error;
+}
+
+/* Check permission for setting the remote IP address/port pair of a socket. */
+static inline int ccs_socket_connect_permission(struct socket *sock,
+ struct sockaddr *addr,
+ int addr_len)
+{
+ int error = 0;
+ const unsigned int type = sock->type;
+ /* Nothing to do if I am a kernel service. */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return 0;
+ switch (type) {
+ case SOCK_STREAM:
+ case SOCK_DGRAM:
+ case SOCK_RAW:
+ break;
+ default:
+ return 0;
+ }
+ switch (addr->sa_family) {
+ struct sockaddr_in6 *addr6;
+ struct sockaddr_in *addr4;
+ u16 port;
+ case AF_INET6:
+ if (addr_len < SIN6_LEN_RFC2133)
+ break;
+ addr6 = (struct sockaddr_in6 *) addr;
+ if (type != SOCK_RAW)
+ port = addr6->sin6_port;
+ else
+ port = htons(sock->sk->sk_protocol);
+ error = ccs_check_network_connect_acl(true, type,
+ addr6->sin6_addr.s6_addr,
+ port);
+ break;
+ case AF_INET:
+ if (addr_len < sizeof(struct sockaddr_in))
+ break;
+ addr4 = (struct sockaddr_in *) addr;
+ if (type != SOCK_RAW)
+ port = addr4->sin_port;
+ else
+ port = htons(sock->sk->sk_protocol);
+ error = ccs_check_network_connect_acl(false, type,
+ (u8 *) &addr4->sin_addr,
+ port);
+ break;
+ }
+ if (type != SOCK_STREAM)
+ return error;
+ switch (sock->sk->sk_family) {
+ case PF_INET:
+ case PF_INET6:
+ if (!ccs_capable(TOMOYO_INET_STREAM_SOCKET_CONNECT))
+ error = -EPERM;
+ break;
+ }
+ return error;
+}
+
+/* Check permission for setting the local IP address/port pair of a socket. */
+static inline int ccs_socket_bind_permission(struct socket *sock,
+ struct sockaddr *addr,
+ int addr_len)
+{
+ int error = 0;
+ const unsigned int type = sock->type;
+ /* Nothing to do if I am a kernel service. */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return 0;
+ switch (type) {
+ case SOCK_STREAM:
+ case SOCK_DGRAM:
+ case SOCK_RAW:
+ break;
+ default:
+ return 0;
+ }
+ switch (addr->sa_family) {
+ struct sockaddr_in6 *addr6;
+ struct sockaddr_in *addr4;
+ u16 port;
+ case AF_INET6:
+ if (addr_len < SIN6_LEN_RFC2133)
+ break;
+ addr6 = (struct sockaddr_in6 *) addr;
+ if (type != SOCK_RAW)
+ port = addr6->sin6_port;
+ else
+ port = htons(sock->sk->sk_protocol);
+ error = ccs_check_network_bind_acl(true, type,
+ addr6->sin6_addr.s6_addr,
+ port);
+ break;
+ case AF_INET:
+ if (addr_len < sizeof(struct sockaddr_in))
+ break;
+ addr4 = (struct sockaddr_in *) addr;
+ if (type != SOCK_RAW)
+ port = addr4->sin_port;
+ else
+ port = htons(sock->sk->sk_protocol);
+ error = ccs_check_network_bind_acl(false, type,
+ (u8 *) &addr4->sin_addr,
+ port);
+ break;
+ }
+ return error;
+}
+
+/*
+ * Check permission for accepting a TCP socket.
+ *
+ * Currently, the LSM hook for this purpose is not provided.
+ */
+static inline int ccs_socket_accept_permission(struct socket *sock,
+ struct sockaddr *addr)
+{
+ int error = 0;
+ int addr_len;
+ /* Nothing to do if I am a kernel service. */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return 0;
+ switch (sock->sk->sk_family) {
+ case PF_INET:
+ case PF_INET6:
+ break;
+ default:
+ return 0;
+ }
+ error = sock->ops->getname(sock, addr, &addr_len, 2);
+ if (error)
+ return error;
+ switch (addr->sa_family) {
+ struct sockaddr_in6 *addr6;
+ struct sockaddr_in *addr4;
+ case AF_INET6:
+ addr6 = (struct sockaddr_in6 *) addr;
+ error = ccs_check_network_accept_acl(true,
+ addr6->sin6_addr.s6_addr,
+ addr6->sin6_port);
+ break;
+ case AF_INET:
+ addr4 = (struct sockaddr_in *) addr;
+ error = ccs_check_network_accept_acl(false,
+ (u8 *) &addr4->sin_addr,
+ addr4->sin_port);
+ break;
+ }
+ return error;
+}
+
+/* Check permission for sending a datagram via a UDP or RAW socket. */
+static inline int ccs_socket_sendmsg_permission(struct socket *sock,
+ struct sockaddr *addr,
+ int addr_len)
+{
+ int error = 0;
+ const int type = sock->type;
+ /* Nothing to do if I am a kernel service. */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return 0;
+ if (!addr || (type != SOCK_DGRAM && type != SOCK_RAW))
+ return 0;
+ switch (addr->sa_family) {
+ struct sockaddr_in6 *addr6;
+ struct sockaddr_in *addr4;
+ u16 port;
+ case AF_INET6:
+ if (addr_len < SIN6_LEN_RFC2133)
+ break;
+ addr6 = (struct sockaddr_in6 *) addr;
+ if (type == SOCK_DGRAM)
+ port = addr6->sin6_port;
+ else
+ port = htons(sock->sk->sk_protocol);
+ error = ccs_check_network_sendmsg_acl(true, type,
+ addr6->sin6_addr.s6_addr,
+ port);
+ break;
+ case AF_INET:
+ if (addr_len < sizeof(struct sockaddr_in))
+ break;
+ addr4 = (struct sockaddr_in *) addr;
+ if (type == SOCK_DGRAM)
+ port = addr4->sin_port;
+ else
+ port = htons(sock->sk->sk_protocol);
+ error = ccs_check_network_sendmsg_acl(false, type,
+ (u8 *) &addr4->sin_addr,
+ port);
+ break;
+ }
+ return error;
+}
+
+/*
+ * Check permission for receiving a datagram via a UDP or RAW socket.
+ *
+ * Currently, the LSM hook for this purpose is not provided.
+ */
+static inline int ccs_socket_recv_datagram_permission(struct sock *sk,
+ struct sk_buff *skb,
+ const unsigned int flags)
+{
+ int error = 0;
+ const unsigned int type = sk->sk_type;
+ /* Nothing to do if I didn't receive a datagram. */
+ if (!skb)
+ return 0;
+ /* Nothing to do if I can't sleep. */
+ if (in_atomic())
+ return 0;
+ /* Nothing to do if I am a kernel service. */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return 0;
+ if (type != SOCK_DGRAM && type != SOCK_RAW)
+ return 0;
+
+ switch (sk->sk_family) {
+ struct in6_addr sin6;
+ struct in_addr sin4;
+ u16 port;
+ case PF_INET6:
+ if (type == SOCK_DGRAM) { /* UDP IPv6 */
+ if (skb->protocol == htons(ETH_P_IP)) {
+ ipv6_addr_set(&sin6, 0, 0, htonl(0xffff),
+ ip_hdr(skb)->saddr);
+ } else {
+ ipv6_addr_copy(&sin6, &ipv6_hdr(skb)->saddr);
+ }
+ port = udp_hdr(skb)->source;
+ } else { /* RAW IPv6 */
+ ipv6_addr_copy(&sin6, &ipv6_hdr(skb)->saddr);
+ port = htons(sk->sk_protocol);
+ }
+ error = ccs_check_network_recvmsg_acl(true, type,
+ (u8 *) &sin6, port);
+ break;
+ case PF_INET:
+ if (type == SOCK_DGRAM) { /* UDP IPv4 */
+ sin4.s_addr = ip_hdr(skb)->saddr;
+ port = udp_hdr(skb)->source;
+ } else { /* RAW IPv4 */
+ sin4.s_addr = ip_hdr(skb)->saddr;
+ port = htons(sk->sk_protocol);
+ }
+ error = ccs_check_network_recvmsg_acl(false, type,
+ (u8 *) &sin4, port);
+ break;
+ }
+ if (!error)
+ return 0;
+ lock_sock(sk);
+ /*
+ * Remove from queue if MSG_PEEK is used so that
+ * the head message from unwanted source in receive queue will not
+ * prevent the caller from picking up next message from wanted source
+ * when the caller is using MSG_PEEK flag for picking up.
+ */
+ if (flags & MSG_PEEK) {
+ unsigned long cpu_flags;
+ /***** CRITICAL SECTION START *****/
+ spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags);
+ if (skb == skb_peek(&sk->sk_receive_queue)) {
+ __skb_unlink(skb, &sk->sk_receive_queue);
+ atomic_dec(&skb->users);
+ }
+ spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags);
+ /***** CRITICAL SECTION END *****/
+ }
+ /* Drop reference count. */
+ skb_free_datagram(sk, skb);
+ release_sock(sk);
+ /* Hope less harmful than -EPERM. */
+ return -EAGAIN;
+}
+
+#else
+
+static inline int ccs_socket_create_permission(int family, int type,
+ int protocol)
+{
+ return 0;
+}
+static inline int ccs_socket_listen_permission(struct socket *sock)
+{
+ return 0;
+}
+static inline int ccs_socket_connect_permission(struct socket *sock,
+ struct sockaddr *addr,
+ int addr_len)
+{
+ return 0;
+}
+static inline int ccs_socket_bind_permission(struct socket *sock,
+ struct sockaddr *addr,
+ int addr_len)
+{
+ return 0;
+}
+static inline int ccs_socket_accept_permission(struct socket *sock,
+ struct sockaddr *addr)
+{
+ return 0;
+}
+static inline int ccs_socket_sendmsg_permission(struct socket *sock,
+ struct sockaddr *addr,
+ int addr_len)
+{
+ return 0;
+}
+static inline int ccs_socket_recv_datagram_permission(struct sock *sk,
+ struct sk_buff *skb,
+ const unsigned int flags)
+{
+ return 0;
+}
+
+#endif
+
+#endif
--
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
| Karl Meyer | PROBLEM: 2.6.23-rc "NETDEV WATCHDOG: eth0: transmit timed out" |
| Greg Kroah-Hartman | [PATCH 040/196] kobject: add kobject_add_ng function |
| Steven Rostedt | [RFC PATCH v4] Unified trace buffer |
| Dave Airlie | [git pull] drm patches for 2.6.27 final |
| Krzysztof Halasa | Re: [PATCH v2] Re: WAN: new PPP code for generic HDLC |
| David Miller | Re: [PATCH] Expose netdevice dev_id through sysfs |
| Jay Cliburn | Re: atl1 64-bit => 32-bit DMA borkage (reproducible, bisected) |
| Evgeniy Polyakov | [resend take 2 0/4] Distributed storage. |
git: | |
| Andrew Morton | Untracked working tree files |
| Miklos Vajna | [rfc] git submodules howto |
| Ben Collins | Re: [kernel.org users] [RFD] On deprecating "git-foo" for builtins |
| Jon Smirl | ! [rejected] master -> master (non-fast forward) |
| rancor | How to copy/pipe console buffert to file? |
| Pieter Verberne | File collision while using pkg_add |
| Greg Thomas | Re: Is it possible to fix a stale NFS hadle without rebooting? |
| Didier Wiroth | win32-codecs, avi and amd64 question |
| Netfilter kernel module | 9 hours ago | Linux kernel |
| serial driver xmit problem | 12 hours ago | Linux kernel |
| Why Windows is better than Linux | 12 hours ago | Linux general |
| How can I see my kernel messages in vt12? | 19 hours ago | Linux kernel |
| Grub | 1 day ago | Linux general |
| vmalloc_fault handling in x86_64 | 1 day ago | Linux kernel |
| epoll_wait()ing on epoll FD | 1 day ago | Linux kernel |
| Framebuffer in x86_64 causes problems to multiseat | 1 day ago | Linux kernel |
| Difference between 2.4 and 2.6 regarding thread creation | 1 day ago | Linux general |
| Compiling gfs2 on kernel 2.6.27 | 2 days ago | Linux kernel |
