]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
059d84db TH |
2 | /* |
3 | * security/tomoyo/network.c | |
4 | * | |
5 | * Copyright (C) 2005-2011 NTT DATA CORPORATION | |
6 | */ | |
7 | ||
8 | #include "common.h" | |
9 | #include <linux/slab.h> | |
10 | ||
11 | /* Structure for holding inet domain socket's address. */ | |
12 | struct tomoyo_inet_addr_info { | |
13 | __be16 port; /* In network byte order. */ | |
14 | const __be32 *address; /* In network byte order. */ | |
15 | bool is_ipv6; | |
16 | }; | |
17 | ||
18 | /* Structure for holding unix domain socket's address. */ | |
19 | struct tomoyo_unix_addr_info { | |
20 | u8 *addr; /* This may not be '\0' terminated string. */ | |
21 | unsigned int addr_len; | |
22 | }; | |
23 | ||
24 | /* Structure for holding socket address. */ | |
25 | struct tomoyo_addr_info { | |
26 | u8 protocol; | |
27 | u8 operation; | |
28 | struct tomoyo_inet_addr_info inet; | |
29 | struct tomoyo_unix_addr_info unix0; | |
30 | }; | |
31 | ||
32 | /* String table for socket's protocols. */ | |
33 | const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX] = { | |
34 | [SOCK_STREAM] = "stream", | |
35 | [SOCK_DGRAM] = "dgram", | |
36 | [SOCK_RAW] = "raw", | |
37 | [SOCK_SEQPACKET] = "seqpacket", | |
38 | [0] = " ", /* Dummy for avoiding NULL pointer dereference. */ | |
39 | [4] = " ", /* Dummy for avoiding NULL pointer dereference. */ | |
40 | }; | |
41 | ||
42 | /** | |
43 | * tomoyo_parse_ipaddr_union - Parse an IP address. | |
44 | * | |
45 | * @param: Pointer to "struct tomoyo_acl_param". | |
46 | * @ptr: Pointer to "struct tomoyo_ipaddr_union". | |
47 | * | |
48 | * Returns true on success, false otherwise. | |
49 | */ | |
50 | bool tomoyo_parse_ipaddr_union(struct tomoyo_acl_param *param, | |
51 | struct tomoyo_ipaddr_union *ptr) | |
52 | { | |
53 | u8 * const min = ptr->ip[0].in6_u.u6_addr8; | |
54 | u8 * const max = ptr->ip[1].in6_u.u6_addr8; | |
55 | char *address = tomoyo_read_token(param); | |
56 | const char *end; | |
57 | ||
58 | if (!strchr(address, ':') && | |
59 | in4_pton(address, -1, min, '-', &end) > 0) { | |
60 | ptr->is_ipv6 = false; | |
61 | if (!*end) | |
62 | ptr->ip[1].s6_addr32[0] = ptr->ip[0].s6_addr32[0]; | |
63 | else if (*end++ != '-' || | |
64 | in4_pton(end, -1, max, '\0', &end) <= 0 || *end) | |
65 | return false; | |
66 | return true; | |
67 | } | |
68 | if (in6_pton(address, -1, min, '-', &end) > 0) { | |
69 | ptr->is_ipv6 = true; | |
70 | if (!*end) | |
71 | memmove(max, min, sizeof(u16) * 8); | |
72 | else if (*end++ != '-' || | |
73 | in6_pton(end, -1, max, '\0', &end) <= 0 || *end) | |
74 | return false; | |
75 | return true; | |
76 | } | |
77 | return false; | |
78 | } | |
79 | ||
80 | /** | |
81 | * tomoyo_print_ipv4 - Print an IPv4 address. | |
82 | * | |
83 | * @buffer: Buffer to write to. | |
84 | * @buffer_len: Size of @buffer. | |
85 | * @min_ip: Pointer to __be32. | |
86 | * @max_ip: Pointer to __be32. | |
87 | * | |
88 | * Returns nothing. | |
89 | */ | |
90 | static void tomoyo_print_ipv4(char *buffer, const unsigned int buffer_len, | |
91 | const __be32 *min_ip, const __be32 *max_ip) | |
92 | { | |
93 | snprintf(buffer, buffer_len, "%pI4%c%pI4", min_ip, | |
94 | *min_ip == *max_ip ? '\0' : '-', max_ip); | |
95 | } | |
96 | ||
97 | /** | |
98 | * tomoyo_print_ipv6 - Print an IPv6 address. | |
99 | * | |
100 | * @buffer: Buffer to write to. | |
101 | * @buffer_len: Size of @buffer. | |
102 | * @min_ip: Pointer to "struct in6_addr". | |
103 | * @max_ip: Pointer to "struct in6_addr". | |
104 | * | |
105 | * Returns nothing. | |
106 | */ | |
107 | static void tomoyo_print_ipv6(char *buffer, const unsigned int buffer_len, | |
108 | const struct in6_addr *min_ip, | |
109 | const struct in6_addr *max_ip) | |
110 | { | |
111 | snprintf(buffer, buffer_len, "%pI6c%c%pI6c", min_ip, | |
112 | !memcmp(min_ip, max_ip, 16) ? '\0' : '-', max_ip); | |
113 | } | |
114 | ||
115 | /** | |
116 | * tomoyo_print_ip - Print an IP address. | |
117 | * | |
118 | * @buf: Buffer to write to. | |
119 | * @size: Size of @buf. | |
120 | * @ptr: Pointer to "struct ipaddr_union". | |
121 | * | |
122 | * Returns nothing. | |
123 | */ | |
124 | void tomoyo_print_ip(char *buf, const unsigned int size, | |
125 | const struct tomoyo_ipaddr_union *ptr) | |
126 | { | |
127 | if (ptr->is_ipv6) | |
128 | tomoyo_print_ipv6(buf, size, &ptr->ip[0], &ptr->ip[1]); | |
129 | else | |
130 | tomoyo_print_ipv4(buf, size, &ptr->ip[0].s6_addr32[0], | |
131 | &ptr->ip[1].s6_addr32[0]); | |
132 | } | |
133 | ||
134 | /* | |
135 | * Mapping table from "enum tomoyo_network_acl_index" to | |
136 | * "enum tomoyo_mac_index" for inet domain socket. | |
137 | */ | |
138 | static const u8 tomoyo_inet2mac | |
139 | [TOMOYO_SOCK_MAX][TOMOYO_MAX_NETWORK_OPERATION] = { | |
140 | [SOCK_STREAM] = { | |
141 | [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_STREAM_BIND, | |
142 | [TOMOYO_NETWORK_LISTEN] = | |
143 | TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN, | |
144 | [TOMOYO_NETWORK_CONNECT] = | |
145 | TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT, | |
146 | }, | |
147 | [SOCK_DGRAM] = { | |
148 | [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_DGRAM_BIND, | |
149 | [TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_INET_DGRAM_SEND, | |
150 | }, | |
151 | [SOCK_RAW] = { | |
152 | [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_RAW_BIND, | |
153 | [TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_INET_RAW_SEND, | |
154 | }, | |
155 | }; | |
156 | ||
157 | /* | |
158 | * Mapping table from "enum tomoyo_network_acl_index" to | |
159 | * "enum tomoyo_mac_index" for unix domain socket. | |
160 | */ | |
161 | static const u8 tomoyo_unix2mac | |
162 | [TOMOYO_SOCK_MAX][TOMOYO_MAX_NETWORK_OPERATION] = { | |
163 | [SOCK_STREAM] = { | |
164 | [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND, | |
165 | [TOMOYO_NETWORK_LISTEN] = | |
166 | TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN, | |
167 | [TOMOYO_NETWORK_CONNECT] = | |
168 | TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT, | |
169 | }, | |
170 | [SOCK_DGRAM] = { | |
171 | [TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND, | |
172 | [TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND, | |
173 | }, | |
174 | [SOCK_SEQPACKET] = { | |
175 | [TOMOYO_NETWORK_BIND] = | |
176 | TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND, | |
177 | [TOMOYO_NETWORK_LISTEN] = | |
178 | TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN, | |
179 | [TOMOYO_NETWORK_CONNECT] = | |
180 | TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT, | |
181 | }, | |
182 | }; | |
183 | ||
184 | /** | |
185 | * tomoyo_same_inet_acl - Check for duplicated "struct tomoyo_inet_acl" entry. | |
186 | * | |
187 | * @a: Pointer to "struct tomoyo_acl_info". | |
188 | * @b: Pointer to "struct tomoyo_acl_info". | |
189 | * | |
190 | * Returns true if @a == @b except permission bits, false otherwise. | |
191 | */ | |
192 | static bool tomoyo_same_inet_acl(const struct tomoyo_acl_info *a, | |
193 | const struct tomoyo_acl_info *b) | |
194 | { | |
195 | const struct tomoyo_inet_acl *p1 = container_of(a, typeof(*p1), head); | |
196 | const struct tomoyo_inet_acl *p2 = container_of(b, typeof(*p2), head); | |
197 | ||
198 | return p1->protocol == p2->protocol && | |
199 | tomoyo_same_ipaddr_union(&p1->address, &p2->address) && | |
200 | tomoyo_same_number_union(&p1->port, &p2->port); | |
201 | } | |
202 | ||
203 | /** | |
204 | * tomoyo_same_unix_acl - Check for duplicated "struct tomoyo_unix_acl" entry. | |
205 | * | |
206 | * @a: Pointer to "struct tomoyo_acl_info". | |
207 | * @b: Pointer to "struct tomoyo_acl_info". | |
208 | * | |
209 | * Returns true if @a == @b except permission bits, false otherwise. | |
210 | */ | |
211 | static bool tomoyo_same_unix_acl(const struct tomoyo_acl_info *a, | |
212 | const struct tomoyo_acl_info *b) | |
213 | { | |
214 | const struct tomoyo_unix_acl *p1 = container_of(a, typeof(*p1), head); | |
215 | const struct tomoyo_unix_acl *p2 = container_of(b, typeof(*p2), head); | |
216 | ||
217 | return p1->protocol == p2->protocol && | |
218 | tomoyo_same_name_union(&p1->name, &p2->name); | |
219 | } | |
220 | ||
221 | /** | |
222 | * tomoyo_merge_inet_acl - Merge duplicated "struct tomoyo_inet_acl" entry. | |
223 | * | |
224 | * @a: Pointer to "struct tomoyo_acl_info". | |
225 | * @b: Pointer to "struct tomoyo_acl_info". | |
226 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | |
227 | * | |
228 | * Returns true if @a is empty, false otherwise. | |
229 | */ | |
230 | static bool tomoyo_merge_inet_acl(struct tomoyo_acl_info *a, | |
231 | struct tomoyo_acl_info *b, | |
232 | const bool is_delete) | |
233 | { | |
234 | u8 * const a_perm = | |
235 | &container_of(a, struct tomoyo_inet_acl, head)->perm; | |
5797e861 | 236 | u8 perm = READ_ONCE(*a_perm); |
059d84db TH |
237 | const u8 b_perm = container_of(b, struct tomoyo_inet_acl, head)->perm; |
238 | ||
239 | if (is_delete) | |
240 | perm &= ~b_perm; | |
241 | else | |
242 | perm |= b_perm; | |
5797e861 | 243 | WRITE_ONCE(*a_perm, perm); |
059d84db TH |
244 | return !perm; |
245 | } | |
246 | ||
247 | /** | |
248 | * tomoyo_merge_unix_acl - Merge duplicated "struct tomoyo_unix_acl" entry. | |
249 | * | |
250 | * @a: Pointer to "struct tomoyo_acl_info". | |
251 | * @b: Pointer to "struct tomoyo_acl_info". | |
252 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | |
253 | * | |
254 | * Returns true if @a is empty, false otherwise. | |
255 | */ | |
256 | static bool tomoyo_merge_unix_acl(struct tomoyo_acl_info *a, | |
257 | struct tomoyo_acl_info *b, | |
258 | const bool is_delete) | |
259 | { | |
260 | u8 * const a_perm = | |
261 | &container_of(a, struct tomoyo_unix_acl, head)->perm; | |
5797e861 | 262 | u8 perm = READ_ONCE(*a_perm); |
059d84db TH |
263 | const u8 b_perm = container_of(b, struct tomoyo_unix_acl, head)->perm; |
264 | ||
265 | if (is_delete) | |
266 | perm &= ~b_perm; | |
267 | else | |
268 | perm |= b_perm; | |
5797e861 | 269 | WRITE_ONCE(*a_perm, perm); |
059d84db TH |
270 | return !perm; |
271 | } | |
272 | ||
273 | /** | |
274 | * tomoyo_write_inet_network - Write "struct tomoyo_inet_acl" list. | |
275 | * | |
276 | * @param: Pointer to "struct tomoyo_acl_param". | |
277 | * | |
278 | * Returns 0 on success, negative value otherwise. | |
279 | * | |
280 | * Caller holds tomoyo_read_lock(). | |
281 | */ | |
282 | int tomoyo_write_inet_network(struct tomoyo_acl_param *param) | |
283 | { | |
284 | struct tomoyo_inet_acl e = { .head.type = TOMOYO_TYPE_INET_ACL }; | |
285 | int error = -EINVAL; | |
286 | u8 type; | |
287 | const char *protocol = tomoyo_read_token(param); | |
288 | const char *operation = tomoyo_read_token(param); | |
289 | ||
290 | for (e.protocol = 0; e.protocol < TOMOYO_SOCK_MAX; e.protocol++) | |
291 | if (!strcmp(protocol, tomoyo_proto_keyword[e.protocol])) | |
292 | break; | |
293 | for (type = 0; type < TOMOYO_MAX_NETWORK_OPERATION; type++) | |
294 | if (tomoyo_permstr(operation, tomoyo_socket_keyword[type])) | |
295 | e.perm |= 1 << type; | |
296 | if (e.protocol == TOMOYO_SOCK_MAX || !e.perm) | |
297 | return -EINVAL; | |
298 | if (param->data[0] == '@') { | |
299 | param->data++; | |
300 | e.address.group = | |
301 | tomoyo_get_group(param, TOMOYO_ADDRESS_GROUP); | |
302 | if (!e.address.group) | |
303 | return -ENOMEM; | |
304 | } else { | |
305 | if (!tomoyo_parse_ipaddr_union(param, &e.address)) | |
306 | goto out; | |
307 | } | |
308 | if (!tomoyo_parse_number_union(param, &e.port) || | |
309 | e.port.values[1] > 65535) | |
310 | goto out; | |
311 | error = tomoyo_update_domain(&e.head, sizeof(e), param, | |
312 | tomoyo_same_inet_acl, | |
313 | tomoyo_merge_inet_acl); | |
314 | out: | |
315 | tomoyo_put_group(e.address.group); | |
316 | tomoyo_put_number_union(&e.port); | |
317 | return error; | |
318 | } | |
319 | ||
320 | /** | |
321 | * tomoyo_write_unix_network - Write "struct tomoyo_unix_acl" list. | |
322 | * | |
323 | * @param: Pointer to "struct tomoyo_acl_param". | |
324 | * | |
325 | * Returns 0 on success, negative value otherwise. | |
326 | */ | |
327 | int tomoyo_write_unix_network(struct tomoyo_acl_param *param) | |
328 | { | |
329 | struct tomoyo_unix_acl e = { .head.type = TOMOYO_TYPE_UNIX_ACL }; | |
330 | int error; | |
331 | u8 type; | |
332 | const char *protocol = tomoyo_read_token(param); | |
333 | const char *operation = tomoyo_read_token(param); | |
334 | ||
335 | for (e.protocol = 0; e.protocol < TOMOYO_SOCK_MAX; e.protocol++) | |
336 | if (!strcmp(protocol, tomoyo_proto_keyword[e.protocol])) | |
337 | break; | |
338 | for (type = 0; type < TOMOYO_MAX_NETWORK_OPERATION; type++) | |
339 | if (tomoyo_permstr(operation, tomoyo_socket_keyword[type])) | |
340 | e.perm |= 1 << type; | |
341 | if (e.protocol == TOMOYO_SOCK_MAX || !e.perm) | |
342 | return -EINVAL; | |
343 | if (!tomoyo_parse_name_union(param, &e.name)) | |
344 | return -EINVAL; | |
345 | error = tomoyo_update_domain(&e.head, sizeof(e), param, | |
346 | tomoyo_same_unix_acl, | |
347 | tomoyo_merge_unix_acl); | |
348 | tomoyo_put_name_union(&e.name); | |
349 | return error; | |
350 | } | |
351 | ||
352 | /** | |
353 | * tomoyo_audit_net_log - Audit network log. | |
354 | * | |
355 | * @r: Pointer to "struct tomoyo_request_info". | |
356 | * @family: Name of socket family ("inet" or "unix"). | |
357 | * @protocol: Name of protocol in @family. | |
358 | * @operation: Name of socket operation. | |
359 | * @address: Name of address. | |
360 | * | |
361 | * Returns 0 on success, negative value otherwise. | |
362 | */ | |
363 | static int tomoyo_audit_net_log(struct tomoyo_request_info *r, | |
364 | const char *family, const u8 protocol, | |
365 | const u8 operation, const char *address) | |
366 | { | |
367 | return tomoyo_supervisor(r, "network %s %s %s %s\n", family, | |
368 | tomoyo_proto_keyword[protocol], | |
369 | tomoyo_socket_keyword[operation], address); | |
370 | } | |
371 | ||
372 | /** | |
373 | * tomoyo_audit_inet_log - Audit INET network log. | |
374 | * | |
375 | * @r: Pointer to "struct tomoyo_request_info". | |
376 | * | |
377 | * Returns 0 on success, negative value otherwise. | |
378 | */ | |
379 | static int tomoyo_audit_inet_log(struct tomoyo_request_info *r) | |
380 | { | |
381 | char buf[128]; | |
382 | int len; | |
383 | const __be32 *address = r->param.inet_network.address; | |
384 | ||
385 | if (r->param.inet_network.is_ipv6) | |
386 | tomoyo_print_ipv6(buf, sizeof(buf), (const struct in6_addr *) | |
387 | address, (const struct in6_addr *) address); | |
388 | else | |
389 | tomoyo_print_ipv4(buf, sizeof(buf), address, address); | |
390 | len = strlen(buf); | |
391 | snprintf(buf + len, sizeof(buf) - len, " %u", | |
392 | r->param.inet_network.port); | |
393 | return tomoyo_audit_net_log(r, "inet", r->param.inet_network.protocol, | |
394 | r->param.inet_network.operation, buf); | |
395 | } | |
396 | ||
397 | /** | |
398 | * tomoyo_audit_unix_log - Audit UNIX network log. | |
399 | * | |
400 | * @r: Pointer to "struct tomoyo_request_info". | |
401 | * | |
402 | * Returns 0 on success, negative value otherwise. | |
403 | */ | |
404 | static int tomoyo_audit_unix_log(struct tomoyo_request_info *r) | |
405 | { | |
406 | return tomoyo_audit_net_log(r, "unix", r->param.unix_network.protocol, | |
407 | r->param.unix_network.operation, | |
408 | r->param.unix_network.address->name); | |
409 | } | |
410 | ||
411 | /** | |
412 | * tomoyo_check_inet_acl - Check permission for inet domain socket operation. | |
413 | * | |
414 | * @r: Pointer to "struct tomoyo_request_info". | |
415 | * @ptr: Pointer to "struct tomoyo_acl_info". | |
416 | * | |
417 | * Returns true if granted, false otherwise. | |
418 | */ | |
419 | static bool tomoyo_check_inet_acl(struct tomoyo_request_info *r, | |
420 | const struct tomoyo_acl_info *ptr) | |
421 | { | |
422 | const struct tomoyo_inet_acl *acl = | |
423 | container_of(ptr, typeof(*acl), head); | |
424 | const u8 size = r->param.inet_network.is_ipv6 ? 16 : 4; | |
425 | ||
426 | if (!(acl->perm & (1 << r->param.inet_network.operation)) || | |
427 | !tomoyo_compare_number_union(r->param.inet_network.port, | |
428 | &acl->port)) | |
429 | return false; | |
430 | if (acl->address.group) | |
431 | return tomoyo_address_matches_group | |
432 | (r->param.inet_network.is_ipv6, | |
433 | r->param.inet_network.address, acl->address.group); | |
434 | return acl->address.is_ipv6 == r->param.inet_network.is_ipv6 && | |
435 | memcmp(&acl->address.ip[0], | |
436 | r->param.inet_network.address, size) <= 0 && | |
437 | memcmp(r->param.inet_network.address, | |
438 | &acl->address.ip[1], size) <= 0; | |
439 | } | |
440 | ||
441 | /** | |
442 | * tomoyo_check_unix_acl - Check permission for unix domain socket operation. | |
443 | * | |
444 | * @r: Pointer to "struct tomoyo_request_info". | |
445 | * @ptr: Pointer to "struct tomoyo_acl_info". | |
446 | * | |
447 | * Returns true if granted, false otherwise. | |
448 | */ | |
449 | static bool tomoyo_check_unix_acl(struct tomoyo_request_info *r, | |
450 | const struct tomoyo_acl_info *ptr) | |
451 | { | |
452 | const struct tomoyo_unix_acl *acl = | |
453 | container_of(ptr, typeof(*acl), head); | |
454 | ||
455 | return (acl->perm & (1 << r->param.unix_network.operation)) && | |
456 | tomoyo_compare_name_union(r->param.unix_network.address, | |
457 | &acl->name); | |
458 | } | |
459 | ||
460 | /** | |
461 | * tomoyo_inet_entry - Check permission for INET network operation. | |
462 | * | |
463 | * @address: Pointer to "struct tomoyo_addr_info". | |
464 | * | |
465 | * Returns 0 on success, negative value otherwise. | |
466 | */ | |
467 | static int tomoyo_inet_entry(const struct tomoyo_addr_info *address) | |
468 | { | |
469 | const int idx = tomoyo_read_lock(); | |
470 | struct tomoyo_request_info r; | |
471 | int error = 0; | |
472 | const u8 type = tomoyo_inet2mac[address->protocol][address->operation]; | |
473 | ||
474 | if (type && tomoyo_init_request_info(&r, NULL, type) | |
475 | != TOMOYO_CONFIG_DISABLED) { | |
476 | r.param_type = TOMOYO_TYPE_INET_ACL; | |
477 | r.param.inet_network.protocol = address->protocol; | |
478 | r.param.inet_network.operation = address->operation; | |
479 | r.param.inet_network.is_ipv6 = address->inet.is_ipv6; | |
480 | r.param.inet_network.address = address->inet.address; | |
481 | r.param.inet_network.port = ntohs(address->inet.port); | |
482 | do { | |
483 | tomoyo_check_acl(&r, tomoyo_check_inet_acl); | |
484 | error = tomoyo_audit_inet_log(&r); | |
485 | } while (error == TOMOYO_RETRY_REQUEST); | |
486 | } | |
487 | tomoyo_read_unlock(idx); | |
488 | return error; | |
489 | } | |
490 | ||
491 | /** | |
492 | * tomoyo_check_inet_address - Check permission for inet domain socket's operation. | |
493 | * | |
494 | * @addr: Pointer to "struct sockaddr". | |
495 | * @addr_len: Size of @addr. | |
496 | * @port: Port number. | |
497 | * @address: Pointer to "struct tomoyo_addr_info". | |
498 | * | |
499 | * Returns 0 on success, negative value otherwise. | |
500 | */ | |
501 | static int tomoyo_check_inet_address(const struct sockaddr *addr, | |
502 | const unsigned int addr_len, | |
503 | const u16 port, | |
504 | struct tomoyo_addr_info *address) | |
505 | { | |
506 | struct tomoyo_inet_addr_info *i = &address->inet; | |
507 | ||
e6193f78 TH |
508 | if (addr_len < offsetofend(struct sockaddr, sa_family)) |
509 | return 0; | |
059d84db TH |
510 | switch (addr->sa_family) { |
511 | case AF_INET6: | |
512 | if (addr_len < SIN6_LEN_RFC2133) | |
513 | goto skip; | |
514 | i->is_ipv6 = true; | |
515 | i->address = (__be32 *) | |
516 | ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr; | |
517 | i->port = ((struct sockaddr_in6 *) addr)->sin6_port; | |
518 | break; | |
519 | case AF_INET: | |
520 | if (addr_len < sizeof(struct sockaddr_in)) | |
521 | goto skip; | |
522 | i->is_ipv6 = false; | |
523 | i->address = (__be32 *) | |
524 | &((struct sockaddr_in *) addr)->sin_addr; | |
525 | i->port = ((struct sockaddr_in *) addr)->sin_port; | |
526 | break; | |
527 | default: | |
528 | goto skip; | |
529 | } | |
530 | if (address->protocol == SOCK_RAW) | |
531 | i->port = htons(port); | |
532 | return tomoyo_inet_entry(address); | |
533 | skip: | |
534 | return 0; | |
535 | } | |
536 | ||
537 | /** | |
538 | * tomoyo_unix_entry - Check permission for UNIX network operation. | |
539 | * | |
540 | * @address: Pointer to "struct tomoyo_addr_info". | |
541 | * | |
542 | * Returns 0 on success, negative value otherwise. | |
543 | */ | |
544 | static int tomoyo_unix_entry(const struct tomoyo_addr_info *address) | |
545 | { | |
546 | const int idx = tomoyo_read_lock(); | |
547 | struct tomoyo_request_info r; | |
548 | int error = 0; | |
549 | const u8 type = tomoyo_unix2mac[address->protocol][address->operation]; | |
550 | ||
551 | if (type && tomoyo_init_request_info(&r, NULL, type) | |
552 | != TOMOYO_CONFIG_DISABLED) { | |
553 | char *buf = address->unix0.addr; | |
554 | int len = address->unix0.addr_len - sizeof(sa_family_t); | |
555 | ||
556 | if (len <= 0) { | |
557 | buf = "anonymous"; | |
558 | len = 9; | |
559 | } else if (buf[0]) { | |
560 | len = strnlen(buf, len); | |
561 | } | |
562 | buf = tomoyo_encode2(buf, len); | |
563 | if (buf) { | |
564 | struct tomoyo_path_info addr; | |
565 | ||
566 | addr.name = buf; | |
567 | tomoyo_fill_path_info(&addr); | |
568 | r.param_type = TOMOYO_TYPE_UNIX_ACL; | |
569 | r.param.unix_network.protocol = address->protocol; | |
570 | r.param.unix_network.operation = address->operation; | |
571 | r.param.unix_network.address = &addr; | |
572 | do { | |
573 | tomoyo_check_acl(&r, tomoyo_check_unix_acl); | |
574 | error = tomoyo_audit_unix_log(&r); | |
575 | } while (error == TOMOYO_RETRY_REQUEST); | |
576 | kfree(buf); | |
577 | } else | |
578 | error = -ENOMEM; | |
579 | } | |
580 | tomoyo_read_unlock(idx); | |
581 | return error; | |
582 | } | |
583 | ||
584 | /** | |
585 | * tomoyo_check_unix_address - Check permission for unix domain socket's operation. | |
586 | * | |
587 | * @addr: Pointer to "struct sockaddr". | |
588 | * @addr_len: Size of @addr. | |
589 | * @address: Pointer to "struct tomoyo_addr_info". | |
590 | * | |
591 | * Returns 0 on success, negative value otherwise. | |
592 | */ | |
593 | static int tomoyo_check_unix_address(struct sockaddr *addr, | |
594 | const unsigned int addr_len, | |
595 | struct tomoyo_addr_info *address) | |
596 | { | |
597 | struct tomoyo_unix_addr_info *u = &address->unix0; | |
598 | ||
e6193f78 TH |
599 | if (addr_len < offsetofend(struct sockaddr, sa_family)) |
600 | return 0; | |
059d84db TH |
601 | if (addr->sa_family != AF_UNIX) |
602 | return 0; | |
603 | u->addr = ((struct sockaddr_un *) addr)->sun_path; | |
604 | u->addr_len = addr_len; | |
605 | return tomoyo_unix_entry(address); | |
606 | } | |
607 | ||
608 | /** | |
609 | * tomoyo_kernel_service - Check whether I'm kernel service or not. | |
610 | * | |
611 | * Returns true if I'm kernel service, false otherwise. | |
612 | */ | |
613 | static bool tomoyo_kernel_service(void) | |
614 | { | |
615 | /* Nothing to do if I am a kernel service. */ | |
4e53d170 | 616 | return current->flags & PF_KTHREAD; |
059d84db TH |
617 | } |
618 | ||
619 | /** | |
620 | * tomoyo_sock_family - Get socket's family. | |
621 | * | |
622 | * @sk: Pointer to "struct sock". | |
623 | * | |
624 | * Returns one of PF_INET, PF_INET6, PF_UNIX or 0. | |
625 | */ | |
626 | static u8 tomoyo_sock_family(struct sock *sk) | |
627 | { | |
628 | u8 family; | |
629 | ||
630 | if (tomoyo_kernel_service()) | |
631 | return 0; | |
632 | family = sk->sk_family; | |
633 | switch (family) { | |
634 | case PF_INET: | |
635 | case PF_INET6: | |
636 | case PF_UNIX: | |
637 | return family; | |
638 | default: | |
639 | return 0; | |
640 | } | |
641 | } | |
642 | ||
643 | /** | |
644 | * tomoyo_socket_listen_permission - Check permission for listening a socket. | |
645 | * | |
646 | * @sock: Pointer to "struct socket". | |
647 | * | |
648 | * Returns 0 on success, negative value otherwise. | |
649 | */ | |
650 | int tomoyo_socket_listen_permission(struct socket *sock) | |
651 | { | |
652 | struct tomoyo_addr_info address; | |
653 | const u8 family = tomoyo_sock_family(sock->sk); | |
654 | const unsigned int type = sock->type; | |
655 | struct sockaddr_storage addr; | |
656 | int addr_len; | |
657 | ||
658 | if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET)) | |
659 | return 0; | |
660 | { | |
661 | const int error = sock->ops->getname(sock, (struct sockaddr *) | |
9b2c45d4 | 662 | &addr, 0); |
059d84db | 663 | |
9b2c45d4 | 664 | if (error < 0) |
059d84db | 665 | return error; |
9b2c45d4 | 666 | addr_len = error; |
059d84db TH |
667 | } |
668 | address.protocol = type; | |
669 | address.operation = TOMOYO_NETWORK_LISTEN; | |
670 | if (family == PF_UNIX) | |
671 | return tomoyo_check_unix_address((struct sockaddr *) &addr, | |
672 | addr_len, &address); | |
673 | return tomoyo_check_inet_address((struct sockaddr *) &addr, addr_len, | |
674 | 0, &address); | |
675 | } | |
676 | ||
677 | /** | |
678 | * tomoyo_socket_connect_permission - Check permission for setting the remote address of a socket. | |
679 | * | |
680 | * @sock: Pointer to "struct socket". | |
681 | * @addr: Pointer to "struct sockaddr". | |
682 | * @addr_len: Size of @addr. | |
683 | * | |
684 | * Returns 0 on success, negative value otherwise. | |
685 | */ | |
686 | int tomoyo_socket_connect_permission(struct socket *sock, | |
687 | struct sockaddr *addr, int addr_len) | |
688 | { | |
689 | struct tomoyo_addr_info address; | |
690 | const u8 family = tomoyo_sock_family(sock->sk); | |
691 | const unsigned int type = sock->type; | |
692 | ||
693 | if (!family) | |
694 | return 0; | |
695 | address.protocol = type; | |
696 | switch (type) { | |
697 | case SOCK_DGRAM: | |
698 | case SOCK_RAW: | |
699 | address.operation = TOMOYO_NETWORK_SEND; | |
700 | break; | |
701 | case SOCK_STREAM: | |
702 | case SOCK_SEQPACKET: | |
703 | address.operation = TOMOYO_NETWORK_CONNECT; | |
704 | break; | |
705 | default: | |
706 | return 0; | |
707 | } | |
708 | if (family == PF_UNIX) | |
709 | return tomoyo_check_unix_address(addr, addr_len, &address); | |
710 | return tomoyo_check_inet_address(addr, addr_len, sock->sk->sk_protocol, | |
711 | &address); | |
712 | } | |
713 | ||
714 | /** | |
715 | * tomoyo_socket_bind_permission - Check permission for setting the local address of a socket. | |
716 | * | |
717 | * @sock: Pointer to "struct socket". | |
718 | * @addr: Pointer to "struct sockaddr". | |
719 | * @addr_len: Size of @addr. | |
720 | * | |
721 | * Returns 0 on success, negative value otherwise. | |
722 | */ | |
723 | int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr, | |
724 | int addr_len) | |
725 | { | |
726 | struct tomoyo_addr_info address; | |
727 | const u8 family = tomoyo_sock_family(sock->sk); | |
728 | const unsigned int type = sock->type; | |
729 | ||
730 | if (!family) | |
731 | return 0; | |
732 | switch (type) { | |
733 | case SOCK_STREAM: | |
734 | case SOCK_DGRAM: | |
735 | case SOCK_RAW: | |
736 | case SOCK_SEQPACKET: | |
737 | address.protocol = type; | |
738 | address.operation = TOMOYO_NETWORK_BIND; | |
739 | break; | |
740 | default: | |
741 | return 0; | |
742 | } | |
743 | if (family == PF_UNIX) | |
744 | return tomoyo_check_unix_address(addr, addr_len, &address); | |
745 | return tomoyo_check_inet_address(addr, addr_len, sock->sk->sk_protocol, | |
746 | &address); | |
747 | } | |
748 | ||
749 | /** | |
750 | * tomoyo_socket_sendmsg_permission - Check permission for sending a datagram. | |
751 | * | |
752 | * @sock: Pointer to "struct socket". | |
753 | * @msg: Pointer to "struct msghdr". | |
754 | * @size: Unused. | |
755 | * | |
756 | * Returns 0 on success, negative value otherwise. | |
757 | */ | |
758 | int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg, | |
759 | int size) | |
760 | { | |
761 | struct tomoyo_addr_info address; | |
762 | const u8 family = tomoyo_sock_family(sock->sk); | |
763 | const unsigned int type = sock->type; | |
764 | ||
765 | if (!msg->msg_name || !family || | |
766 | (type != SOCK_DGRAM && type != SOCK_RAW)) | |
767 | return 0; | |
768 | address.protocol = type; | |
769 | address.operation = TOMOYO_NETWORK_SEND; | |
770 | if (family == PF_UNIX) | |
771 | return tomoyo_check_unix_address((struct sockaddr *) | |
772 | msg->msg_name, | |
773 | msg->msg_namelen, &address); | |
774 | return tomoyo_check_inet_address((struct sockaddr *) msg->msg_name, | |
775 | msg->msg_namelen, | |
776 | sock->sk->sk_protocol, &address); | |
777 | } |