From 54655cf9a49f61f07fdb5b6dde823550f0ce133a Mon Sep 17 00:00:00 2001 From: John Johansen Date: Sat, 23 Aug 2014 23:55:12 -0700 Subject: [PATCH] Add network.c, network.h, missing from previous ci --- parser/network.c | 336 +++++++++++++++++++++++++++++++++++++++++++++++ parser/network.h | 78 +++++++++++ 2 files changed, 414 insertions(+) create mode 100644 parser/network.c create mode 100644 parser/network.h diff --git a/parser/network.c b/parser/network.c new file mode 100644 index 000000000..e439f22cc --- /dev/null +++ b/parser/network.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2014 + * Canonical, Ltd. (All rights reserved) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact Novell, Inc. or Canonical + * Ltd. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "parser.h" +#include "profile.h" +#include "parser_yacc.h" +#include "network.h" + + +/* Bleah C++ doesn't have non-trivial designated initializers so we just + * have to make sure these are in order. This means we are more brittle + * but there isn't much we can do. + */ +const char *sock_types[] = { + "none", /* 0 */ + "stream", /* 1 [SOCK_STREAM] */ + "dgram", /* 2 [SOCK_DGRAM] */ + "raw", /* 3 [SOCK_RAW] */ + "rdm", /* 4 [SOCK_RDM] */ + "seqpacket", /* 5 [SOCK_SEQPACKET] */ + "dccp", /* 6 [SOCK_DCCP] */ + "invalid", /* 7 */ + "invalid", /* 8 */ + "invalid", /* 9 */ + "packet", /* 10 [SOCK_PACKET] */ + /* + * See comment above + */ +}; + +struct network_tuple { + const char *family_name; + unsigned int family; + const char *type_name; + unsigned int type; + const char *protocol_name; + unsigned int protocol; +}; + +/* FIXME: currently just treating as a bit mask this will have to change + * set up a table of mappings, there can be several mappings for a + * given match. + * currently the mapping does not set the protocol for stream/dgram to + * anything other than 0. + * network inet tcp -> network inet stream 0 instead of + * network inet raw tcp. + * some entries are just provided for completeness at this time + */ +/* values stolen from /etc/protocols - needs to change */ +#define RAW_TCP 6 +#define RAW_UDP 17 +#define RAW_ICMP 1 +#define RAW_ICMPv6 58 + +/* used by af_name.h to auto generate table entries for "name", AF_NAME + * pair */ +#define AA_GEN_NET_ENT(name, AF) \ + {name, AF, "stream", SOCK_STREAM, "", 0xffffff}, \ + {name, AF, "dgram", SOCK_DGRAM, "", 0xffffff}, \ + {name, AF, "seqpacket", SOCK_SEQPACKET, "", 0xffffff}, \ + {name, AF, "rdm", SOCK_RDM, "", 0xffffff}, \ + {name, AF, "raw", SOCK_RAW, "", 0xffffff}, \ + {name, AF, "packet", SOCK_PACKET, "", 0xffffff}, +/*FIXME: missing {name, AF, "dccp", SOCK_DCCP, "", 0xfffffff}, */ + +static struct network_tuple network_mappings[] = { + /* basic types */ + #include "af_names.h" +/* FIXME: af_names.h is missing AF_LLC, AF_TIPC */ + /* mapped types */ + {"inet", AF_INET, "raw", SOCK_RAW, + "tcp", 1 << RAW_TCP}, + {"inet", AF_INET, "raw", SOCK_RAW, + "udp", 1 << RAW_UDP}, + {"inet", AF_INET, "raw", SOCK_RAW, + "icmp", 1 << RAW_ICMP}, + {"inet", AF_INET, "tcp", SOCK_STREAM, + "", 0xffffffff}, /* should we give raw tcp too? */ + {"inet", AF_INET, "udp", SOCK_DGRAM, + "", 0xffffffff}, /* should these be open masks? */ + {"inet", AF_INET, "icmp", SOCK_RAW, + "", 1 << RAW_ICMP}, + {"inet6", AF_INET6, "tcp", SOCK_STREAM, + "", 0xffffffff}, + {"inet6", AF_INET6, "udp", SOCK_DGRAM, + "", 0xffffffff}, +/* what do we do with icmp on inet6? + {"inet6", AF_INET, "icmp", SOCK_RAW, 0}, + {"inet6", AF_INET, "icmpv6", SOCK_RAW, 0}, +*/ + /* terminate */ + {NULL, 0, NULL, 0, NULL, 0} +}; + +/* The apparmor kernel patches up until 2.6.38 didn't handle networking + * tables with sizes > AF_MAX correctly. This could happen when the + * parser was built against newer kernel headers and then used to load + * policy on an older kernel. This could happen during upgrades or + * in multi-kernel boot systems. + * + * Try to detect the running kernel version and use that to determine + * AF_MAX + */ +#define PROC_VERSION "/proc/sys/kernel/osrelease" +static size_t kernel_af_max(void) { + char buffer[32]; + int major; + int fd, res; + + if (!net_af_max_override) { + return 0; + } + /* the override parameter is specifying the max value */ + if (net_af_max_override > 0) + return net_af_max_override; + + fd = open(PROC_VERSION, O_RDONLY); + if (!fd) + /* fall back to default provided during build */ + return 0; + res = read(fd, &buffer, sizeof(buffer) - 1); + close(fd); + if (res <= 0) + return 0; + buffer[res] = '\0'; + res = sscanf(buffer, "2.6.%d", &major); + if (res != 1) + return 0; + + switch(major) { + case 24: + case 25: + case 26: + return 34; + case 27: + return 35; + case 28: + case 29: + case 30: + return 36; + case 31: + case 32: + case 33: + case 34: + case 35: + return 37; + case 36: + case 37: + return 38; + /* kernels .38 and later should handle this correctly so no + * static mapping needed + */ + default: + return 0; + } +} + +/* Yuck. We grab AF_* values to define above from linux/socket.h because + * they are more accurate than sys/socket.h for what the kernel actually + * supports. However, we can't just include linux/socket.h directly, + * because the AF_* definitions are protected with an ifdef KERNEL + * wrapper, but we don't want to define that because that can cause + * other redefinitions from glibc. However, because the kernel may have + * more definitions than glibc, we need make sure AF_MAX reflects this, + * hence the wrapping function. + */ +size_t get_af_max() { + size_t af_max; + /* HACK: declare that version without "create" had a static AF_MAX */ + if (!perms_create && !net_af_max_override) + net_af_max_override = -1; + +#if AA_AF_MAX > AF_MAX + af_max = AA_AF_MAX; +#else + af_max = AF_MAX; +#endif + + /* HACK: some kernels didn't handle network tables from parsers + * compiled against newer kernel headers as they are larger than + * the running kernel expected. If net_override is defined check + * to see if there is a static max specified for that kernel + */ + if (net_af_max_override) { + size_t max = kernel_af_max(); + if (max && max < af_max) + return max; + } + + return af_max; +} +struct aa_network_entry *new_network_ent(unsigned int family, + unsigned int type, + unsigned int protocol) +{ + struct aa_network_entry *new_entry; + new_entry = (struct aa_network_entry *) calloc(1, sizeof(struct aa_network_entry)); + if (new_entry) { + new_entry->family = family; + new_entry->type = type; + new_entry->protocol = protocol; + new_entry->next = NULL; + } + return new_entry; +} + +struct aa_network_entry *network_entry(const char *family, const char *type, + const char *protocol) +{ + int i; + struct aa_network_entry *new_entry, *entry = NULL; + + for (i = 0; network_mappings[i].family_name; i++) { + if (family) { + PDEBUG("Checking family %s\n", network_mappings[i].family_name); + if (strcmp(family, network_mappings[i].family_name) != 0) + continue; + PDEBUG("Found family %s\n", family); + } + if (type) { + PDEBUG("Checking type %s\n", network_mappings[i].type_name); + if (strcmp(type, network_mappings[i].type_name) != 0) + continue; + PDEBUG("Found type %s\n", type); + } + if (protocol) { + PDEBUG("Checking protocol %s\n", network_mappings[i].protocol_name); + if (strcmp(protocol, network_mappings[i].protocol_name) != 0) + continue; + /* fixme should we allow specifying protocol by # + * without needing the protocol mapping? */ + } + /* if here we have a match */ + new_entry = new_network_ent(network_mappings[i].family, + network_mappings[i].type, + network_mappings[i].protocol); + if (!new_entry) + yyerror(_("Memory allocation error.")); + new_entry->next = entry; + entry = new_entry; + } + + return entry; +}; + +#define ALL_TYPES 0x43e + +/* another case of C++ not supporting non-trivial designated initializers */ +#undef AA_GEN_NET_ENT +#define AA_GEN_NET_ENT(name, AF) name, /* [AF] = name, */ + +static const char *network_families[] = { +#include "af_names.h" +}; + +void __debug_network(unsigned int *array, const char *name) +{ + unsigned int count = sizeof(sock_types)/sizeof(sock_types[0]); + unsigned int mask = ~((1 << count) -1); + unsigned int i, j; + int none = 1; + size_t af_max = get_af_max(); + + for (i = AF_UNSPEC; i < af_max; i++) + if (array[i]) { + none = 0; + break; + } + + if (none) + return; + + printf("%s: ", name); + + /* This can only be set by an unqualified network rule */ + if (array[AF_UNSPEC]) { + printf("\n"); + return; + } + + for (i = 0; i < af_max; i++) { + if (array[i]) { + const char *fam = network_families[i]; + if (fam) + printf("%s ", fam); + else + printf("#%u ", i); + + /* All types/protocols */ + if (array[i] == 0xffffffff || array[i] == ALL_TYPES) + continue; + + printf("{ "); + + for (j = 0; j < count; j++) { + const char *type; + if (array[i] & (1 << j)) { + type = sock_types[j]; + if (type) + printf("%s ", type); + else + printf("#%u ", j); + } + } + if (array[i] & mask) + printf("#%x ", array[i] & mask); + + printf("} "); + } + } + printf("\n"); +} diff --git a/parser/network.h b/parser/network.h new file mode 100644 index 000000000..a76e3ea10 --- /dev/null +++ b/parser/network.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014 + * Canonical, Ltd. (All rights reserved) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, contact Novell, Inc. or Canonical + * Ltd. + */ + +#ifndef __AA_NETWORK_H +#define __AA_NETWORK_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "parser.h" +#include "rule.h" +#include "profile.h" + +/* supported AF protocols */ +struct aa_network_entry { + unsigned int family; + unsigned int type; + unsigned int protocol; + + struct aa_network_entry *next; +}; + +extern struct aa_network_entry *new_network_ent(unsigned int family, + unsigned int type, + unsigned int protocol); +extern struct aa_network_entry *network_entry(const char *family, + const char *type, + const char *protocol); +extern size_t get_af_max(void); + +void __debug_network(unsigned int *array, const char *name); + +struct network { + unsigned int *allow; /* array of type masks + * indexed by AF_FAMILY */ + unsigned int *audit; + unsigned int *deny; + unsigned int *quiet; + + network(void) { allow = audit = deny = quiet = NULL; } + + void dump(void) { + if (allow) + __debug_network(allow, "Network"); + if (audit) + __debug_network(audit, "Audit Net"); + if (deny) + __debug_network(deny, "Deny Net"); + if (quiet) + __debug_network(quiet, "Quiet Net"); + } +}; + +#endif /* __AA_NETWORK_H */