mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
parser: refactor network to use rule class as its base.
There is one significant difference in the encoding of the network rules. Before this change, when the parser was encoding a "network," rule, it would generate an entry for every family and every type/protocol. After this patch the parser should generate an entry for every family, but the type/protocol is changed to .. in the pcre syntax. There should be no difference in behavior. Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
This commit is contained in:
parent
11976c42e3
commit
820f1fb5f2
10 changed files with 315 additions and 301 deletions
|
@ -99,7 +99,7 @@ EXTRA_CFLAGS+=-DPACKAGE=\"${NAME}\" -DLOCALEDIR=\"${LOCALEDIR}\"
|
||||||
SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
|
SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
|
||||||
parser_main.c parser_misc.c parser_merge.c parser_symtab.c \
|
parser_main.c parser_misc.c parser_merge.c parser_symtab.c \
|
||||||
parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
|
parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
|
||||||
parser_alias.c common_optarg.c lib.c network.c \
|
parser_alias.c common_optarg.c lib.c network.cc \
|
||||||
mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \
|
mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \
|
||||||
af_rule.cc af_unix.cc policy_cache.c default_features.c userns.cc \
|
af_rule.cc af_unix.cc policy_cache.c default_features.c userns.cc \
|
||||||
mqueue.cc io_uring.cc
|
mqueue.cc io_uring.cc
|
||||||
|
@ -295,7 +295,7 @@ signal.o: signal.cc $(HDRS)
|
||||||
ptrace.o: ptrace.cc $(HDRS)
|
ptrace.o: ptrace.cc $(HDRS)
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
network.o: network.c $(HDRS)
|
network.o: network.cc $(HDRS)
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
default_features.o: default_features.c $(HDRS)
|
default_features.o: default_features.c $(HDRS)
|
||||||
|
|
|
@ -108,6 +108,9 @@ unix_rule::unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode
|
||||||
perms = AA_VALID_NET_PERMS;
|
perms = AA_VALID_NET_PERMS;
|
||||||
audit = audit_p;
|
audit = audit_p;
|
||||||
rule_mode = rule_mode_p;
|
rule_mode = rule_mode_p;
|
||||||
|
/* if this constructor is used, then there's already a
|
||||||
|
* downgraded network_rule in profile */
|
||||||
|
downgrade = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unix_rule::unix_rule(perms_t perms_p, struct cond_entry *conds,
|
unix_rule::unix_rule(perms_t perms_p, struct cond_entry *conds,
|
||||||
|
@ -190,7 +193,7 @@ static void writeu16(std::ostringstream &o, int v)
|
||||||
void unix_rule::downgrade_rule(Profile &prof) {
|
void unix_rule::downgrade_rule(Profile &prof) {
|
||||||
perms_t mask = (perms_t) -1;
|
perms_t mask = (perms_t) -1;
|
||||||
|
|
||||||
if (!prof.net.allow && !prof.alloc_net_table())
|
if (!prof.net.allow && !prof.net.alloc_net_table())
|
||||||
yyerror(_("Memory allocation error."));
|
yyerror(_("Memory allocation error."));
|
||||||
if (sock_type_n != -1)
|
if (sock_type_n != -1)
|
||||||
mask = 1 << sock_type_n;
|
mask = 1 << sock_type_n;
|
||||||
|
@ -198,6 +201,11 @@ void unix_rule::downgrade_rule(Profile &prof) {
|
||||||
prof.net.allow[AF_UNIX] |= mask;
|
prof.net.allow[AF_UNIX] |= mask;
|
||||||
if (audit == AUDIT_FORCE)
|
if (audit == AUDIT_FORCE)
|
||||||
prof.net.audit[AF_UNIX] |= mask;
|
prof.net.audit[AF_UNIX] |= mask;
|
||||||
|
const char *error;
|
||||||
|
network_rule *netv8 = new network_rule(AF_UNIX, sock_type_n);
|
||||||
|
if(!netv8->add_prefix({audit, rule_mode, owner}, error))
|
||||||
|
yyerror(error);
|
||||||
|
prof.rule_ents.push_back(netv8);
|
||||||
} else {
|
} else {
|
||||||
/* deny rules have to be dropped because the downgrade makes
|
/* deny rules have to be dropped because the downgrade makes
|
||||||
* the rule less specific meaning it will make the profile more
|
* the rule less specific meaning it will make the profile more
|
||||||
|
@ -317,7 +325,8 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||||
* older kernels and be enforced to the best of the old network
|
* older kernels and be enforced to the best of the old network
|
||||||
* rules ability
|
* rules ability
|
||||||
*/
|
*/
|
||||||
downgrade_rule(prof);
|
if (downgrade)
|
||||||
|
downgrade_rule(prof);
|
||||||
if (!features_supports_unix) {
|
if (!features_supports_unix) {
|
||||||
if (features_supports_network || features_supports_networkv8) {
|
if (features_supports_network || features_supports_networkv8) {
|
||||||
/* only warn if we are building against a kernel
|
/* only warn if we are building against a kernel
|
||||||
|
|
|
@ -36,6 +36,7 @@ class unix_rule: public af_rule {
|
||||||
public:
|
public:
|
||||||
char *addr;
|
char *addr;
|
||||||
char *peer_addr;
|
char *peer_addr;
|
||||||
|
bool downgrade = true;
|
||||||
|
|
||||||
unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p);
|
unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p);
|
||||||
unix_rule(perms_t perms, struct cond_entry *conds,
|
unix_rule(perms_t perms, struct cond_entry *conds,
|
||||||
|
|
|
@ -16,10 +16,6 @@
|
||||||
* Ltd.
|
* Ltd.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/apparmor.h>
|
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -28,9 +24,9 @@
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "profile.h"
|
#include "profile.h"
|
||||||
#include "parser_yacc.h"
|
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
|
||||||
|
#define ALL_TYPES 0x43e
|
||||||
|
|
||||||
int parse_net_perms(const char *str_mode, perms_t *mode, int fail)
|
int parse_net_perms(const char *str_mode, perms_t *mode, int fail)
|
||||||
{
|
{
|
||||||
|
@ -119,7 +115,7 @@ static struct network_tuple network_mappings[] = {
|
||||||
/* FIXME: af_names.h is missing AF_LLC, AF_TIPC */
|
/* FIXME: af_names.h is missing AF_LLC, AF_TIPC */
|
||||||
/* mapped types */
|
/* mapped types */
|
||||||
{"inet", AF_INET, "raw", SOCK_RAW,
|
{"inet", AF_INET, "raw", SOCK_RAW,
|
||||||
"tcp", 1 << RAW_TCP},
|
"tcp", 1 << RAW_TCP},
|
||||||
{"inet", AF_INET, "raw", SOCK_RAW,
|
{"inet", AF_INET, "raw", SOCK_RAW,
|
||||||
"udp", 1 << RAW_UDP},
|
"udp", 1 << RAW_UDP},
|
||||||
{"inet", AF_INET, "raw", SOCK_RAW,
|
{"inet", AF_INET, "raw", SOCK_RAW,
|
||||||
|
@ -239,21 +235,21 @@ size_t get_af_max() {
|
||||||
|
|
||||||
return af_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const char *net_find_af_name(unsigned int af)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (af < 0 || af > get_af_max())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(network_mappings) / sizeof(*network_mappings); i++) {
|
||||||
|
if (network_mappings[i].family == af)
|
||||||
|
return network_mappings[i].family_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
const struct network_tuple *net_find_mapping(const struct network_tuple *map,
|
const struct network_tuple *net_find_mapping(const struct network_tuple *map,
|
||||||
const char *family,
|
const char *family,
|
||||||
|
@ -302,95 +298,225 @@ const struct network_tuple *net_find_mapping(const struct network_tuple *map,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct aa_network_entry *network_entry(const char *family, const char *type,
|
void network_rule::set_netperm(unsigned int family, unsigned int type)
|
||||||
const char *protocol)
|
|
||||||
{
|
{
|
||||||
struct aa_network_entry *new_entry, *entry = NULL;
|
if (type > SOCK_PACKET) {
|
||||||
const struct network_tuple *mapping = NULL;
|
/* setting mask instead of a bit */
|
||||||
|
network_perms[family] |= type;
|
||||||
while ((mapping = net_find_mapping(mapping, family, type, protocol))) {
|
} else
|
||||||
new_entry = new_network_ent(mapping->family, mapping->type,
|
network_perms[family] |= 1 << type;
|
||||||
mapping->protocol);
|
|
||||||
if (!new_entry)
|
|
||||||
yyerror(_("Memory allocation error."));
|
|
||||||
new_entry->next = entry;
|
|
||||||
entry = new_entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define ALL_TYPES 0x43e
|
|
||||||
|
|
||||||
const char *net_find_af_name(unsigned int af)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if (af < 0 || af > get_af_max())
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(network_mappings) / sizeof(*network_mappings); i++) {
|
|
||||||
if (network_mappings[i].family == af)
|
|
||||||
return network_mappings[i].family_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void __debug_network(unsigned int *array, const char *name)
|
network_rule::network_rule(const char *family, const char *type,
|
||||||
|
const char *protocol):
|
||||||
|
perms_rule_t(AA_CLASS_NETV8)
|
||||||
{
|
{
|
||||||
|
if (!family && !type && !protocol) {
|
||||||
|
size_t family_index;
|
||||||
|
for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) {
|
||||||
|
network_map[family_index].push_back({ family_index, 0xFFFFFFFF, 0xFFFFFFFF });
|
||||||
|
set_netperm(family_index, 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const struct network_tuple *mapping = NULL;
|
||||||
|
while ((mapping = net_find_mapping(mapping, family, type, protocol))) {
|
||||||
|
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
|
||||||
|
set_netperm(mapping->family, mapping->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == NULL && network_map.empty()) {
|
||||||
|
while ((mapping = net_find_mapping(mapping, type, family, protocol))) {
|
||||||
|
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
|
||||||
|
set_netperm(mapping->family, mapping->type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (network_map.empty())
|
||||||
|
yyerror(_("Invalid network entry."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
network_rule::network_rule(unsigned int family, unsigned int type):
|
||||||
|
perms_rule_t(AA_CLASS_NETV8)
|
||||||
|
{
|
||||||
|
network_map[family].push_back({ family, type, 0xFFFFFFFF });
|
||||||
|
set_netperm(family, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
ostream &network_rule::dump(ostream &os)
|
||||||
|
{
|
||||||
|
class_rule_t::dump(os);
|
||||||
|
|
||||||
unsigned int count = sizeof(sock_types)/sizeof(sock_types[0]);
|
unsigned int count = sizeof(sock_types)/sizeof(sock_types[0]);
|
||||||
unsigned int mask = ~((1 << count) -1);
|
unsigned int mask = ~((1 << count) -1);
|
||||||
unsigned int i, j;
|
unsigned int 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 */
|
/* This can only be set by an unqualified network rule */
|
||||||
if (array[AF_UNSPEC]) {
|
if (network_map.find(AF_UNSPEC) != network_map.end()) {
|
||||||
printf("<all>\n");
|
os << ",\n";
|
||||||
return;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < af_max; i++) {
|
for (const auto& perm : network_perms) {
|
||||||
if (array[i]) {
|
unsigned int family = perm.first;
|
||||||
const char *fam = net_find_af_name(i);
|
unsigned int type = perm.second;
|
||||||
if (fam)
|
|
||||||
printf("%s ", fam);
|
|
||||||
else
|
|
||||||
printf("#%u ", i);
|
|
||||||
|
|
||||||
/* All types/protocols */
|
const char *family_name = net_find_af_name(family);
|
||||||
if (array[i] == 0xffffffff || array[i] == ALL_TYPES)
|
if (family_name)
|
||||||
continue;
|
os << " " << family_name;
|
||||||
|
else
|
||||||
|
os << " #" << family;
|
||||||
|
|
||||||
printf("{ ");
|
/* All types/protocols */
|
||||||
|
if (type == 0xffffffff || type == ALL_TYPES)
|
||||||
|
continue;
|
||||||
|
|
||||||
for (j = 0; j < count; j++) {
|
printf(" {");
|
||||||
const char *type;
|
|
||||||
if (array[i] & (1 << j)) {
|
for (j = 0; j < count; j++) {
|
||||||
type = sock_types[j].name;
|
const char *type_name;
|
||||||
if (type)
|
if (type & (1 << j)) {
|
||||||
printf("%s ", type);
|
type_name = sock_types[j].name;
|
||||||
else
|
if (type_name)
|
||||||
printf("#%u ", j);
|
os << " " << type_name;
|
||||||
|
else
|
||||||
|
os << " #" << j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type & mask)
|
||||||
|
os << " #" << std::hex << (type & mask);
|
||||||
|
|
||||||
|
printf(" }");
|
||||||
|
}
|
||||||
|
|
||||||
|
os << ",\n";
|
||||||
|
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int network_rule::expand_variables(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void network_rule::warn_once(const char *name)
|
||||||
|
{
|
||||||
|
rule_t::warn_once(name, "network rules not enforced");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mask) {
|
||||||
|
std::ostringstream buffer;
|
||||||
|
std::string buf;
|
||||||
|
|
||||||
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_NETV8;
|
||||||
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((family & 0xff00) >> 8);
|
||||||
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (family & 0xff);
|
||||||
|
if (type_mask > 0xffff) {
|
||||||
|
buffer << "..";
|
||||||
|
} else {
|
||||||
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((type_mask & 0xff00) >> 8);
|
||||||
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (type_mask & 0xff);
|
||||||
|
}
|
||||||
|
buf = buffer.str();
|
||||||
|
|
||||||
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(AA_VALID_NET_PERMS),
|
||||||
|
perms_rule_t::audit == AUDIT_FORCE ? map_perms(AA_VALID_NET_PERMS) : 0,
|
||||||
|
parseopts))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int network_rule::gen_policy_re(Profile &prof)
|
||||||
|
{
|
||||||
|
std::ostringstream buffer;
|
||||||
|
std::string buf;
|
||||||
|
|
||||||
|
if (!features_supports_networkv8) {
|
||||||
|
warn_once(prof.name);
|
||||||
|
return RULE_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& perm : network_perms) {
|
||||||
|
unsigned int family = perm.first;
|
||||||
|
unsigned int type = perm.second;
|
||||||
|
|
||||||
|
if (type > 0xffff) {
|
||||||
|
if (!gen_net_rule(prof, family, type))
|
||||||
|
goto fail;
|
||||||
|
} else {
|
||||||
|
int t;
|
||||||
|
/* generate rules for types that are set */
|
||||||
|
for (t = 0; t < 16; t++) {
|
||||||
|
if (type & (1 << t)) {
|
||||||
|
if (!gen_net_rule(prof, family, t))
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (array[i] & mask)
|
}
|
||||||
printf("#%x ", array[i] & mask);
|
|
||||||
|
|
||||||
printf("} ");
|
}
|
||||||
|
return RULE_OK;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return RULE_ERROR;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize static members */
|
||||||
|
unsigned int *network_rule::allow = NULL;
|
||||||
|
unsigned int *network_rule::audit = NULL;
|
||||||
|
unsigned int *network_rule::deny = NULL;
|
||||||
|
unsigned int *network_rule::quiet = NULL;
|
||||||
|
|
||||||
|
bool network_rule::alloc_net_table()
|
||||||
|
{
|
||||||
|
if (allow)
|
||||||
|
return true;
|
||||||
|
allow = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
||||||
|
audit = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
||||||
|
deny = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
||||||
|
quiet = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
||||||
|
if (!allow || !audit || !deny || !quiet)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update is required because at the point of the creation of the
|
||||||
|
* network_rule object, we don't have owner, rule_mode, or audit
|
||||||
|
* set.
|
||||||
|
*/
|
||||||
|
void network_rule::update_compat_net(void)
|
||||||
|
{
|
||||||
|
if (!alloc_net_table())
|
||||||
|
yyerror(_("Memory allocation error."));
|
||||||
|
|
||||||
|
for (auto& nm: network_map) {
|
||||||
|
for (auto& entry : nm.second) {
|
||||||
|
if (entry.type > SOCK_PACKET) {
|
||||||
|
/* setting mask instead of a bit */
|
||||||
|
if (rule_mode == RULE_DENY) {
|
||||||
|
deny[entry.family] |= entry.type;
|
||||||
|
if (dedup_perms_rule_t::audit != AUDIT_FORCE)
|
||||||
|
quiet[entry.family] |= entry.type;
|
||||||
|
} else {
|
||||||
|
allow[entry.family] |= entry.type;
|
||||||
|
if (dedup_perms_rule_t::audit == AUDIT_FORCE)
|
||||||
|
audit[entry.family] |= entry.type;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (rule_mode == RULE_DENY) {
|
||||||
|
deny[entry.family] |= 1 << entry.type;
|
||||||
|
if (dedup_perms_rule_t::audit != AUDIT_FORCE)
|
||||||
|
quiet[entry.family] |= 1 << entry.type;
|
||||||
|
} else {
|
||||||
|
allow[entry.family] |= 1 << entry.type;
|
||||||
|
if (dedup_perms_rule_t::audit == AUDIT_FORCE)
|
||||||
|
audit[entry.family] |= 1 << entry.type;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
104
parser/network.h
104
parser/network.h
|
@ -29,6 +29,8 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "rule.h"
|
#include "rule.h"
|
||||||
|
@ -82,13 +84,10 @@ struct network_tuple {
|
||||||
unsigned int protocol;
|
unsigned int protocol;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* supported AF protocols */
|
|
||||||
struct aa_network_entry {
|
struct aa_network_entry {
|
||||||
unsigned int family;
|
long unsigned int family;
|
||||||
unsigned int type;
|
unsigned int type;
|
||||||
unsigned int protocol;
|
unsigned int protocol;
|
||||||
|
|
||||||
struct aa_network_entry *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline uint32_t map_perms(uint32_t mask)
|
static inline uint32_t map_perms(uint32_t mask)
|
||||||
|
@ -99,45 +98,70 @@ static inline uint32_t map_perms(uint32_t mask)
|
||||||
((mask & (AA_NET_SETOPT | AA_NET_GETOPT)) >> 5); /* 5 + (AA_OTHER_SHIFT - 24) */
|
((mask & (AA_NET_SETOPT | AA_NET_GETOPT)) >> 5); /* 5 + (AA_OTHER_SHIFT - 24) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int parse_net_perms(const char *str_mode, perms_t *perms, int fail);
|
int parse_net_perms(const char *str_mode, perms_t *perms, int fail);
|
||||||
extern struct aa_network_entry *new_network_ent(unsigned int family,
|
size_t get_af_max();
|
||||||
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");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int net_find_type_val(const char *type);
|
int net_find_type_val(const char *type);
|
||||||
const char *net_find_type_name(int type);
|
const char *net_find_type_name(int type);
|
||||||
const char *net_find_af_name(unsigned int af);
|
const char *net_find_af_name(unsigned int af);
|
||||||
const struct network_tuple *net_find_mapping(const struct network_tuple *map,
|
|
||||||
const char *family,
|
class network_rule: public perms_rule_t {
|
||||||
const char *type,
|
public:
|
||||||
const char *protocol);
|
std::unordered_map<unsigned int, std::vector<struct aa_network_entry>> network_map;
|
||||||
|
std::unordered_map<unsigned int, perms_t> network_perms;
|
||||||
|
|
||||||
|
/* empty constructor used only for the profile to access
|
||||||
|
* static elements to maintain compatibility with
|
||||||
|
* AA_CLASS_NET */
|
||||||
|
network_rule(): perms_rule_t(AA_CLASS_NETV8) { }
|
||||||
|
network_rule(const char *family, const char *type,
|
||||||
|
const char *protocol);
|
||||||
|
network_rule(unsigned int family, unsigned int type);
|
||||||
|
virtual ~network_rule()
|
||||||
|
{
|
||||||
|
if (allow) {
|
||||||
|
free(allow);
|
||||||
|
allow = NULL;
|
||||||
|
}
|
||||||
|
if (audit) {
|
||||||
|
free(audit);
|
||||||
|
audit = NULL;
|
||||||
|
}
|
||||||
|
if (deny) {
|
||||||
|
free(deny);
|
||||||
|
deny = NULL;
|
||||||
|
}
|
||||||
|
if (quiet) {
|
||||||
|
free(quiet);
|
||||||
|
quiet = NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool gen_net_rule(Profile &prof, u16 family, unsigned int type_mask);
|
||||||
|
void set_netperm(unsigned int family, unsigned int type);
|
||||||
|
void update_compat_net(void);
|
||||||
|
|
||||||
|
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||||
|
if (p.owner) {
|
||||||
|
error = _("owner prefix not allowed on network rules");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
virtual ostream &dump(ostream &os);
|
||||||
|
virtual int expand_variables(void);
|
||||||
|
virtual int gen_policy_re(Profile &prof);
|
||||||
|
// TODO: implement rule dedup cmp member function
|
||||||
|
/* array of type masks indexed by AF_FAMILY */
|
||||||
|
/* allow, audit, deny and quiet are used for compatibility with AA_CLASS_NET */
|
||||||
|
static unsigned int *allow;
|
||||||
|
static unsigned int *audit;
|
||||||
|
static unsigned int *deny;
|
||||||
|
static unsigned int *quiet;
|
||||||
|
|
||||||
|
bool alloc_net_table(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void warn_once(const char *name) override;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* __AA_NETWORK_H */
|
#endif /* __AA_NETWORK_H */
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
#include "profile.h"
|
#include "profile.h"
|
||||||
#include "parser_yacc.h"
|
#include "parser_yacc.h"
|
||||||
|
#include "network.h"
|
||||||
|
|
||||||
/* #define DEBUG */
|
/* #define DEBUG */
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
|
@ -857,80 +857,6 @@ int post_process_policydb_ents(Profile *prof)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool gen_net_rule(Profile *prof, u16 family, unsigned int type_mask,
|
|
||||||
bool audit, bool deny) {
|
|
||||||
std::ostringstream buffer;
|
|
||||||
std::string buf;
|
|
||||||
|
|
||||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_NETV8;
|
|
||||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((family & 0xff00) >> 8);
|
|
||||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (family & 0xff);
|
|
||||||
if (type_mask > 0xffff) {
|
|
||||||
buffer << "..";
|
|
||||||
} else {
|
|
||||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((type_mask & 0xff00) >> 8);
|
|
||||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (type_mask & 0xff);
|
|
||||||
}
|
|
||||||
buf = buffer.str();
|
|
||||||
if (!prof->policy.rules->add_rule(buf.c_str(), deny, map_perms(AA_VALID_NET_PERMS),
|
|
||||||
audit ? map_perms(AA_VALID_NET_PERMS) : 0,
|
|
||||||
parseopts))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool gen_af_rules(Profile *prof, u16 family, unsigned int type_mask,
|
|
||||||
unsigned int audit_mask, bool deny)
|
|
||||||
{
|
|
||||||
if (type_mask > 0xffff && audit_mask > 0xffff) {
|
|
||||||
/* instead of generating multiple rules wild card type */
|
|
||||||
return gen_net_rule(prof, family, type_mask, audit_mask, deny);
|
|
||||||
} else {
|
|
||||||
int t;
|
|
||||||
/* generate rules for types that are set */
|
|
||||||
for (t = 0; t < 16; t++) {
|
|
||||||
if (type_mask & (1 << t)) {
|
|
||||||
if (!gen_net_rule(prof, family, t,
|
|
||||||
audit_mask & (1 << t),
|
|
||||||
deny))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool post_process_policydb_net(Profile *prof)
|
|
||||||
{
|
|
||||||
u16 af;
|
|
||||||
|
|
||||||
/* no network rules defined so we don't have generate them */
|
|
||||||
if (!prof->net.allow)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* generate rules if the af has something set */
|
|
||||||
for (af = AF_UNSPEC; af < get_af_max(); af++) {
|
|
||||||
if (prof->net.allow[af] ||
|
|
||||||
prof->net.deny[af] ||
|
|
||||||
prof->net.audit[af] ||
|
|
||||||
prof->net.quiet[af]) {
|
|
||||||
if (!gen_af_rules(prof, af, prof->net.allow[af],
|
|
||||||
prof->net.audit[af],
|
|
||||||
false))
|
|
||||||
return false;
|
|
||||||
if (!gen_af_rules(prof, af, prof->net.deny[af],
|
|
||||||
prof->net.quiet[af],
|
|
||||||
true))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAKE_STR(X) #X
|
#define MAKE_STR(X) #X
|
||||||
#define CLASS_STR(X) "\\d" MAKE_STR(X)
|
#define CLASS_STR(X) "\\d" MAKE_STR(X)
|
||||||
#define MAKE_SUB_STR(X) "\\000" MAKE_STR(X)
|
#define MAKE_SUB_STR(X) "\\000" MAKE_STR(X)
|
||||||
|
@ -959,9 +885,6 @@ int process_profile_policydb(Profile *prof)
|
||||||
|
|
||||||
if (!post_process_policydb_ents(prof))
|
if (!post_process_policydb_ents(prof))
|
||||||
goto out;
|
goto out;
|
||||||
/* TODO: move to network class */
|
|
||||||
if (features_supports_networkv8 && !post_process_policydb_net(prof))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* insert entries to show indicate what compiler/policy expects
|
/* insert entries to show indicate what compiler/policy expects
|
||||||
* to be supported
|
* to be supported
|
||||||
|
|
|
@ -187,13 +187,14 @@ bool check_x_qualifier(struct cod_entry *entry, const char *&errror);
|
||||||
#include "userns.h"
|
#include "userns.h"
|
||||||
#include "mqueue.h"
|
#include "mqueue.h"
|
||||||
#include "io_uring.h"
|
#include "io_uring.h"
|
||||||
|
#include "network.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
%union {
|
%union {
|
||||||
char *id;
|
char *id;
|
||||||
char *flag_id;
|
char *flag_id;
|
||||||
char *mode;
|
char *mode;
|
||||||
struct aa_network_entry *network_entry;
|
network_rule *network_entry;
|
||||||
Profile *prof;
|
Profile *prof;
|
||||||
struct cod_net_entry *net_entry;
|
struct cod_net_entry *net_entry;
|
||||||
struct cod_entry *user_entry;
|
struct cod_entry *user_entry;
|
||||||
|
@ -693,51 +694,23 @@ rules: rules opt_prefix block
|
||||||
|
|
||||||
rules: rules opt_prefix network_rule
|
rules: rules opt_prefix network_rule
|
||||||
{
|
{
|
||||||
struct aa_network_entry *entry, *tmp;
|
const char *error;
|
||||||
|
if (!$3->add_prefix($2, error))
|
||||||
|
yyerror(error);
|
||||||
|
/* class members need to be updated after prefix is added */
|
||||||
|
$3->update_compat_net();
|
||||||
|
|
||||||
PDEBUG("Matched: network rule\n");
|
auto nm_af_unix = $3->network_map.find(AF_UNIX);
|
||||||
if ($2.owner)
|
if (nm_af_unix != $3->network_map.end()) {
|
||||||
yyerror(_("owner prefix not allowed"));
|
for (auto& entry : nm_af_unix->second) {
|
||||||
if (!$3)
|
unix_rule *rule = new unix_rule(entry.type,
|
||||||
yyerror(_("Assert: `network_rule' return invalid protocol."));
|
$2.audit, $2.rule_mode);
|
||||||
if (!$1->alloc_net_table())
|
|
||||||
yyerror(_("Memory allocation error."));
|
|
||||||
list_for_each_safe($3, entry, tmp) {
|
|
||||||
|
|
||||||
/* map to extended mediation, let rule backend do
|
|
||||||
* downgrade if needed
|
|
||||||
*/
|
|
||||||
if (entry->family == AF_UNIX) {
|
|
||||||
unix_rule *rule = new unix_rule(entry->type, $2.audit, $2.rule_mode);
|
|
||||||
if (!rule)
|
if (!rule)
|
||||||
yyerror(_("Memory allocation error."));
|
yyerror(_("Memory allocation error."));
|
||||||
$1->rule_ents.push_back(rule);
|
$1->rule_ents.push_back(rule);
|
||||||
}
|
}
|
||||||
if (entry->type > SOCK_PACKET) {
|
|
||||||
/* setting mask instead of a bit */
|
|
||||||
if ($2.rule_mode == RULE_DENY) {
|
|
||||||
$1->net.deny[entry->family] |= entry->type;
|
|
||||||
if ($2.audit != AUDIT_FORCE)
|
|
||||||
$1->net.quiet[entry->family] |= entry->type;
|
|
||||||
} else {
|
|
||||||
$1->net.allow[entry->family] |= entry->type;
|
|
||||||
if ($2.audit == AUDIT_FORCE)
|
|
||||||
$1->net.audit[entry->family] |= entry->type;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($2.rule_mode == RULE_DENY) {
|
|
||||||
$1->net.deny[entry->family] |= 1 << entry->type;
|
|
||||||
if ($2.audit != AUDIT_FORCE)
|
|
||||||
$1->net.quiet[entry->family] |= 1 << entry->type;
|
|
||||||
} else {
|
|
||||||
$1->net.allow[entry->family] |= 1 << entry->type;
|
|
||||||
if ($2.audit == AUDIT_FORCE)
|
|
||||||
$1->net.audit[entry->family] |= 1 << entry->type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(entry);
|
|
||||||
}
|
}
|
||||||
|
$1->rule_ents.push_back($3);
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1109,38 +1082,20 @@ link_rule: TOK_LINK opt_subset_flag id_or_var TOK_ARROW id_or_var TOK_END_OF_RUL
|
||||||
|
|
||||||
network_rule: TOK_NETWORK TOK_END_OF_RULE
|
network_rule: TOK_NETWORK TOK_END_OF_RULE
|
||||||
{
|
{
|
||||||
size_t family;
|
network_rule *entry = new network_rule(NULL, NULL, NULL);
|
||||||
struct aa_network_entry *new_entry, *entry = NULL;
|
|
||||||
for (family = AF_UNSPEC; family < get_af_max(); family++) {
|
|
||||||
new_entry = new_network_ent(family, 0xffffffff,
|
|
||||||
0xffffffff);
|
|
||||||
if (!new_entry)
|
|
||||||
yyerror(_("Memory allocation error."));
|
|
||||||
new_entry->next = entry;
|
|
||||||
entry = new_entry;
|
|
||||||
}
|
|
||||||
$$ = entry;
|
$$ = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
network_rule: TOK_NETWORK TOK_ID TOK_END_OF_RULE
|
network_rule: TOK_NETWORK TOK_ID TOK_END_OF_RULE
|
||||||
{
|
{
|
||||||
struct aa_network_entry *entry;
|
network_rule *entry = new network_rule($2, NULL, NULL);
|
||||||
entry = network_entry($2, NULL, NULL);
|
|
||||||
if (!entry)
|
|
||||||
/* test for short circuiting of family */
|
|
||||||
entry = network_entry(NULL, $2, NULL);
|
|
||||||
if (!entry)
|
|
||||||
yyerror(_("Invalid network entry."));
|
|
||||||
free($2);
|
free($2);
|
||||||
$$ = entry;
|
$$ = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
network_rule: TOK_NETWORK TOK_ID TOK_ID TOK_END_OF_RULE
|
network_rule: TOK_NETWORK TOK_ID TOK_ID TOK_END_OF_RULE
|
||||||
{
|
{
|
||||||
struct aa_network_entry *entry;
|
network_rule *entry = new network_rule($2, $3, NULL);
|
||||||
entry = network_entry($2, $3, NULL);
|
|
||||||
if (!entry)
|
|
||||||
yyerror(_("Invalid network entry."));
|
|
||||||
free($2);
|
free($2);
|
||||||
free($3);
|
free($3);
|
||||||
$$ = entry;
|
$$ = entry;
|
||||||
|
|
|
@ -72,20 +72,6 @@ void ProfileList::dump_profile_names(bool children)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Profile::alloc_net_table()
|
|
||||||
{
|
|
||||||
if (net.allow)
|
|
||||||
return true;
|
|
||||||
net.allow = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
|
||||||
net.audit = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
|
||||||
net.deny = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
|
||||||
net.quiet = (unsigned int *) calloc(get_af_max(), sizeof(unsigned int));
|
|
||||||
if (!net.allow || !net.audit || !net.deny || !net.quiet)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Profile::~Profile()
|
Profile::~Profile()
|
||||||
{
|
{
|
||||||
hat_table.clear();
|
hat_table.clear();
|
||||||
|
@ -115,14 +101,6 @@ Profile::~Profile()
|
||||||
for (int i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++)
|
for (int i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++)
|
||||||
if (exec_table[i])
|
if (exec_table[i])
|
||||||
free(exec_table[i]);
|
free(exec_table[i]);
|
||||||
if (net.allow)
|
|
||||||
free(net.allow);
|
|
||||||
if (net.audit)
|
|
||||||
free(net.audit);
|
|
||||||
if (net.deny)
|
|
||||||
free(net.deny);
|
|
||||||
if (net.quiet)
|
|
||||||
free(net.quiet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool comp (rule_t *lhs, rule_t *rhs)
|
static bool comp (rule_t *lhs, rule_t *rhs)
|
||||||
|
|
|
@ -311,7 +311,7 @@ public:
|
||||||
|
|
||||||
flagvals flags;
|
flagvals flags;
|
||||||
struct capabilities caps;
|
struct capabilities caps;
|
||||||
struct network net;
|
network_rule net;
|
||||||
|
|
||||||
struct aa_rlimits rlimits;
|
struct aa_rlimits rlimits;
|
||||||
|
|
||||||
|
@ -384,7 +384,6 @@ public:
|
||||||
|
|
||||||
flags.dump(cerr);
|
flags.dump(cerr);
|
||||||
caps.dump();
|
caps.dump();
|
||||||
net.dump();
|
|
||||||
|
|
||||||
if (entries)
|
if (entries)
|
||||||
debug_cod_entries(entries);
|
debug_cod_entries(entries);
|
||||||
|
@ -397,8 +396,6 @@ public:
|
||||||
hat_table.dump();
|
hat_table.dump();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool alloc_net_table();
|
|
||||||
|
|
||||||
std::string hname(void)
|
std::string hname(void)
|
||||||
{
|
{
|
||||||
if (!parent)
|
if (!parent)
|
||||||
|
|
Loading…
Add table
Reference in a new issue