parser: generate all ip options when ip is not specified

When the ip is not specified, then we should generate rules for ip
types: anonymous, ipv4 and ipv6. And that's the case for both local
and peer when considering recv and send permissions.

std::ostringstream does not have a copy constructor, that's why in
several places one can see streaming the string of one stream into
another.

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
This commit is contained in:
Georgia Garcia 2024-03-14 17:31:52 -03:00
parent 63676459c4
commit a0a0c88d9e
2 changed files with 148 additions and 53 deletions

View file

@ -578,8 +578,51 @@ std::string gen_port_cond(uint16_t port)
return oss.str(); return oss.str();
} }
void network_rule::gen_ip_conds(std::ostringstream &oss, ip_conds entry, bool is_peer, bool is_cmd) std::list<std::ostringstream> gen_all_ip_options(std::ostringstream &oss) {
std::list<std::ostringstream> all_streams;
std::ostringstream anon, ipv4, ipv6;
int i;
anon << oss.str();
ipv4 << oss.str();
ipv6 << oss.str();
anon << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ANON_SIZE;
/* add a byte containing the size of the following ip */
ipv4 << "\\x" << std::setfill('0') << std::setw(2) << std::hex << IPV4_SIZE;
for (i = 0; i < 4; i++)
ipv4 << ".";
/* add a byte containing the size of the following ip */
ipv6 << "\\x" << std::setfill('0') << std::setw(2) << std::hex << IPV6_SIZE;
for (i = 0; i < 16; ++i)
ipv6 << ".";
all_streams.push_back(std::move(anon));
all_streams.push_back(std::move(ipv4));
all_streams.push_back(std::move(ipv6));
return all_streams;
}
std::list<std::ostringstream> copy_streams_list(std::list<std::ostringstream> &streams)
{ {
std::list<std::ostringstream> streams_copy;
for (auto &oss : streams) {
std::ostringstream oss_copy(oss.str());
streams_copy.push_back(std::move(oss_copy));
}
return streams_copy;
}
bool network_rule::gen_ip_conds(Profile &prof, std::list<std::ostringstream> &streams, ip_conds entry, bool is_peer, bool is_cmd)
{
std::string buf;
perms_t cond_perms;
std::list<std::ostringstream> ip_streams;
for (auto &oss : streams) {
if (entry.is_port) { if (entry.is_port) {
/* encode port type (privileged - 1, remote - 2, unprivileged - 0) */ /* encode port type (privileged - 1, remote - 2, unprivileged - 0) */
if (!is_peer && perms & AA_NET_BIND && entry.port < IPPORT_RESERVED) if (!is_peer && perms & AA_NET_BIND && entry.port < IPPORT_RESERVED)
@ -592,21 +635,51 @@ void network_rule::gen_ip_conds(std::ostringstream &oss, ip_conds entry, bool is
oss << gen_port_cond(entry.port); oss << gen_port_cond(entry.port);
} else { } else {
/* port type + port number */ /* port type + port number */
if (!is_cmd) oss << "...";
oss << "."; }
oss << "..";
} }
ip_streams = std::move(streams);
streams.clear();
for (auto &oss : ip_streams) {
if (entry.is_ip) { if (entry.is_ip) {
oss << gen_ip_cond(entry.ip); oss << gen_ip_cond(entry.ip);
streams.push_back(std::move(oss));
} else { } else {
/* encode 0 to indicate there's no ip (ip size) */ streams.splice(streams.end(), gen_all_ip_options(oss));
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ANON_SIZE; }
} }
oss << "\\-x01"; /* oob separator */ cond_perms = map_perms(perms);
if (!is_cmd && (label || is_peer))
cond_perms = (AA_CONT_MATCH << 1);
for (auto &oss : streams) {
oss << "\\x00"; /* null transition */
buf = oss.str();
/* AA_CONT_MATCH mapping (cond_perms) only applies to perms, not audit */
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, cond_perms,
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts))
return false;
if (label) {
if (is_peer)
cond_perms = (AA_CONT_MATCH << 1);
oss << default_match_pattern; /* label - not used for now */ oss << default_match_pattern; /* label - not used for now */
oss << "\\x00"; /* null transition */ oss << "\\x00"; /* null transition */
buf = oss.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, cond_perms,
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts))
return false;
}
}
return true;
} }
bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mask, unsigned int protocol) { bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mask, unsigned int protocol) {
@ -650,48 +723,69 @@ bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mas
} }
if (perms & AA_PEER_NET_PERMS) { if (perms & AA_PEER_NET_PERMS) {
gen_ip_conds(buffer, peer, true, false); std::list<std::ostringstream> streams;
std::ostringstream cmd_buffer;
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_ADDR; cmd_buffer << buffer.str();
streams.push_back(std::move(cmd_buffer));
gen_ip_conds(buffer, local, false, true); if (!gen_ip_conds(prof, streams, peer, true, false))
return false;
buf = buffer.str(); for (auto &oss : streams) {
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms), oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_ADDR;
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, }
parseopts))
if (!gen_ip_conds(prof, streams, local, false, true))
return false; return false;
} }
if ((perms & AA_NET_LISTEN) || (perms & AA_NET_OPT)) {
gen_ip_conds(buffer, local, false, false); std::list<std::ostringstream> streams;
std::ostringstream common_buffer;
common_buffer << buffer.str();
streams.push_back(std::move(common_buffer));
if (!gen_ip_conds(prof, streams, local, false, false))
return false;
if (perms & AA_NET_LISTEN) { if (perms & AA_NET_LISTEN) {
std::ostringstream cmd_buffer; std::list<std::ostringstream> cmd_streams;
cmd_buffer << buffer.str(); cmd_streams = copy_streams_list(streams);
cmd_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_LISTEN;
for (auto &cmd_buffer : streams) {
std::ostringstream listen_buffer;
listen_buffer << cmd_buffer.str();
listen_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_LISTEN;
/* length of queue allowed - not used for now */ /* length of queue allowed - not used for now */
cmd_buffer << ".."; listen_buffer << "..";
buf = cmd_buffer.str(); buf = listen_buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms), if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms),
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts)) parseopts))
return false; return false;
} }
}
if (perms & AA_NET_OPT) { if (perms & AA_NET_OPT) {
std::ostringstream cmd_buffer; std::list<std::ostringstream> cmd_streams;
cmd_buffer << buffer.str(); cmd_streams = copy_streams_list(streams);
cmd_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_OPT;
for (auto &cmd_buffer : streams) {
std::ostringstream opt_buffer;
opt_buffer << cmd_buffer.str();
opt_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_OPT;
/* level - not used for now */ /* level - not used for now */
cmd_buffer << ".."; opt_buffer << "..";
/* socket mapping - not used for now */ /* socket mapping - not used for now */
cmd_buffer << ".."; opt_buffer << "..";
buf = cmd_buffer.str(); buf = opt_buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms), if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms),
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts)) parseopts))
return false; return false;
} }
} }
return true; return true;
} }

View file

@ -26,6 +26,7 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <list>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
@ -183,7 +184,7 @@ public:
} }
}; };
void gen_ip_conds(std::ostringstream &oss, ip_conds entry, bool is_peer, bool is_cmd); bool gen_ip_conds(Profile &prof, std::list<std::ostringstream> &streams, ip_conds entry, bool is_peer, bool is_cmd);
bool gen_net_rule(Profile &prof, u16 family, unsigned int type_mask, unsigned int protocol); bool gen_net_rule(Profile &prof, u16 family, unsigned int type_mask, unsigned int protocol);
void set_netperm(unsigned int family, unsigned int type, unsigned int protocol); void set_netperm(unsigned int family, unsigned int type, unsigned int protocol);
void update_compat_net(void); void update_compat_net(void);