checkpolicy: support CIDR notation for nodecon statements
Support the Classless Inter-Domain Routing (CIDR) notation for IP addresses with their associated network masks in nodecon statements. The two following statements are equivalent: nodecon 10.8.0.0 255.255.0.0 USER1:ROLE1:TYPE1 nodecon 10.8.0.0/16 USER1:ROLE1:TYPE1 Signed-off-by: Christian Göttsche <cgzones@googlemail.com> Acked-by: James Carter <jwcart2@gmail.com>
This commit is contained in:
parent
44533801dd
commit
804e52b7f8
|
@ -5335,6 +5335,100 @@ out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int define_ipv4_cidr_node_context(void)
|
||||||
|
{
|
||||||
|
char *endptr, *id, *split;
|
||||||
|
unsigned long mask_bits;
|
||||||
|
uint32_t mask;
|
||||||
|
struct in_addr addr;
|
||||||
|
ocontext_t *newc, *c, *l, *head;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
|
||||||
|
yyerror("nodecon not supported for target");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pass == 1) {
|
||||||
|
free(queue_remove(id_queue));
|
||||||
|
parse_security_context(NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = queue_remove(id_queue);
|
||||||
|
if (!id) {
|
||||||
|
yyerror("failed to read IPv4 address");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
split = strchr(id, '/');
|
||||||
|
if (!split) {
|
||||||
|
yyerror2("invalid IPv4 CIDR notation: %s", id);
|
||||||
|
free(id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*split = '\0';
|
||||||
|
|
||||||
|
rc = inet_pton(AF_INET, id, &addr);
|
||||||
|
if (rc < 1) {
|
||||||
|
yyerror2("failed to parse IPv4 address %s", id);
|
||||||
|
free(id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
mask_bits = strtoul(split + 1, &endptr, 10);
|
||||||
|
if (errno || *endptr != '\0' || mask_bits > 32) {
|
||||||
|
yyerror2("invalid mask in IPv4 CIDR notation: %s", split + 1);
|
||||||
|
free(id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(id);
|
||||||
|
|
||||||
|
if (mask_bits == 0) {
|
||||||
|
yywarn("IPv4 CIDR mask of 0, matching all IPs");
|
||||||
|
mask = 0;
|
||||||
|
} else {
|
||||||
|
mask = ~((UINT32_C(1) << (32 - mask_bits)) - 1);
|
||||||
|
mask = htobe32(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((~mask & addr.s_addr) != 0)
|
||||||
|
yywarn("host bits in IPv4 address set");
|
||||||
|
|
||||||
|
newc = calloc(1, sizeof(ocontext_t));
|
||||||
|
if (!newc) {
|
||||||
|
yyerror("out of memory");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
newc->u.node.addr = addr.s_addr & mask;
|
||||||
|
newc->u.node.mask = mask;
|
||||||
|
|
||||||
|
if (parse_security_context(&newc->context[0])) {
|
||||||
|
free(newc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create order of most specific to least retaining
|
||||||
|
the order specified in the configuration. */
|
||||||
|
head = policydbp->ocontexts[OCON_NODE];
|
||||||
|
for (l = NULL, c = head; c; l = c, c = c->next) {
|
||||||
|
if (newc->u.node.mask > c->u.node.mask)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
newc->next = c;
|
||||||
|
|
||||||
|
if (l)
|
||||||
|
l->next = newc;
|
||||||
|
else
|
||||||
|
policydbp->ocontexts[OCON_NODE] = newc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ipv6_is_mask_contiguous(const struct in6_addr *mask)
|
static int ipv6_is_mask_contiguous(const struct in6_addr *mask)
|
||||||
{
|
{
|
||||||
int filled = 1;
|
int filled = 1;
|
||||||
|
@ -5369,6 +5463,26 @@ static int ipv6_has_host_bits_set(const struct in6_addr *addr, const struct in6_
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ipv6_cidr_bits_to_mask(unsigned long cidr_bits, struct in6_addr *mask)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
if (cidr_bits == 0) {
|
||||||
|
mask->s6_addr32[i] = 0;
|
||||||
|
} else if (cidr_bits >= 32) {
|
||||||
|
mask->s6_addr32[i] = ~UINT32_C(0);
|
||||||
|
} else {
|
||||||
|
mask->s6_addr32[i] = htobe32(~((UINT32_C(1) << (32 - cidr_bits)) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cidr_bits >= 32)
|
||||||
|
cidr_bits -= 32;
|
||||||
|
else
|
||||||
|
cidr_bits = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int define_ipv6_node_context(void)
|
int define_ipv6_node_context(void)
|
||||||
{
|
{
|
||||||
char *id;
|
char *id;
|
||||||
|
@ -5469,6 +5583,99 @@ int define_ipv6_node_context(void)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int define_ipv6_cidr_node_context(void)
|
||||||
|
{
|
||||||
|
char *endptr, *id, *split;
|
||||||
|
unsigned long mask_bits;
|
||||||
|
int rc;
|
||||||
|
struct in6_addr addr, mask;
|
||||||
|
ocontext_t *newc, *c, *l, *head;
|
||||||
|
|
||||||
|
if (policydbp->target_platform != SEPOL_TARGET_SELINUX) {
|
||||||
|
yyerror("nodecon not supported for target");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pass == 1) {
|
||||||
|
free(queue_remove(id_queue));
|
||||||
|
free(queue_remove(id_queue));
|
||||||
|
parse_security_context(NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = queue_remove(id_queue);
|
||||||
|
if (!id) {
|
||||||
|
yyerror("failed to read IPv6 address");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
split = strchr(id, '/');
|
||||||
|
if (!split) {
|
||||||
|
yyerror2("invalid IPv6 CIDR notation: %s", id);
|
||||||
|
free(id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*split = '\0';
|
||||||
|
|
||||||
|
rc = inet_pton(AF_INET6, id, &addr);
|
||||||
|
if (rc < 1) {
|
||||||
|
yyerror2("failed to parse IPv6 address %s", id);
|
||||||
|
free(id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
mask_bits = strtoul(split + 1, &endptr, 10);
|
||||||
|
if (errno || *endptr != '\0' || mask_bits > 128) {
|
||||||
|
yyerror2("invalid mask in IPv6 CIDR notation: %s", split + 1);
|
||||||
|
free(id);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask_bits == 0) {
|
||||||
|
yywarn("IPv6 CIDR mask of 0, matching all IPs");
|
||||||
|
}
|
||||||
|
|
||||||
|
ipv6_cidr_bits_to_mask(mask_bits, &mask);
|
||||||
|
|
||||||
|
if (ipv6_has_host_bits_set(&addr, &mask)) {
|
||||||
|
yywarn("host bits in ipv6 address set");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(id);
|
||||||
|
|
||||||
|
newc = calloc(1, sizeof(ocontext_t));
|
||||||
|
if (!newc) {
|
||||||
|
yyerror("out of memory");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&newc->u.node6.addr[0], &addr.s6_addr[0], 16);
|
||||||
|
memcpy(&newc->u.node6.mask[0], &mask.s6_addr[0], 16);
|
||||||
|
|
||||||
|
if (parse_security_context(&newc->context[0])) {
|
||||||
|
free(newc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create order of most specific to least retaining
|
||||||
|
the order specified in the configuration. */
|
||||||
|
head = policydbp->ocontexts[OCON_NODE6];
|
||||||
|
for (l = NULL, c = head; c; l = c, c = c->next) {
|
||||||
|
if (memcmp(&newc->u.node6.mask, &c->u.node6.mask, 16) > 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
newc->next = c;
|
||||||
|
|
||||||
|
if (l)
|
||||||
|
l->next = newc;
|
||||||
|
else
|
||||||
|
policydbp->ocontexts[OCON_NODE6] = newc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int define_fs_use(int behavior)
|
int define_fs_use(int behavior)
|
||||||
{
|
{
|
||||||
ocontext_t *newc, *c, *head;
|
ocontext_t *newc, *c, *head;
|
||||||
|
|
|
@ -38,7 +38,9 @@ int define_genfs_context(int has_type);
|
||||||
int define_initial_sid_context(void);
|
int define_initial_sid_context(void);
|
||||||
int define_initial_sid(void);
|
int define_initial_sid(void);
|
||||||
int define_ipv4_node_context(void);
|
int define_ipv4_node_context(void);
|
||||||
|
int define_ipv4_cidr_node_context(void);
|
||||||
int define_ipv6_node_context(void);
|
int define_ipv6_node_context(void);
|
||||||
|
int define_ipv6_cidr_node_context(void);
|
||||||
int define_level(void);
|
int define_level(void);
|
||||||
int define_netif_context(void);
|
int define_netif_context(void);
|
||||||
int define_permissive(void);
|
int define_permissive(void);
|
||||||
|
|
|
@ -145,7 +145,9 @@ typedef int (* require_func_t)(int pass);
|
||||||
%token EQUALS
|
%token EQUALS
|
||||||
%token NOTEQUAL
|
%token NOTEQUAL
|
||||||
%token IPV4_ADDR
|
%token IPV4_ADDR
|
||||||
|
%token IPV4_CIDR
|
||||||
%token IPV6_ADDR
|
%token IPV6_ADDR
|
||||||
|
%token IPV6_CIDR
|
||||||
%token MODULE VERSION_IDENTIFIER REQUIRE OPTIONAL
|
%token MODULE VERSION_IDENTIFIER REQUIRE OPTIONAL
|
||||||
%token POLICYCAP
|
%token POLICYCAP
|
||||||
%token PERMISSIVE
|
%token PERMISSIVE
|
||||||
|
@ -739,8 +741,12 @@ node_contexts : node_context_def
|
||||||
;
|
;
|
||||||
node_context_def : NODECON ipv4_addr_def ipv4_addr_def security_context_def
|
node_context_def : NODECON ipv4_addr_def ipv4_addr_def security_context_def
|
||||||
{if (define_ipv4_node_context()) YYABORT;}
|
{if (define_ipv4_node_context()) YYABORT;}
|
||||||
|
| NODECON ipv4_cidr_def security_context_def
|
||||||
|
{if (define_ipv4_cidr_node_context()) YYABORT;}
|
||||||
| NODECON ipv6_addr ipv6_addr security_context_def
|
| NODECON ipv6_addr ipv6_addr security_context_def
|
||||||
{if (define_ipv6_node_context()) YYABORT;}
|
{if (define_ipv6_node_context()) YYABORT;}
|
||||||
|
| NODECON ipv6_cidr security_context_def
|
||||||
|
{if (define_ipv6_cidr_node_context()) YYABORT;}
|
||||||
;
|
;
|
||||||
opt_fs_uses : fs_uses
|
opt_fs_uses : fs_uses
|
||||||
|
|
|
|
||||||
|
@ -771,6 +777,9 @@ genfs_context_def : GENFSCON filesystem path '-' identifier security_context_def
|
||||||
ipv4_addr_def : IPV4_ADDR
|
ipv4_addr_def : IPV4_ADDR
|
||||||
{ if (insert_id(yytext,0)) YYABORT; }
|
{ if (insert_id(yytext,0)) YYABORT; }
|
||||||
;
|
;
|
||||||
|
ipv4_cidr_def : IPV4_CIDR
|
||||||
|
{ if (insert_id(yytext,0)) YYABORT; }
|
||||||
|
;
|
||||||
xperms : xperm
|
xperms : xperm
|
||||||
{ if (insert_separator(0)) YYABORT; }
|
{ if (insert_separator(0)) YYABORT; }
|
||||||
| nested_xperm_set
|
| nested_xperm_set
|
||||||
|
@ -899,6 +908,9 @@ number64 : NUMBER
|
||||||
ipv6_addr : IPV6_ADDR
|
ipv6_addr : IPV6_ADDR
|
||||||
{ if (insert_id(yytext,0)) YYABORT; }
|
{ if (insert_id(yytext,0)) YYABORT; }
|
||||||
;
|
;
|
||||||
|
ipv6_cidr : IPV6_CIDR
|
||||||
|
{ if (insert_id(yytext,0)) YYABORT; }
|
||||||
|
;
|
||||||
policycap_def : POLICYCAP identifier ';'
|
policycap_def : POLICYCAP identifier ';'
|
||||||
{if (define_polcap()) YYABORT;}
|
{if (define_polcap()) YYABORT;}
|
||||||
;
|
;
|
||||||
|
|
|
@ -292,8 +292,10 @@ GLBLUB { return(GLBLUB); }
|
||||||
{letter}({alnum}|[_\-])*([\.]?({alnum}|[_\-]))* { return(IDENTIFIER); }
|
{letter}({alnum}|[_\-])*([\.]?({alnum}|[_\-]))* { return(IDENTIFIER); }
|
||||||
{digit}+|0x{hexval}+ { return(NUMBER); }
|
{digit}+|0x{hexval}+ { return(NUMBER); }
|
||||||
{alnum}*{letter}{alnum}* { return(FILESYSTEM); }
|
{alnum}*{letter}{alnum}* { return(FILESYSTEM); }
|
||||||
|
{digit}{1,3}(\.{digit}{1,3}){3}"/"{digit}{1,2} { return(IPV4_CIDR); }
|
||||||
{digit}{1,3}(\.{digit}{1,3}){3} { return(IPV4_ADDR); }
|
{digit}{1,3}(\.{digit}{1,3}){3} { return(IPV4_ADDR); }
|
||||||
{hexval}{0,4}":"{hexval}{0,4}":"({hexval}|[:.])* { return(IPV6_ADDR); }
|
{hexval}{0,4}":"{hexval}{0,4}":"({hexval}|[:.])* { return(IPV6_ADDR); }
|
||||||
|
{hexval}{0,4}":"{hexval}{0,4}":"({hexval}|[:.])*"/"{digit}{1,3} { return(IPV6_CIDR); }
|
||||||
{digit}+(\.({alnum}|[_.])*)? { return(VERSION_IDENTIFIER); }
|
{digit}+(\.({alnum}|[_.])*)? { return(VERSION_IDENTIFIER); }
|
||||||
#line[ ]1[ ]\"[^\n]*\" { set_source_file(yytext+9); }
|
#line[ ]1[ ]\"[^\n]*\" { set_source_file(yytext+9); }
|
||||||
#line[ ]{digit}+ {
|
#line[ ]{digit}+ {
|
||||||
|
|
|
@ -71,7 +71,9 @@ portcon tcp 80 USER1:ROLE1:TYPE1
|
||||||
portcon udp 100-200 USER1:ROLE1:TYPE1
|
portcon udp 100-200 USER1:ROLE1:TYPE1
|
||||||
netifcon lo USER1:ROLE1:TYPE1 USER1:ROLE1:TYPE1
|
netifcon lo USER1:ROLE1:TYPE1 USER1:ROLE1:TYPE1
|
||||||
nodecon 127.0.0.1 255.255.255.255 USER1:ROLE1:TYPE1
|
nodecon 127.0.0.1 255.255.255.255 USER1:ROLE1:TYPE1
|
||||||
|
nodecon 127.0.0.0/24 USER1:ROLE1:TYPE1
|
||||||
nodecon ::ffff:127.0.0.1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff USER1:ROLE1:TYPE1
|
nodecon ::ffff:127.0.0.1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff USER1:ROLE1:TYPE1
|
||||||
|
nodecon ff80::/16 USER1:ROLE1:TYPE1
|
||||||
# hex numbers will be turned in decimal ones
|
# hex numbers will be turned in decimal ones
|
||||||
ibpkeycon fe80:: 0xFFFF USER1:ROLE1:TYPE1
|
ibpkeycon fe80:: 0xFFFF USER1:ROLE1:TYPE1
|
||||||
ibpkeycon fe80:: 0-0x10 USER1:ROLE1:TYPE1
|
ibpkeycon fe80:: 0-0x10 USER1:ROLE1:TYPE1
|
||||||
|
|
|
@ -71,7 +71,9 @@ portcon tcp 80 USER1:ROLE1:TYPE1
|
||||||
portcon udp 100-200 USER1:ROLE1:TYPE1
|
portcon udp 100-200 USER1:ROLE1:TYPE1
|
||||||
netifcon lo USER1:ROLE1:TYPE1 USER1:ROLE1:TYPE1
|
netifcon lo USER1:ROLE1:TYPE1 USER1:ROLE1:TYPE1
|
||||||
nodecon 127.0.0.1 255.255.255.255 USER1:ROLE1:TYPE1
|
nodecon 127.0.0.1 255.255.255.255 USER1:ROLE1:TYPE1
|
||||||
|
nodecon 127.0.0.0 255.255.255.0 USER1:ROLE1:TYPE1
|
||||||
nodecon ::ffff:127.0.0.1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff USER1:ROLE1:TYPE1
|
nodecon ::ffff:127.0.0.1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff USER1:ROLE1:TYPE1
|
||||||
|
nodecon ff80:: ffff:: USER1:ROLE1:TYPE1
|
||||||
ibpkeycon fe80:: 65535 USER1:ROLE1:TYPE1
|
ibpkeycon fe80:: 65535 USER1:ROLE1:TYPE1
|
||||||
ibpkeycon fe80:: 0-16 USER1:ROLE1:TYPE1
|
ibpkeycon fe80:: 0-16 USER1:ROLE1:TYPE1
|
||||||
ibendportcon mlx4_0 2 USER1:ROLE1:TYPE1
|
ibendportcon mlx4_0 2 USER1:ROLE1:TYPE1
|
||||||
|
|
|
@ -71,7 +71,9 @@ portcon tcp 80 USER1:ROLE1:TYPE1
|
||||||
portcon udp 100-200 USER1:ROLE1:TYPE1
|
portcon udp 100-200 USER1:ROLE1:TYPE1
|
||||||
netifcon lo USER1:ROLE1:TYPE1 USER1:ROLE1:TYPE1
|
netifcon lo USER1:ROLE1:TYPE1 USER1:ROLE1:TYPE1
|
||||||
nodecon 127.0.0.1 255.255.255.255 USER1:ROLE1:TYPE1
|
nodecon 127.0.0.1 255.255.255.255 USER1:ROLE1:TYPE1
|
||||||
|
nodecon 127.0.0.0 255.255.255.0 USER1:ROLE1:TYPE1
|
||||||
nodecon ::ffff:127.0.0.1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff USER1:ROLE1:TYPE1
|
nodecon ::ffff:127.0.0.1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff USER1:ROLE1:TYPE1
|
||||||
|
nodecon ff80:: ffff:: USER1:ROLE1:TYPE1
|
||||||
ibpkeycon fe80:: 65535 USER1:ROLE1:TYPE1
|
ibpkeycon fe80:: 65535 USER1:ROLE1:TYPE1
|
||||||
ibpkeycon fe80:: 0-16 USER1:ROLE1:TYPE1
|
ibpkeycon fe80:: 0-16 USER1:ROLE1:TYPE1
|
||||||
ibendportcon mlx4_0 2 USER1:ROLE1:TYPE1
|
ibendportcon mlx4_0 2 USER1:ROLE1:TYPE1
|
||||||
|
|
Loading…
Reference in New Issue