mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
Add network.c, network.h, missing from previous ci
This commit is contained in:
parent
d3c229fc48
commit
54655cf9a4
2 changed files with 414 additions and 0 deletions
336
parser/network.c
Normal file
336
parser/network.c
Normal file
|
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#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("<all>\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");
|
||||
}
|
78
parser/network.h
Normal file
78
parser/network.h
Normal file
|
@ -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 <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/limits.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#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 */
|
Loading…
Add table
Reference in a new issue