1 |
/* |
2 |
* include/linux/tomoyo_socket.h |
3 |
* |
4 |
* Implementation of the Domain-Based Mandatory Access Control. |
5 |
* |
6 |
* Copyright (C) 2005-2007 NTT DATA CORPORATION |
7 |
* |
8 |
* Version: 1.5.3-pre 2007/12/03 |
9 |
* |
10 |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
11 |
* See README.ccs for ChangeLog. |
12 |
* |
13 |
*/ |
14 |
|
15 |
#ifndef _LINUX_TOMOYO_SOCKET_H |
16 |
#define _LINUX_TOMOYO_SOCKET_H |
17 |
|
18 |
/***** TOMOYO Linux start. *****/ |
19 |
|
20 |
#if defined(CONFIG_TOMOYO) |
21 |
|
22 |
#include <net/ip.h> |
23 |
#include <net/ipv6.h> |
24 |
#include <net/udp.h> |
25 |
#include <asm/uaccess.h> |
26 |
|
27 |
#include <linux/version.h> |
28 |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) |
29 |
#define sk_family family |
30 |
#define sk_protocol protocol |
31 |
#define sk_type type |
32 |
#define sk_receive_queue receive_queue |
33 |
#endif |
34 |
|
35 |
#define MAX_SOCK_ADDR 128 /* net/socket.c */ |
36 |
|
37 |
static inline int CheckSocketCreatePermission(int family, int type, int protocol) |
38 |
{ |
39 |
int error = 0; |
40 |
if (segment_eq(get_fs(), KERNEL_DS)) return 0; |
41 |
if (family == PF_INET || family == PF_INET6) { |
42 |
switch (type) { |
43 |
case SOCK_STREAM: |
44 |
error = CheckCapabilityACL(TOMOYO_INET_STREAM_SOCKET_CREATE); |
45 |
break; |
46 |
case SOCK_DGRAM: |
47 |
error = CheckCapabilityACL(TOMOYO_USE_INET_DGRAM_SOCKET); |
48 |
break; |
49 |
case SOCK_RAW: |
50 |
error = CheckCapabilityACL(TOMOYO_USE_INET_RAW_SOCKET); |
51 |
break; |
52 |
} |
53 |
} else if (family == PF_PACKET) { |
54 |
error = CheckCapabilityACL(TOMOYO_USE_PACKET_SOCKET); |
55 |
} else if (family == PF_ROUTE) { |
56 |
error = CheckCapabilityACL(TOMOYO_USE_ROUTE_SOCKET); |
57 |
} |
58 |
return error; |
59 |
} |
60 |
|
61 |
static inline int CheckSocketListenPermission(struct socket *sock) |
62 |
{ |
63 |
int error = 0; |
64 |
if (segment_eq(get_fs(), KERNEL_DS)) return 0; |
65 |
if (sock->type == SOCK_STREAM) { |
66 |
switch (sock->sk->sk_family) { |
67 |
case PF_INET: |
68 |
case PF_INET6: |
69 |
error = CheckCapabilityACL(TOMOYO_INET_STREAM_SOCKET_LISTEN); |
70 |
if (!error) { |
71 |
char addr[MAX_SOCK_ADDR]; |
72 |
int addr_len; |
73 |
if (sock->ops->getname(sock, (struct sockaddr *) addr, &addr_len, 0) == 0) { |
74 |
switch (((struct sockaddr *) addr)->sa_family) { |
75 |
case AF_INET6: |
76 |
error = CheckNetworkListenACL(1, ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr, ((struct sockaddr_in6 *) addr)->sin6_port); |
77 |
break; |
78 |
case AF_INET: |
79 |
error = CheckNetworkListenACL(0, (u8 *) &((struct sockaddr_in *) addr)->sin_addr, ((struct sockaddr_in *) addr)->sin_port); |
80 |
break; |
81 |
} |
82 |
} else { |
83 |
error = -EPERM; |
84 |
} |
85 |
} |
86 |
break; |
87 |
} |
88 |
} |
89 |
return error; |
90 |
} |
91 |
|
92 |
static inline int CheckSocketConnectPermission(struct socket *sock, struct sockaddr *addr, int addr_len) |
93 |
{ |
94 |
int error = 0; |
95 |
const unsigned int type = sock->type; |
96 |
if (segment_eq(get_fs(), KERNEL_DS)) return 0; |
97 |
if (type == SOCK_STREAM || type == SOCK_DGRAM || type == SOCK_RAW) { |
98 |
switch (addr->sa_family) { |
99 |
case AF_INET6: |
100 |
if (addr_len >= SIN6_LEN_RFC2133) { |
101 |
if (type != SOCK_RAW) { |
102 |
error = CheckNetworkConnectACL(1, type, ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr, ((struct sockaddr_in6 *) addr)->sin6_port); |
103 |
} else { |
104 |
error = CheckNetworkConnectACL(1, SOCK_RAW, ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr, htons(sock->sk->sk_protocol)); |
105 |
} |
106 |
} |
107 |
break; |
108 |
case AF_INET: |
109 |
if (addr_len >= sizeof(struct sockaddr_in)) { |
110 |
if (type != SOCK_RAW) { |
111 |
error = CheckNetworkConnectACL(0, type, (u8 *) &((struct sockaddr_in *) addr)->sin_addr, ((struct sockaddr_in *) addr)->sin_port); |
112 |
} else { |
113 |
error = CheckNetworkConnectACL(0, SOCK_RAW, (u8 *) &((struct sockaddr_in *) addr)->sin_addr, htons(sock->sk->sk_protocol)); |
114 |
} |
115 |
} |
116 |
break; |
117 |
} |
118 |
} |
119 |
if (type == SOCK_STREAM) { |
120 |
switch (sock->sk->sk_family) { |
121 |
case PF_INET: |
122 |
case PF_INET6: |
123 |
error = CheckCapabilityACL(TOMOYO_INET_STREAM_SOCKET_CONNECT) ? -EPERM : error; |
124 |
break; |
125 |
} |
126 |
} |
127 |
return error; |
128 |
} |
129 |
|
130 |
static inline int CheckSocketBindPermission(struct socket *sock, struct sockaddr *addr, int addr_len) |
131 |
{ |
132 |
int error = 0; |
133 |
const unsigned int type = sock->type; |
134 |
if (segment_eq(get_fs(), KERNEL_DS)) return 0; |
135 |
if (type == SOCK_STREAM || type == SOCK_DGRAM || type == SOCK_RAW) { |
136 |
switch (addr->sa_family) { |
137 |
case AF_INET6: |
138 |
if (addr_len >= SIN6_LEN_RFC2133) { |
139 |
if (type != SOCK_RAW) { |
140 |
error = CheckNetworkBindACL(1, type, ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr, ((struct sockaddr_in6 *) addr)->sin6_port); |
141 |
} else { |
142 |
error = CheckNetworkBindACL(1, SOCK_RAW, ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr, htons(sock->sk->sk_protocol)); |
143 |
} |
144 |
} |
145 |
break; |
146 |
case AF_INET: |
147 |
if (addr_len >= sizeof(struct sockaddr_in)) { |
148 |
if (type != SOCK_RAW) { |
149 |
error = CheckNetworkBindACL(0, type, (u8 *) &((struct sockaddr_in *) addr)->sin_addr, ((struct sockaddr_in *) addr)->sin_port); |
150 |
} else { |
151 |
error = CheckNetworkBindACL(0, SOCK_RAW, (u8 *) &((struct sockaddr_in *) addr)->sin_addr, htons(sock->sk->sk_protocol)); |
152 |
} |
153 |
} |
154 |
break; |
155 |
} |
156 |
} |
157 |
return error; |
158 |
} |
159 |
|
160 |
static inline int CheckSocketAcceptPermission(struct socket *sock, struct sockaddr *addr) |
161 |
{ |
162 |
int error = 0; |
163 |
int addr_len; |
164 |
if (segment_eq(get_fs(), KERNEL_DS)) return 0; |
165 |
switch (sock->sk->sk_family) { |
166 |
case PF_INET: |
167 |
case PF_INET6: |
168 |
if (sock->ops->getname(sock, addr, &addr_len, 2) == 0) { |
169 |
switch (addr->sa_family) { |
170 |
case AF_INET6: |
171 |
error = CheckNetworkAcceptACL(1, ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr, ((struct sockaddr_in6 *) addr)->sin6_port); |
172 |
break; |
173 |
case AF_INET: |
174 |
error = CheckNetworkAcceptACL(0, (u8 *) &((struct sockaddr_in *) addr)->sin_addr, ((struct sockaddr_in *) addr)->sin_port); |
175 |
break; |
176 |
} |
177 |
} else { |
178 |
error = -EPERM; |
179 |
} |
180 |
} |
181 |
return error; |
182 |
} |
183 |
|
184 |
static inline int CheckSocketSendMsgPermission(struct socket *sock, struct sockaddr *addr, int addr_len) |
185 |
{ |
186 |
int error = 0; |
187 |
const int type = sock->type; |
188 |
if (segment_eq(get_fs(), KERNEL_DS)) return 0; |
189 |
if (addr && (type == SOCK_DGRAM || type == SOCK_RAW)) { |
190 |
switch (addr->sa_family) { |
191 |
case AF_INET6: |
192 |
if (addr_len >= SIN6_LEN_RFC2133) { |
193 |
error = CheckNetworkSendMsgACL(1, type, ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr, type == SOCK_DGRAM ? ((struct sockaddr_in6 *) addr)->sin6_port : htons(sock->sk->sk_protocol)); |
194 |
} |
195 |
break; |
196 |
case AF_INET: |
197 |
if (addr_len >= sizeof(struct sockaddr_in)) { |
198 |
error = CheckNetworkSendMsgACL(0, type, (u8 *) &((struct sockaddr_in *) addr)->sin_addr, type == SOCK_DGRAM ? ((struct sockaddr_in *) addr)->sin_port : htons(sock->sk->sk_protocol)); |
199 |
} |
200 |
break; |
201 |
} |
202 |
} |
203 |
return error; |
204 |
} |
205 |
|
206 |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) |
207 |
|
208 |
static inline struct iphdr *ip_hdr(const struct sk_buff *skb) |
209 |
{ |
210 |
return skb->nh.iph; |
211 |
} |
212 |
|
213 |
static inline struct udphdr *udp_hdr(const struct sk_buff *skb) |
214 |
{ |
215 |
return skb->h.uh; |
216 |
} |
217 |
|
218 |
static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb) |
219 |
{ |
220 |
return skb->nh.ipv6h; |
221 |
} |
222 |
|
223 |
#endif |
224 |
|
225 |
static inline int CheckSocketRecvDatagramPermission(struct sock *sk, struct sk_buff *skb, const unsigned int flags) |
226 |
{ |
227 |
int error = 0; |
228 |
const unsigned int type = sk->sk_type; |
229 |
struct in6_addr sin6; |
230 |
struct in_addr sin; |
231 |
u16 port; |
232 |
|
233 |
if (!skb) return 0; |
234 |
|
235 |
if (in_interrupt()) return 0; |
236 |
|
237 |
if (segment_eq(get_fs(), KERNEL_DS)) return 0; |
238 |
|
239 |
if (type != SOCK_DGRAM && type != SOCK_RAW) return 0; |
240 |
|
241 |
switch (sk->sk_family) { |
242 |
case PF_INET6: |
243 |
if (type == SOCK_DGRAM) { /* UDP IPv6 */ |
244 |
if (skb->protocol == htons(ETH_P_IP)) { |
245 |
ipv6_addr_set(&sin6, 0, 0, htonl(0xffff), ip_hdr(skb)->saddr); |
246 |
} else { |
247 |
ipv6_addr_copy(&sin6, &ipv6_hdr(skb)->saddr); |
248 |
} |
249 |
port = udp_hdr(skb)->source; |
250 |
} else { /* RAW IPv6 */ |
251 |
ipv6_addr_copy(&sin6, &ipv6_hdr(skb)->saddr); |
252 |
port = htons(sk->sk_protocol); |
253 |
} |
254 |
error = CheckNetworkRecvMsgACL(1, type, (u8 *) &sin6, port); |
255 |
break; |
256 |
case PF_INET: |
257 |
if (type == SOCK_DGRAM) { /* UDP IPv4 */ |
258 |
sin.s_addr = ip_hdr(skb)->saddr; |
259 |
port = udp_hdr(skb)->source; |
260 |
} else { /* RAW IPv4 */ |
261 |
sin.s_addr = ip_hdr(skb)->saddr; |
262 |
port = htons(sk->sk_protocol); |
263 |
} |
264 |
error = CheckNetworkRecvMsgACL(0, type, (u8 *) &sin, port); |
265 |
break; |
266 |
} |
267 |
if (error) { |
268 |
/* |
269 |
* Remove from queue if MSG_PEEK is used so that |
270 |
* the head message from unwanted source in receive queue will not |
271 |
* prevent the caller from picking up next message from wanted source |
272 |
* when the caller is using MSG_PEEK flag for picking up. |
273 |
*/ |
274 |
if (flags & MSG_PEEK) { |
275 |
unsigned long cpu_flags; |
276 |
spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags); |
277 |
if (skb == skb_peek(&sk->sk_receive_queue)) { |
278 |
__skb_unlink(skb, &sk->sk_receive_queue); |
279 |
atomic_dec(&skb->users); |
280 |
} |
281 |
spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags); |
282 |
} |
283 |
/* Drop reference count. */ |
284 |
skb_free_datagram(sk, skb); |
285 |
/* Hope less harmful than -EPERM. */ |
286 |
error = -EAGAIN; |
287 |
} |
288 |
return error; |
289 |
} |
290 |
|
291 |
#else |
292 |
|
293 |
static inline int CheckSocketCreatePermission(int family, int type, int protocol) { return 0; } |
294 |
static inline int CheckSocketListenPermission(struct socket *sock) { return 0; } |
295 |
static inline int CheckSocketConnectPermission(struct socket *sock, struct sockaddr *addr, int addr_len) { return 0; } |
296 |
static inline int CheckSocketBindPermission(struct socket *sock, struct sockaddr *addr, int addr_len) { return 0; } |
297 |
static inline int CheckSocketAcceptPermission(struct socket *sock, struct sockaddr *addr) { return 0; } |
298 |
static inline int CheckSocketSendMsgPermission(struct socket *sock, struct sockaddr *addr, int addr_len) { return 0; } |
299 |
static inline int CheckSocketRecvDatagramPermission(struct sock *sk, struct sk_buff *skb, const unsigned int flags) { return 0; } |
300 |
|
301 |
#endif |
302 |
|
303 |
/***** TOMOYO Linux end. *****/ |
304 |
#endif |