5 |
* |
* |
6 |
* Copyright (C) 2005-2008 NTT DATA CORPORATION |
* Copyright (C) 2005-2008 NTT DATA CORPORATION |
7 |
* |
* |
8 |
* Version: 1.6.0-pre 2008/03/24 |
* Version: 1.6.0 2008/04/01 |
9 |
* |
* |
10 |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
11 |
* See README.ccs for ChangeLog. |
* See README.ccs for ChangeLog. |
15 |
#include <linux/ccs_common.h> |
#include <linux/ccs_common.h> |
16 |
#include <linux/tomoyo.h> |
#include <linux/tomoyo.h> |
17 |
#include <linux/realpath.h> |
#include <linux/realpath.h> |
18 |
#include <net/ip.h> |
#include <linux/net.h> |
19 |
|
#include <linux/inet.h> |
20 |
|
#include <linux/in.h> |
21 |
|
#include <linux/in6.h> |
22 |
|
|
23 |
/** |
/** |
24 |
* audit_network_log - Audit network log. |
* audit_network_log - Audit network log. |
28 |
* @address: An IPv4 or IPv6 address. |
* @address: An IPv4 or IPv6 address. |
29 |
* @port: Port number. |
* @port: Port number. |
30 |
* @is_granted: True if this is a granted log. |
* @is_granted: True if this is a granted log. |
31 |
* @profile: Profile number. |
* @profile: Profile number used. |
32 |
* @mode: Access control mode. |
* @mode: Access control mode used. |
33 |
* |
* |
34 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
35 |
*/ |
*/ |
36 |
static int audit_network_log(const bool is_ipv6, const char *operation, |
static int audit_network_log(const bool is_ipv6, const char *operation, |
37 |
const u32 *address, const u16 port, |
const char *address, const u16 port, |
38 |
const bool is_granted, const u8 profile, |
const bool is_granted, |
39 |
const u8 mode) |
const u8 profile, const u8 mode) |
40 |
{ |
{ |
41 |
char *buf; |
char *buf; |
42 |
int len = 256, len2; |
int len = 256; |
43 |
|
int len2; |
44 |
if (ccs_can_save_audit_log(is_granted) < 0) |
if (ccs_can_save_audit_log(is_granted) < 0) |
45 |
return -ENOMEM; |
return -ENOMEM; |
46 |
buf = ccs_init_audit_log(&len, profile, mode, NULL); |
buf = ccs_init_audit_log(&len, profile, mode, NULL); |
47 |
if (!buf) |
if (!buf) |
48 |
return -ENOMEM; |
return -ENOMEM; |
49 |
len2 = strlen(buf); |
len2 = strlen(buf); |
50 |
snprintf(buf + len2, len - len2 - 1, KEYWORD_ALLOW_NETWORK "%s ", |
snprintf(buf + len2, len - len2 - 1, KEYWORD_ALLOW_NETWORK "%s %s %u\n", |
51 |
operation); |
operation, address, port); |
|
len2 = strlen(buf); |
|
|
if (is_ipv6) { |
|
|
ccs_print_ipv6(buf + len2, len - len2, |
|
|
(const struct in6_addr *) address); |
|
|
} else { |
|
|
u32 ip = *address; |
|
|
snprintf(buf + len2, len - len2 - 1, "%u.%u.%u.%u", |
|
|
NIPQUAD(ip)); |
|
|
} |
|
|
len2 = strlen(buf); |
|
|
snprintf(buf + len2, len - len2 - 1, " %u\n", port); |
|
52 |
return ccs_write_audit_log(buf, is_granted); |
return ccs_write_audit_log(buf, is_granted); |
53 |
} |
} |
54 |
|
|
78 |
mutex_lock(&lock); |
mutex_lock(&lock); |
79 |
list1_for_each_entry(ptr, &address_list, list) { |
list1_for_each_entry(ptr, &address_list, list) { |
80 |
for (i = 0; i < ptr->in_use_count; i++) { |
for (i = 0; i < ptr->in_use_count; i++) { |
81 |
if (memcmp(&ptr->addr[i], addr, sizeof(*addr)) == 0) |
if (!memcmp(&ptr->addr[i], addr, sizeof(*addr))) |
82 |
goto ok; |
goto ok; |
83 |
} |
} |
84 |
if (i < block_size) |
if (i < block_size) |
103 |
/** |
/** |
104 |
* update_address_group_entry - Update "struct address_group_entry" list. |
* update_address_group_entry - Update "struct address_group_entry" list. |
105 |
* |
* |
106 |
* @group_name: The name of group. |
* @group_name: The name of address group. |
107 |
* @is_ipv6: True if @address is an IPv6 address. |
* @is_ipv6: True if @min_address and @max_address are IPv6 addresses. |
108 |
* @min_address: Start of IPv4 or IPv6 address range. |
* @min_address: Start of IPv4 or IPv6 address range. |
109 |
* @max_address: End of IPv4 or IPv6 address range. |
* @max_address: End of IPv4 or IPv6 address range. |
110 |
* @is_delete: True if it is a delete request. |
* @is_delete: True if it is a delete request. |
118 |
const bool is_delete) |
const bool is_delete) |
119 |
{ |
{ |
120 |
static DEFINE_MUTEX(lock); |
static DEFINE_MUTEX(lock); |
121 |
struct address_group_entry *new_group, *group; |
struct address_group_entry *new_group; |
122 |
struct address_group_member *new_member, *member; |
struct address_group_entry *group; |
123 |
|
struct address_group_member *new_member; |
124 |
|
struct address_group_member *member; |
125 |
const struct path_info *saved_group_name; |
const struct path_info *saved_group_name; |
126 |
const struct in6_addr *saved_min_address = NULL; |
const struct in6_addr *saved_min_address = NULL; |
127 |
const struct in6_addr *saved_max_address = NULL; |
const struct in6_addr *saved_max_address = NULL; |
194 |
error = 0; |
error = 0; |
195 |
out: |
out: |
196 |
mutex_unlock(&lock); |
mutex_unlock(&lock); |
197 |
|
ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY); |
198 |
return error; |
return error; |
199 |
} |
} |
200 |
|
|
210 |
{ |
{ |
211 |
u8 count; |
u8 count; |
212 |
bool is_ipv6; |
bool is_ipv6; |
213 |
u16 min_address[8], max_address[8]; |
u16 min_address[8]; |
214 |
|
u16 max_address[8]; |
215 |
char *cp = strchr(data, ' '); |
char *cp = strchr(data, ' '); |
216 |
if (!cp) |
if (!cp) |
217 |
return -EINVAL; |
return -EINVAL; |
255 |
+ (u8) max_address[3]); |
+ (u8) max_address[3]); |
256 |
*(u32 *) max_address = ip; |
*(u32 *) max_address = ip; |
257 |
is_ipv6 = false; |
is_ipv6 = false; |
258 |
} else { |
goto ok; |
|
return -EINVAL; |
|
259 |
} |
} |
260 |
|
return -EINVAL; |
261 |
ok: |
ok: |
262 |
return update_address_group_entry(data, is_ipv6, |
return update_address_group_entry(data, is_ipv6, |
263 |
min_address, max_address, is_delete); |
min_address, max_address, is_delete); |
266 |
/** |
/** |
267 |
* find_or_assign_new_address_group - Create address group. |
* find_or_assign_new_address_group - Create address group. |
268 |
* |
* |
269 |
* @group_name: The name of group. |
* @group_name: The name of address group. |
270 |
* |
* |
271 |
* Returns pointer to "struct address_group_entry" on success, NULL otherwise. |
* Returns pointer to "struct address_group_entry" on success, NULL otherwise. |
272 |
*/ |
*/ |
277 |
struct address_group_entry *group; |
struct address_group_entry *group; |
278 |
for (i = 0; i <= 1; i++) { |
for (i = 0; i <= 1; i++) { |
279 |
list1_for_each_entry(group, &address_group_list, list) { |
list1_for_each_entry(group, &address_group_list, list) { |
280 |
if (strcmp(group_name, group->group_name->name) == 0) |
if (!strcmp(group_name, group->group_name->name)) |
281 |
return group; |
return group; |
282 |
} |
} |
283 |
if (i == 0) { |
if (!i) { |
284 |
const u16 dummy[2] = { 0, 0 }; |
const u16 dummy[2] = { 0, 0 }; |
285 |
update_address_group_entry(group_name, false, |
update_address_group_entry(group_name, false, |
286 |
dummy, dummy, false); |
dummy, dummy, false); |
292 |
} |
} |
293 |
|
|
294 |
/** |
/** |
295 |
* address_matches_to_group - Check whether the given address matches members |
* address_matches_to_group - Check whether the given address matches members of the given address group. |
|
* of the given address group. |
|
296 |
* |
* |
297 |
* @is_ipv6: True if @address is an IPv6 address. |
* @is_ipv6: True if @address is an IPv6 address. |
298 |
* @address: An IPv4 or IPv6 address. |
* @address: An IPv4 or IPv6 address. |
323 |
} |
} |
324 |
|
|
325 |
/** |
/** |
326 |
* ccs_read_address_group_policy - Dump "struct address_group_entry" list. |
* ccs_read_address_group_policy - Read "struct address_group_entry" list. |
327 |
* |
* |
328 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
329 |
* |
* |
344 |
list); |
list); |
345 |
if (member->is_deleted) |
if (member->is_deleted) |
346 |
continue; |
continue; |
347 |
if (!member->is_ipv6) { |
if (member->is_ipv6) { |
348 |
const struct in6_addr *min_address |
const struct in6_addr *min_address |
349 |
= member->min.ipv6; |
= member->min.ipv6; |
350 |
const struct in6_addr *max_address |
const struct in6_addr *max_address |
385 |
|
|
386 |
#if !defined(NIP6) |
#if !defined(NIP6) |
387 |
#define NIP6(addr) \ |
#define NIP6(addr) \ |
388 |
ntohs((addr).s6_addr16[0]),ntohs((addr).s6_addr16[1]),\ |
ntohs((addr).s6_addr16[0]), ntohs((addr).s6_addr16[1]), \ |
389 |
ntohs((addr).s6_addr16[2]),ntohs((addr).s6_addr16[3]),\ |
ntohs((addr).s6_addr16[2]), ntohs((addr).s6_addr16[3]), \ |
390 |
ntohs((addr).s6_addr16[4]),ntohs((addr).s6_addr16[5]),\ |
ntohs((addr).s6_addr16[4]), ntohs((addr).s6_addr16[5]), \ |
391 |
ntohs((addr).s6_addr16[6]),ntohs((addr).s6_addr16[7]) |
ntohs((addr).s6_addr16[6]), ntohs((addr).s6_addr16[7]) |
392 |
#endif |
#endif |
393 |
|
|
394 |
/** |
/** |
395 |
* ccs_print_ipv6 - Dump an IPv6 address. |
* ccs_print_ipv6 - Print an IPv6 address. |
396 |
* |
* |
397 |
* @buffer: Buffer to write to. |
* @buffer: Buffer to write to. |
398 |
* @buffer_len: Size of @buffer . |
* @buffer_len: Size of @buffer. |
399 |
* @ip: Pointer to "struct in6_addr". |
* @ip: Pointer to "struct in6_addr". |
400 |
* |
* |
401 |
* Returns @buffer. |
* Returns nothing. |
402 |
*/ |
*/ |
403 |
char *ccs_print_ipv6(char *buffer, const int buffer_len, |
void ccs_print_ipv6(char *buffer, const int buffer_len, |
404 |
const struct in6_addr *ip) |
const struct in6_addr *ip) |
405 |
{ |
{ |
406 |
memset(buffer, 0, buffer_len); |
memset(buffer, 0, buffer_len); |
407 |
snprintf(buffer, buffer_len - 1, "%x:%x:%x:%x:%x:%x:%x:%x", NIP6(*ip)); |
snprintf(buffer, buffer_len - 1, "%x:%x:%x:%x:%x:%x:%x:%x", NIP6(*ip)); |
|
return buffer; |
|
408 |
} |
} |
409 |
|
|
410 |
/** |
/** |
491 |
if (is_delete) |
if (is_delete) |
492 |
goto delete; |
goto delete; |
493 |
list1_for_each_entry(ptr, &domain->acl_info_list, list) { |
list1_for_each_entry(ptr, &domain->acl_info_list, list) { |
494 |
if ((ptr->type & ~(ACL_DELETED | ACL_WITH_CONDITION)) |
if (ccs_acl_type1(ptr) != TYPE_IP_NETWORK_ACL) |
|
!= TYPE_IP_NETWORK_ACL) |
|
495 |
continue; |
continue; |
496 |
if (ccs_get_condition_part(ptr) != condition) |
if (ccs_get_condition_part(ptr) != condition) |
497 |
continue; |
continue; |
537 |
delete: |
delete: |
538 |
error = -ENOENT; |
error = -ENOENT; |
539 |
list1_for_each_entry(ptr, &domain->acl_info_list, list) { |
list1_for_each_entry(ptr, &domain->acl_info_list, list) { |
540 |
if ((ptr->type & ~ACL_WITH_CONDITION) != TYPE_IP_NETWORK_ACL) |
if (ccs_acl_type2(ptr) != TYPE_IP_NETWORK_ACL) |
541 |
continue; |
continue; |
542 |
if (ccs_get_condition_part(ptr) != condition) |
if (ccs_get_condition_part(ptr) != condition) |
543 |
continue; |
continue; |
588 |
/* using host byte order to allow u32 comparison than memcmp().*/ |
/* using host byte order to allow u32 comparison than memcmp().*/ |
589 |
const u32 ip = ntohl(*address); |
const u32 ip = ntohl(*address); |
590 |
bool found = false; |
bool found = false; |
591 |
|
char buf[64]; |
592 |
if (!mode) |
if (!mode) |
593 |
return 0; |
return 0; |
594 |
list1_for_each_entry(ptr, &domain->acl_info_list, list) { |
list1_for_each_entry(ptr, &domain->acl_info_list, list) { |
595 |
struct ip_network_acl_record *acl; |
struct ip_network_acl_record *acl; |
596 |
if ((ptr->type & ~ACL_WITH_CONDITION) != TYPE_IP_NETWORK_ACL) |
if (ccs_acl_type2(ptr) != TYPE_IP_NETWORK_ACL) |
597 |
continue; |
continue; |
598 |
acl = container_of(ptr, struct ip_network_acl_record, head); |
acl = container_of(ptr, struct ip_network_acl_record, head); |
599 |
if (acl->operation_type != operation || port < acl->min_port || |
if (acl->operation_type != operation || port < acl->min_port || |
617 |
found = true; |
found = true; |
618 |
break; |
break; |
619 |
} |
} |
620 |
audit_network_log(is_ipv6, keyword, address, port, found, profile, |
memset(buf, 0, sizeof(buf)); |
621 |
mode); |
if (is_ipv6) |
622 |
|
ccs_print_ipv6(buf, sizeof(buf), |
623 |
|
(const struct in6_addr *) address); |
624 |
|
else |
625 |
|
snprintf(buf, sizeof(buf) - 1, "%u.%u.%u.%u", HIPQUAD(ip)); |
626 |
|
audit_network_log(is_ipv6, keyword, buf, port, found, profile, mode); |
627 |
if (found) |
if (found) |
628 |
return 0; |
return 0; |
629 |
if (ccs_verbose_mode()) { |
if (ccs_verbose_mode()) |
630 |
if (is_ipv6) { |
printk(KERN_WARNING "TOMOYO-%s: %s to %s %u denied for %s\n", |
631 |
char buf[64]; |
ccs_get_msg(is_enforce), keyword, buf, port, |
632 |
ccs_print_ipv6(buf, sizeof(buf), |
ccs_get_last_name(domain)); |
633 |
(const struct in6_addr *) address); |
if (is_enforce) |
|
printk(KERN_WARNING "TOMOYO-%s: %s to %s %u " |
|
|
"denied for %s\n", ccs_get_msg(is_enforce), |
|
|
keyword, buf, port, ccs_get_last_name(domain)); |
|
|
} else { |
|
|
printk(KERN_WARNING "TOMOYO-%s: %s to %u.%u.%u.%u %u " |
|
|
"denied for %s\n", ccs_get_msg(is_enforce), |
|
|
keyword, HIPQUAD(ip), port, |
|
|
ccs_get_last_name(domain)); |
|
|
} |
|
|
} |
|
|
if (is_enforce) { |
|
|
if (is_ipv6) { |
|
|
char buf[64]; |
|
|
ccs_print_ipv6(buf, sizeof(buf), |
|
|
(const struct in6_addr *) address); |
|
|
return ccs_check_supervisor("%s\n" |
|
|
KEYWORD_ALLOW_NETWORK "%s " |
|
|
"%s %u\n", |
|
|
domain->domainname->name, |
|
|
keyword, buf, port); |
|
|
} |
|
634 |
return ccs_check_supervisor("%s\n" KEYWORD_ALLOW_NETWORK "%s " |
return ccs_check_supervisor("%s\n" KEYWORD_ALLOW_NETWORK "%s " |
635 |
"%u.%u.%u.%u %u\n", |
"%s %u\n", domain->domainname->name, |
636 |
domain->domainname->name, keyword, |
keyword, buf, port); |
637 |
HIPQUAD(ip), port); |
if (mode == 1 && ccs_check_domain_quota(domain)) |
|
} else if (mode == 1 && ccs_check_domain_quota(domain)) |
|
638 |
update_network_entry(operation, is_ipv6 ? |
update_network_entry(operation, is_ipv6 ? |
639 |
IP_RECORD_TYPE_IPv6 : IP_RECORD_TYPE_IPv4, |
IP_RECORD_TYPE_IPv6 : IP_RECORD_TYPE_IPv4, |
640 |
NULL, address, address, port, port, domain, |
NULL, address, address, port, port, domain, |
656 |
const struct condition_list *condition, |
const struct condition_list *condition, |
657 |
const bool is_delete) |
const bool is_delete) |
658 |
{ |
{ |
659 |
u8 sock_type, operation, record_type; |
u8 sock_type; |
660 |
u16 min_address[8], max_address[8]; |
u8 operation; |
661 |
|
u8 record_type; |
662 |
|
u16 min_address[8]; |
663 |
|
u16 max_address[8]; |
664 |
struct address_group_entry *group = NULL; |
struct address_group_entry *group = NULL; |
665 |
u16 min_port, max_port; |
u16 min_port; |
666 |
|
u16 max_port; |
667 |
u8 count; |
u8 count; |
668 |
char *cp1 = NULL, *cp2 = NULL; |
char *cp1 = strchr(data, ' '); |
669 |
cp1 = strchr(data, ' '); |
char *cp2; |
670 |
if (!cp1) |
if (!cp1) |
671 |
goto out; |
goto out; |
672 |
cp1++; |
cp1++; |
753 |
+ (u8) max_address[3]); |
+ (u8) max_address[3]); |
754 |
*(u32 *) max_address = ip; |
*(u32 *) max_address = ip; |
755 |
record_type = IP_RECORD_TYPE_IPv4; |
record_type = IP_RECORD_TYPE_IPv4; |
756 |
} else if (*cp2 == '@') { |
goto ok; |
757 |
|
} |
758 |
|
if (*cp2 == '@') { |
759 |
group = find_or_assign_new_address_group(cp2 + 1); |
group = find_or_assign_new_address_group(cp2 + 1); |
760 |
if (!group) |
if (!group) |
761 |
return -ENOMEM; |
return -ENOMEM; |
762 |
record_type = IP_RECORD_TYPE_ADDRESS_GROUP; |
record_type = IP_RECORD_TYPE_ADDRESS_GROUP; |
763 |
} else { |
goto ok; |
|
goto out; |
|
764 |
} |
} |
765 |
|
out: |
766 |
|
return -EINVAL; |
767 |
ok: |
ok: |
768 |
if (strchr(cp1, ' ')) |
if (strchr(cp1, ' ')) |
769 |
goto out; |
goto out; |
776 |
(u32 *) min_address, (u32 *) max_address, |
(u32 *) min_address, (u32 *) max_address, |
777 |
min_port, max_port, domain, condition, |
min_port, max_port, domain, condition, |
778 |
is_delete); |
is_delete); |
|
out: |
|
|
return -EINVAL; |
|
779 |
} |
} |
780 |
|
|
781 |
/** |
/** |
907 |
{ |
{ |
908 |
int retval; |
int retval; |
909 |
const u8 operation |
const u8 operation |
910 |
= sock_type == SOCK_DGRAM ? |
= (sock_type == SOCK_DGRAM) ? |
911 |
NETWORK_ACL_UDP_CONNECT : NETWORK_ACL_RAW_CONNECT; |
NETWORK_ACL_UDP_CONNECT : NETWORK_ACL_RAW_CONNECT; |
912 |
current->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR; |
current->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR; |
913 |
retval = check_network_entry(is_ipv6, operation, (const u32 *) address, |
retval = check_network_entry(is_ipv6, operation, (const u32 *) address, |