18 |
#include <net/ipv6.h> |
#include <net/ipv6.h> |
19 |
#include <net/udp.h> |
#include <net/udp.h> |
20 |
#include "internal.h" |
#include "internal.h" |
|
#include <linux/ccsecurity.h> |
|
21 |
|
|
22 |
/* Index numbers for Network Controls. */ |
/* Index numbers for Network Controls. */ |
23 |
enum ccs_network_acl_index { |
enum ccs_network_acl_index { |
446 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
447 |
*/ |
*/ |
448 |
static int ccs_update_network_entry(const u8 operation, const u8 record_type, |
static int ccs_update_network_entry(const u8 operation, const u8 record_type, |
449 |
const char *group_name, |
const char *address_group_name, |
450 |
|
const char *port_group_name, |
451 |
const u32 *min_address, |
const u32 *min_address, |
452 |
const u32 *max_address, |
const u32 *max_address, |
453 |
const u16 min_port, const u16 max_port, |
const u16 min_port, const u16 max_port, |
455 |
struct ccs_condition *condition, |
struct ccs_condition *condition, |
456 |
const bool is_delete) |
const bool is_delete) |
457 |
{ |
{ |
|
struct ccs_ip_network_acl_record *entry = NULL; |
|
458 |
struct ccs_acl_info *ptr; |
struct ccs_acl_info *ptr; |
459 |
|
struct ccs_ip_network_acl_record e; |
460 |
|
struct ccs_ip_network_acl_record *entry = NULL; |
461 |
int error = is_delete ? -ENOENT : -ENOMEM; |
int error = is_delete ? -ENOENT : -ENOMEM; |
462 |
/* using host byte order to allow u32 comparison than memcmp().*/ |
memset(&e, 0, sizeof(e)); |
463 |
const u32 min_ip = ntohl(*min_address); |
e.head.type = TYPE_IP_NETWORK_ACL; |
464 |
const u32 max_ip = ntohl(*max_address); |
e.head.cond = condition; |
|
const struct in6_addr *saved_min_address = NULL; |
|
|
const struct in6_addr *saved_max_address = NULL; |
|
|
struct ccs_address_group_entry *group = NULL; |
|
465 |
if (!domain) |
if (!domain) |
466 |
return -EINVAL; |
return -EINVAL; |
467 |
if (group_name) { |
if (address_group_name) { |
468 |
group = ccs_get_address_group(group_name); |
e.address.group = ccs_get_address_group(address_group_name); |
469 |
if (!group) |
if (!e.address.group) |
470 |
return -ENOMEM; |
return -ENOMEM; |
471 |
} else if (record_type == IP_RECORD_TYPE_IPv6) { |
} else if (record_type == IP_RECORD_TYPE_IPv6) { |
472 |
saved_min_address = ccs_get_ipv6_address((struct in6_addr *) |
e.address.ipv6.min = ccs_get_ipv6_address((struct in6_addr *) |
473 |
min_address); |
min_address); |
474 |
saved_max_address = ccs_get_ipv6_address((struct in6_addr *) |
e.address.ipv6.max = ccs_get_ipv6_address((struct in6_addr *) |
475 |
max_address); |
max_address); |
476 |
if (!saved_min_address || !saved_max_address) |
if (!e.address.ipv6.min || !e.address.ipv6.max) |
477 |
goto out; |
goto out; |
478 |
|
} else { |
479 |
|
/* use host byte order to allow u32 comparison than memcmp().*/ |
480 |
|
e.address.ipv4.min = ntohl(*min_address); |
481 |
|
e.address.ipv4.max = ntohl(*max_address); |
482 |
|
} |
483 |
|
if (port_group_name) { |
484 |
|
if (!ccs_check_and_save_number(port_group_name, |
485 |
|
&e.port_is_group, &e.port)) |
486 |
|
goto out; |
487 |
|
} else { |
488 |
|
e.port.value.min = min_port; |
489 |
|
e.port.value.max = max_port; |
490 |
} |
} |
491 |
if (is_delete) |
if (is_delete) |
492 |
goto delete; |
goto delete; |
499 |
if (ptr->cond != condition) |
if (ptr->cond != condition) |
500 |
continue; |
continue; |
501 |
acl = container_of(ptr, struct ccs_ip_network_acl_record, head); |
acl = container_of(ptr, struct ccs_ip_network_acl_record, head); |
502 |
if (acl->operation_type != operation || |
if (memcmp(acl, &e, sizeof(e))) |
|
acl->record_type != record_type || |
|
|
acl->min_port != min_port || max_port != acl->max_port) |
|
503 |
continue; |
continue; |
|
if (record_type == IP_RECORD_TYPE_ADDRESS_GROUP) { |
|
|
if (acl->u.group != group) |
|
|
continue; |
|
|
} else if (record_type == IP_RECORD_TYPE_IPv4) { |
|
|
if (acl->u.ipv4.min != min_ip || |
|
|
max_ip != acl->u.ipv4.max) |
|
|
continue; |
|
|
} else if (record_type == IP_RECORD_TYPE_IPv6) { |
|
|
if (acl->u.ipv6.min != saved_min_address || |
|
|
saved_max_address != acl->u.ipv6.max) |
|
|
continue; |
|
|
} |
|
504 |
error = ccs_add_domain_acl(NULL, ptr); |
error = ccs_add_domain_acl(NULL, ptr); |
505 |
break; |
break; |
506 |
} |
} |
507 |
if (error && ccs_memory_ok(entry, sizeof(*entry))) { |
if (error && ccs_memory_ok(entry, sizeof(*entry))) { |
508 |
entry->head.type = TYPE_IP_NETWORK_ACL; |
memmove(entry, &e, sizeof(e)); |
509 |
entry->head.cond = condition; |
memset(&e, 0, sizeof(e)); |
|
entry->operation_type = operation; |
|
|
entry->record_type = record_type; |
|
|
if (record_type == IP_RECORD_TYPE_ADDRESS_GROUP) { |
|
|
entry->u.group = group; |
|
|
group = NULL; |
|
|
} else if (record_type == IP_RECORD_TYPE_IPv4) { |
|
|
entry->u.ipv4.min = min_ip; |
|
|
entry->u.ipv4.max = max_ip; |
|
|
} else { |
|
|
entry->u.ipv6.min = saved_min_address; |
|
|
saved_min_address = NULL; |
|
|
entry->u.ipv6.max = saved_max_address; |
|
|
saved_max_address = NULL; |
|
|
} |
|
|
entry->min_port = min_port; |
|
|
entry->max_port = max_port; |
|
510 |
error = ccs_add_domain_acl(domain, &entry->head); |
error = ccs_add_domain_acl(domain, &entry->head); |
511 |
entry = NULL; |
entry = NULL; |
512 |
} |
} |
521 |
if (ptr->cond != condition) |
if (ptr->cond != condition) |
522 |
continue; |
continue; |
523 |
acl = container_of(ptr, struct ccs_ip_network_acl_record, head); |
acl = container_of(ptr, struct ccs_ip_network_acl_record, head); |
524 |
if (acl->operation_type != operation || |
if (memcmp(acl, &e, sizeof(e))) |
|
acl->record_type != record_type || |
|
|
acl->min_port != min_port || max_port != acl->max_port) |
|
525 |
continue; |
continue; |
|
if (record_type == IP_RECORD_TYPE_ADDRESS_GROUP) { |
|
|
if (acl->u.group != group) |
|
|
continue; |
|
|
} else if (record_type == IP_RECORD_TYPE_IPv4) { |
|
|
if (acl->u.ipv4.min != min_ip || |
|
|
max_ip != acl->u.ipv4.max) |
|
|
continue; |
|
|
} else if (record_type == IP_RECORD_TYPE_IPv6) { |
|
|
if (acl->u.ipv6.min != saved_min_address || |
|
|
saved_max_address != acl->u.ipv6.max) |
|
|
continue; |
|
|
} |
|
526 |
error = ccs_del_domain_acl(ptr); |
error = ccs_del_domain_acl(ptr); |
527 |
break; |
break; |
528 |
} |
} |
529 |
mutex_unlock(&ccs_policy_lock); |
mutex_unlock(&ccs_policy_lock); |
530 |
out: |
out: |
531 |
ccs_put_ipv6_address(saved_min_address); |
if (address_group_name) |
532 |
ccs_put_ipv6_address(saved_max_address); |
ccs_put_address_group(e.address.group); |
533 |
ccs_put_address_group(group); |
else if (record_type == IP_RECORD_TYPE_IPv6) { |
534 |
|
ccs_put_ipv6_address(e.address.ipv6.min); |
535 |
|
ccs_put_ipv6_address(e.address.ipv6.max); |
536 |
|
} |
537 |
|
if (port_group_name) |
538 |
|
ccs_put_number_group(e.port.group); |
539 |
kfree(entry); |
kfree(entry); |
540 |
return error; |
return error; |
541 |
} |
} |
576 |
if (ccs_acl_type2(ptr) != TYPE_IP_NETWORK_ACL) |
if (ccs_acl_type2(ptr) != TYPE_IP_NETWORK_ACL) |
577 |
continue; |
continue; |
578 |
acl = container_of(ptr, struct ccs_ip_network_acl_record, head); |
acl = container_of(ptr, struct ccs_ip_network_acl_record, head); |
579 |
if (acl->operation_type != operation || port < acl->min_port || |
if (acl->operation_type != operation) |
580 |
acl->max_port < port || !ccs_check_condition(&r, ptr)) |
continue; |
581 |
|
if (acl->port_is_group) { |
582 |
|
if (!ccs_number_matches_group(port, port, |
583 |
|
acl->port.group)) |
584 |
|
continue; |
585 |
|
} else { |
586 |
|
if (port < acl->port.value.min || |
587 |
|
acl->port.value.max < port) |
588 |
|
continue; |
589 |
|
} |
590 |
|
if (!ccs_check_condition(&r, ptr)) |
591 |
continue; |
continue; |
592 |
if (acl->record_type == IP_RECORD_TYPE_ADDRESS_GROUP) { |
if (acl->record_type == IP_RECORD_TYPE_ADDRESS_GROUP) { |
593 |
if (!ccs_address_matches_group(is_ipv6, address, |
if (!ccs_address_matches_group(is_ipv6, address, |
594 |
acl->u.group)) |
acl->address.group)) |
595 |
continue; |
continue; |
596 |
} else if (acl->record_type == IP_RECORD_TYPE_IPv4) { |
} else if (acl->record_type == IP_RECORD_TYPE_IPv4) { |
597 |
if (is_ipv6 || |
if (is_ipv6 || |
598 |
ip < acl->u.ipv4.min || acl->u.ipv4.max < ip) |
ip < acl->address.ipv4.min || |
599 |
|
acl->address.ipv4.max < ip) |
600 |
continue; |
continue; |
601 |
} else { |
} else { |
602 |
if (!is_ipv6 || |
if (!is_ipv6 || |
603 |
memcmp(acl->u.ipv6.min, address, 16) > 0 || |
memcmp(acl->address.ipv6.min, address, 16) > 0 || |
604 |
memcmp(address, acl->u.ipv6.max, 16) > 0) |
memcmp(address, acl->address.ipv6.max, 16) > 0) |
605 |
continue; |
continue; |
606 |
} |
} |
607 |
r.cond = ptr->cond; |
r.cond = ptr->cond; |
629 |
ccs_update_network_entry(operation, is_ipv6 ? |
ccs_update_network_entry(operation, is_ipv6 ? |
630 |
IP_RECORD_TYPE_IPv6 : |
IP_RECORD_TYPE_IPv6 : |
631 |
IP_RECORD_TYPE_IPv4, |
IP_RECORD_TYPE_IPv4, |
632 |
NULL, address, address, port, port, |
NULL, NULL, address, address, port, |
633 |
r.domain, cond, false); |
port, r.domain, cond, false); |
634 |
ccs_put_condition(cond); |
ccs_put_condition(cond); |
635 |
} |
} |
636 |
return 0; |
return 0; |
676 |
u8 record_type; |
u8 record_type; |
677 |
u16 min_address[8]; |
u16 min_address[8]; |
678 |
u16 max_address[8]; |
u16 max_address[8]; |
679 |
const char *group_name = NULL; |
const char *address_group_name = NULL; |
680 |
|
const char *port_group_name = NULL; |
681 |
u16 min_port; |
u16 min_port; |
682 |
u16 max_port; |
u16 max_port; |
|
u8 count; |
|
683 |
if (!ccs_tokenize(data, w, sizeof(w)) || !w[3][0]) |
if (!ccs_tokenize(data, w, sizeof(w)) || !w[3][0]) |
684 |
return -EINVAL; |
return -EINVAL; |
685 |
if (!strcmp(w[0], "TCP")) |
if (!strcmp(w[0], "TCP")) |
728 |
default: |
default: |
729 |
if (w[2][0] != '@') |
if (w[2][0] != '@') |
730 |
goto out; |
goto out; |
731 |
group_name = w[2] + 1; |
address_group_name = w[2] + 1; |
732 |
record_type = IP_RECORD_TYPE_ADDRESS_GROUP; |
record_type = IP_RECORD_TYPE_ADDRESS_GROUP; |
733 |
break; |
break; |
734 |
} |
} |
735 |
count = sscanf(w[3], "%hu-%hu", &min_port, &max_port); |
switch (sscanf(w[3], "%hu-%hu", &min_port, &max_port)) { |
736 |
if (count != 1 && count != 2) |
case 2: |
737 |
goto out; |
break; |
738 |
if (count == 1) |
case 1: |
739 |
max_port = min_port; |
max_port = min_port; |
740 |
return ccs_update_network_entry(operation, record_type, group_name, |
break; |
741 |
|
default: |
742 |
|
if (w[3][0] != '@') |
743 |
|
goto out; |
744 |
|
port_group_name = w[3]; |
745 |
|
break; |
746 |
|
} |
747 |
|
return ccs_update_network_entry(operation, record_type, |
748 |
|
address_group_name, port_group_name, |
749 |
(u32 *) min_address, |
(u32 *) min_address, |
750 |
(u32 *) max_address, |
(u32 *) max_address, |
751 |
min_port, max_port, domain, condition, |
min_port, max_port, domain, condition, |