mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-01 06:45:38 +00:00
Compare commits
32 Commits
v4.0.0-bet
...
v4.0.0-bet
Author | SHA1 | Date | |
---|---|---|---|
|
2fc80487f7 | ||
|
c87969b37c | ||
|
b68bb18860 | ||
|
c47789340a | ||
|
e23a3eeba5 | ||
|
d0fadc48cf | ||
|
aec3f3b22c | ||
|
101651c88f | ||
|
efc2ec5fdd | ||
|
b01b9895e7 | ||
|
a0a0c88d9e | ||
|
63676459c4 | ||
|
9ed04cb01e | ||
|
2a885872a3 | ||
|
989501428e | ||
|
25f21a0758 | ||
|
022af9c528 | ||
|
9a1838016c | ||
|
f4c19acfba | ||
|
dac9d08764 | ||
|
243162ca29 | ||
|
ae978c1953 | ||
|
d19db55a37 | ||
|
e3d381cf91 | ||
|
aa69d9adc9 | ||
|
3d1dedfa7e | ||
|
f27b1ef93a | ||
|
18d6a917f8 | ||
|
d1d39d176e | ||
|
2d654477f2 | ||
|
66dc2cc7d0 | ||
|
021c3248f9 |
@@ -1 +1 @@
|
|||||||
4.0.0~beta2
|
4.0.0~beta3
|
||||||
|
@@ -93,7 +93,7 @@ if test "$ac_cv_prog_cc_c99" = "no"; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
m4_ifndef([AX_CHECK_COMPILE_FLAG], [AC_MSG_ERROR(['autoconf-archive' missing])])
|
m4_ifndef([AX_CHECK_COMPILE_FLAG], [AC_MSG_ERROR(['autoconf-archive' missing])])
|
||||||
EXTRA_CFLAGS="-Wall $(EXTRA_WARNINGS) -fPIC"
|
EXTRA_CFLAGS="-Wall $EXTRA_WARNINGS -fPIC"
|
||||||
AX_CHECK_COMPILE_FLAG([-flto-partition=none], , , [-Werror])
|
AX_CHECK_COMPILE_FLAG([-flto-partition=none], , , [-Werror])
|
||||||
AS_VAR_IF([ax_cv_check_cflags__Werror__flto_partition_none], [yes],
|
AS_VAR_IF([ax_cv_check_cflags__Werror__flto_partition_none], [yes],
|
||||||
[EXTRA_CFLAGS="$EXTRA_CFLAGS -flto-partition=none"]
|
[EXTRA_CFLAGS="$EXTRA_CFLAGS -flto-partition=none"]
|
||||||
|
@@ -440,7 +440,6 @@ install-arch: $(INSTALLDEPS)
|
|||||||
install-indep: indep
|
install-indep: indep
|
||||||
install -m 755 -d $(INSTALL_CONFDIR)
|
install -m 755 -d $(INSTALL_CONFDIR)
|
||||||
install -m 644 parser.conf $(INSTALL_CONFDIR)
|
install -m 644 parser.conf $(INSTALL_CONFDIR)
|
||||||
install -m 755 -d ${DESTDIR}/var/lib/apparmor
|
|
||||||
install -m 755 -d $(APPARMOR_BIN_PREFIX)
|
install -m 755 -d $(APPARMOR_BIN_PREFIX)
|
||||||
install -m 755 rc.apparmor.functions $(APPARMOR_BIN_PREFIX)
|
install -m 755 rc.apparmor.functions $(APPARMOR_BIN_PREFIX)
|
||||||
install -m 755 profile-load $(APPARMOR_BIN_PREFIX)
|
install -m 755 profile-load $(APPARMOR_BIN_PREFIX)
|
||||||
|
@@ -252,6 +252,19 @@ const char *net_find_af_name(unsigned int af)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *net_find_protocol_name(unsigned int protocol)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(network_mappings) / sizeof(*network_mappings); i++) {
|
||||||
|
if (network_mappings[i].protocol == protocol) {
|
||||||
|
return network_mappings[i].protocol_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,
|
||||||
const char *type,
|
const char *type,
|
||||||
@@ -347,6 +360,10 @@ bool network_rule::parse_port(ip_conds &entry)
|
|||||||
|
|
||||||
bool network_rule::parse_address(ip_conds &entry)
|
bool network_rule::parse_address(ip_conds &entry)
|
||||||
{
|
{
|
||||||
|
if (strcmp(entry.sip, "anon") == 0) {
|
||||||
|
entry.is_anonymous = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
entry.is_ip = true;
|
entry.is_ip = true;
|
||||||
return parse_ip(entry.sip, &entry.ip);
|
return parse_ip(entry.sip, &entry.ip);
|
||||||
}
|
}
|
||||||
@@ -374,23 +391,24 @@ void network_rule::move_conditionals(struct cond_entry *conds, ip_conds &ip_cond
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void network_rule::set_netperm(unsigned int family, unsigned int type)
|
void network_rule::set_netperm(unsigned int family, unsigned int type, unsigned int protocol)
|
||||||
{
|
{
|
||||||
if (type > SOCK_PACKET) {
|
if (type > SOCK_PACKET) {
|
||||||
/* setting mask instead of a bit */
|
/* setting mask instead of a bit */
|
||||||
network_perms[family] |= type;
|
network_perms[family].first |= type;
|
||||||
} else
|
} else
|
||||||
network_perms[family] |= 1 << type;
|
network_perms[family].first |= 1 << type;
|
||||||
|
network_perms[family].second |= protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
network_rule::network_rule(perms_t perms_p, struct cond_entry *conds,
|
network_rule::network_rule(perms_t perms_p, struct cond_entry *conds,
|
||||||
struct cond_entry *peer_conds):
|
struct cond_entry *peer_conds):
|
||||||
dedup_perms_rule_t(AA_CLASS_NETV8)
|
dedup_perms_rule_t(AA_CLASS_NETV8), label(NULL)
|
||||||
{
|
{
|
||||||
size_t family_index;
|
size_t family_index;
|
||||||
for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) {
|
for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) {
|
||||||
network_map[family_index].push_back({ family_index, 0xFFFFFFFF, 0xFFFFFFFF });
|
network_map[family_index].push_back({ family_index, 0xFFFFFFFF, 0xFFFFFFFF });
|
||||||
set_netperm(family_index, 0xFFFFFFFF);
|
set_netperm(family_index, 0xFFFFFFFF, 0xFFFFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
move_conditionals(conds, local);
|
move_conditionals(conds, local);
|
||||||
@@ -412,18 +430,18 @@ network_rule::network_rule(perms_t perms_p, struct cond_entry *conds,
|
|||||||
network_rule::network_rule(perms_t perms_p, const char *family, const char *type,
|
network_rule::network_rule(perms_t perms_p, const char *family, const char *type,
|
||||||
const char *protocol, struct cond_entry *conds,
|
const char *protocol, struct cond_entry *conds,
|
||||||
struct cond_entry *peer_conds):
|
struct cond_entry *peer_conds):
|
||||||
dedup_perms_rule_t(AA_CLASS_NETV8)
|
dedup_perms_rule_t(AA_CLASS_NETV8), label(NULL)
|
||||||
{
|
{
|
||||||
const struct network_tuple *mapping = NULL;
|
const struct network_tuple *mapping = NULL;
|
||||||
while ((mapping = net_find_mapping(mapping, family, type, protocol))) {
|
while ((mapping = net_find_mapping(mapping, family, type, protocol))) {
|
||||||
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
|
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
|
||||||
set_netperm(mapping->family, mapping->type);
|
set_netperm(mapping->family, mapping->type, mapping->protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == NULL && network_map.empty()) {
|
if (type == NULL && network_map.empty()) {
|
||||||
while ((mapping = net_find_mapping(mapping, type, family, protocol))) {
|
while ((mapping = net_find_mapping(mapping, type, family, protocol))) {
|
||||||
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
|
network_map[mapping->family].push_back({ mapping->family, mapping->type, mapping->protocol });
|
||||||
set_netperm(mapping->family, mapping->type);
|
set_netperm(mapping->family, mapping->type, mapping->protocol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,10 +465,10 @@ network_rule::network_rule(perms_t perms_p, const char *family, const char *type
|
|||||||
}
|
}
|
||||||
|
|
||||||
network_rule::network_rule(perms_t perms_p, unsigned int family, unsigned int type):
|
network_rule::network_rule(perms_t perms_p, unsigned int family, unsigned int type):
|
||||||
dedup_perms_rule_t(AA_CLASS_NETV8)
|
dedup_perms_rule_t(AA_CLASS_NETV8), label(NULL)
|
||||||
{
|
{
|
||||||
network_map[family].push_back({ family, type, 0xFFFFFFFF });
|
network_map[family].push_back({ family, type, 0xFFFFFFFF });
|
||||||
set_netperm(family, type);
|
set_netperm(family, type, 0xFFFFFFFF);
|
||||||
|
|
||||||
if (perms_p) {
|
if (perms_p) {
|
||||||
perms = perms_p;
|
perms = perms_p;
|
||||||
@@ -479,7 +497,8 @@ ostream &network_rule::dump(ostream &os)
|
|||||||
|
|
||||||
for (const auto& perm : network_perms) {
|
for (const auto& perm : network_perms) {
|
||||||
unsigned int family = perm.first;
|
unsigned int family = perm.first;
|
||||||
unsigned int type = perm.second;
|
unsigned int type = perm.second.first;
|
||||||
|
unsigned int protocol = perm.second.second;
|
||||||
|
|
||||||
const char *family_name = net_find_af_name(family);
|
const char *family_name = net_find_af_name(family);
|
||||||
if (family_name)
|
if (family_name)
|
||||||
@@ -507,6 +526,12 @@ ostream &network_rule::dump(ostream &os)
|
|||||||
os << " #" << std::hex << (type & mask);
|
os << " #" << std::hex << (type & mask);
|
||||||
|
|
||||||
printf(" }");
|
printf(" }");
|
||||||
|
|
||||||
|
const char *protocol_name = net_find_protocol_name(protocol);
|
||||||
|
if (protocol_name)
|
||||||
|
os << " " << protocol_name;
|
||||||
|
else
|
||||||
|
os << " #" << protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
os << ",\n";
|
os << ",\n";
|
||||||
@@ -531,14 +556,14 @@ std::string gen_ip_cond(const struct ip_address ip)
|
|||||||
int i;
|
int i;
|
||||||
if (ip.family == AF_INET) {
|
if (ip.family == AF_INET) {
|
||||||
/* add a byte containing the size of the following ip */
|
/* add a byte containing the size of the following ip */
|
||||||
oss << "\\x04";
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << IPV4_SIZE;
|
||||||
|
|
||||||
u8 *byte = (u8 *) &ip.address.address_v4; /* in network byte order */
|
u8 *byte = (u8 *) &ip.address.address_v4; /* in network byte order */
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
||||||
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(byte[i]);
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(byte[i]);
|
||||||
} else {
|
} else {
|
||||||
/* add a byte containing the size of the following ip */
|
/* add a byte containing the size of the following ip */
|
||||||
oss << "\\x10";
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << IPV6_SIZE;
|
||||||
for (i = 0; i < 16; ++i)
|
for (i = 0; i < 16; ++i)
|
||||||
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(ip.address.address_v6[i]);
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(ip.address.address_v6[i]);
|
||||||
}
|
}
|
||||||
@@ -557,48 +582,114 @@ 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)
|
||||||
{
|
{
|
||||||
/* encode protocol */
|
std::list<std::ostringstream> streams_copy;
|
||||||
if (!is_cmd) {
|
for (auto &oss : streams) {
|
||||||
if (entry.is_ip) {
|
std::ostringstream oss_copy(oss.str());
|
||||||
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((entry.ip.family & 0xff00) >> 8);
|
streams_copy.push_back(std::move(oss_copy));
|
||||||
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (entry.ip.family & 0xff);
|
}
|
||||||
|
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 && !(entry.is_ip && entry.is_anonymous)) {
|
||||||
|
/* encode port type (privileged - 1, remote - 2, unprivileged - 0) */
|
||||||
|
if (!is_peer && perms & AA_NET_BIND && entry.port < IPPORT_RESERVED)
|
||||||
|
oss << "\\x01";
|
||||||
|
else if (is_peer)
|
||||||
|
oss << "\\x02";
|
||||||
|
else
|
||||||
|
oss << "\\x00";
|
||||||
|
|
||||||
|
oss << gen_port_cond(entry.port);
|
||||||
} else {
|
} else {
|
||||||
oss << "..";
|
/* port type + port number */
|
||||||
|
oss << "...";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.is_port) {
|
ip_streams = std::move(streams);
|
||||||
/* encode port type (privileged - 1, remote - 2, unprivileged - 0) */
|
streams.clear();
|
||||||
if (!is_peer && perms & AA_NET_BIND && entry.port < IPPORT_RESERVED)
|
|
||||||
oss << "\\x01";
|
|
||||||
else if (is_peer)
|
|
||||||
oss << "\\x02";
|
|
||||||
else
|
|
||||||
oss << "\\x00";
|
|
||||||
|
|
||||||
oss << gen_port_cond(entry.port);
|
for (auto &oss : ip_streams) {
|
||||||
} else {
|
if (entry.is_ip) {
|
||||||
/* port type + port number */
|
oss << gen_ip_cond(entry.ip);
|
||||||
if (!is_cmd)
|
streams.push_back(std::move(oss));
|
||||||
oss << ".";
|
} else if (entry.is_anonymous) {
|
||||||
oss << "..";
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ANON_SIZE;
|
||||||
|
streams.push_back(std::move(oss));
|
||||||
|
} else {
|
||||||
|
streams.splice(streams.end(), gen_all_ip_options(oss));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.is_ip) {
|
cond_perms = map_perms(perms);
|
||||||
oss << gen_ip_cond(entry.ip);
|
if (!is_cmd && (label || is_peer))
|
||||||
} else {
|
cond_perms = (AA_CONT_MATCH << 1);
|
||||||
/* encode 0 to indicate there's no ip (ip size) */
|
|
||||||
oss << "\\x00";
|
|
||||||
}
|
|
||||||
|
|
||||||
oss << "\\-x01"; /* oob separator */
|
for (auto &oss : streams) {
|
||||||
oss << default_match_pattern; /* label - not used for now */
|
oss << "\\x00"; /* null transition */
|
||||||
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 || is_peer) {
|
||||||
|
if (!is_peer)
|
||||||
|
cond_perms = map_perms(perms);
|
||||||
|
|
||||||
|
oss << default_match_pattern; /* label - not used for now */
|
||||||
|
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) {
|
bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mask, unsigned int protocol) {
|
||||||
std::ostringstream buffer;
|
std::ostringstream buffer;
|
||||||
std::string buf;
|
std::string buf;
|
||||||
|
|
||||||
@@ -621,49 +712,87 @@ bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mas
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (perms & AA_PEER_NET_PERMS) {
|
buf = buffer.str();
|
||||||
gen_ip_conds(buffer, peer, true, false);
|
/* create perms need to be generated excluding the rest of the perms */
|
||||||
|
if (perms & AA_NET_CREATE) {
|
||||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_ADDR;
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms & AA_NET_CREATE) | (AA_CONT_MATCH << 1),
|
||||||
|
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms & AA_NET_CREATE) : 0,
|
||||||
gen_ip_conds(buffer, local, false, true);
|
|
||||||
|
|
||||||
buf = buffer.str();
|
|
||||||
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,
|
|
||||||
parseopts))
|
parseopts))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((perms & AA_NET_LISTEN) || (perms & AA_NET_OPT)) {
|
|
||||||
gen_ip_conds(buffer, local, false, false);
|
|
||||||
|
|
||||||
if (perms & AA_NET_LISTEN) {
|
/* encode protocol */
|
||||||
std::ostringstream cmd_buffer;
|
if (protocol > 0xffff) {
|
||||||
cmd_buffer << buffer.str();
|
buffer << "..";
|
||||||
cmd_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_LISTEN;
|
} else {
|
||||||
/* length of queue allowed - not used for now */
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << ((protocol & 0xff00) >> 8);
|
||||||
cmd_buffer << "..";
|
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (protocol & 0xff);
|
||||||
buf = cmd_buffer.str();
|
}
|
||||||
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,
|
if (perms & AA_PEER_NET_PERMS) {
|
||||||
parseopts))
|
std::list<std::ostringstream> streams;
|
||||||
return false;
|
std::ostringstream cmd_buffer;
|
||||||
|
|
||||||
|
cmd_buffer << buffer.str();
|
||||||
|
streams.push_back(std::move(cmd_buffer));
|
||||||
|
|
||||||
|
if (!gen_ip_conds(prof, streams, peer, true, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (auto &oss : streams) {
|
||||||
|
oss << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_ADDR;
|
||||||
}
|
}
|
||||||
if (perms & AA_NET_OPT) {
|
|
||||||
std::ostringstream cmd_buffer;
|
if (!gen_ip_conds(prof, streams, local, false, true))
|
||||||
cmd_buffer << buffer.str();
|
return false;
|
||||||
cmd_buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << CMD_OPT;
|
}
|
||||||
/* level - not used for now */
|
|
||||||
cmd_buffer << "..";
|
std::list<std::ostringstream> streams;
|
||||||
/* socket mapping - not used for now */
|
std::ostringstream common_buffer;
|
||||||
cmd_buffer << "..";
|
|
||||||
buf = cmd_buffer.str();
|
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) {
|
||||||
|
std::list<std::ostringstream> cmd_streams;
|
||||||
|
cmd_streams = copy_streams_list(streams);
|
||||||
|
|
||||||
|
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 */
|
||||||
|
listen_buffer << "..";
|
||||||
|
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) {
|
||||||
|
std::list<std::ostringstream> cmd_streams;
|
||||||
|
cmd_streams = copy_streams_list(streams);
|
||||||
|
|
||||||
|
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 */
|
||||||
|
opt_buffer << "..";
|
||||||
|
/* socket mapping - not used for now */
|
||||||
|
opt_buffer << "..";
|
||||||
|
buf = opt_buffer.str();
|
||||||
|
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,
|
||||||
|
parseopts))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,17 +808,18 @@ int network_rule::gen_policy_re(Profile &prof)
|
|||||||
|
|
||||||
for (const auto& perm : network_perms) {
|
for (const auto& perm : network_perms) {
|
||||||
unsigned int family = perm.first;
|
unsigned int family = perm.first;
|
||||||
unsigned int type = perm.second;
|
unsigned int type = perm.second.first;
|
||||||
|
unsigned int protocol = perm.second.second;
|
||||||
|
|
||||||
if (type > 0xffff) {
|
if (type > 0xffff) {
|
||||||
if (!gen_net_rule(prof, family, type))
|
if (!gen_net_rule(prof, family, type, protocol))
|
||||||
goto fail;
|
goto fail;
|
||||||
} else {
|
} else {
|
||||||
int t;
|
int t;
|
||||||
/* generate rules for types that are set */
|
/* generate rules for types that are set */
|
||||||
for (t = 0; t < 16; t++) {
|
for (t = 0; t < 16; t++) {
|
||||||
if (type & (1 << t)) {
|
if (type & (1 << t)) {
|
||||||
if (!gen_net_rule(prof, family, t))
|
if (!gen_net_rule(prof, family, t, protocol))
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -760,13 +890,27 @@ void network_rule::update_compat_net(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmp_network_map(std::unordered_map<unsigned int, perms_t> lhs,
|
static int cmp_ip_conds(ip_conds const &lhs, ip_conds const &rhs)
|
||||||
std::unordered_map<unsigned int, perms_t> rhs)
|
{
|
||||||
|
int res = null_strcmp(lhs.sip, rhs.sip);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
res = null_strcmp(lhs.sport, rhs.sport);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
return lhs.is_anonymous - rhs.is_anonymous;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_network_map(std::unordered_map<unsigned int, std::pair<unsigned int, unsigned int>> lhs,
|
||||||
|
std::unordered_map<unsigned int, std::pair<unsigned int, unsigned int>> rhs)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
size_t family_index;
|
size_t family_index;
|
||||||
for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) {
|
for (family_index = AF_UNSPEC; family_index < get_af_max(); family_index++) {
|
||||||
res = lhs[family_index] - rhs[family_index];
|
res = lhs[family_index].first - rhs[family_index].first;
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
res = lhs[family_index].second - rhs[family_index].second;
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -779,5 +923,14 @@ int network_rule::cmp(rule_t const &rhs) const
|
|||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
network_rule const &nrhs = rule_cast<network_rule const &>(rhs);
|
network_rule const &nrhs = rule_cast<network_rule const &>(rhs);
|
||||||
return cmp_network_map(network_perms, nrhs.network_perms);
|
res = cmp_network_map(network_perms, nrhs.network_perms);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
res = cmp_ip_conds(local, nrhs.local);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
res = cmp_ip_conds(peer, nrhs.peer);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
return null_strcmp(label, nrhs.label);
|
||||||
};
|
};
|
||||||
|
@@ -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>
|
||||||
@@ -79,6 +80,10 @@
|
|||||||
#define CMD_LISTEN 2
|
#define CMD_LISTEN 2
|
||||||
#define CMD_OPT 4
|
#define CMD_OPT 4
|
||||||
|
|
||||||
|
#define ANON_SIZE 0
|
||||||
|
#define IPV4_SIZE 1
|
||||||
|
#define IPV6_SIZE 2
|
||||||
|
|
||||||
struct network_tuple {
|
struct network_tuple {
|
||||||
const char *family_name;
|
const char *family_name;
|
||||||
unsigned int family;
|
unsigned int family;
|
||||||
@@ -127,6 +132,8 @@ public:
|
|||||||
uint16_t port;
|
uint16_t port;
|
||||||
struct ip_address ip;
|
struct ip_address ip;
|
||||||
|
|
||||||
|
bool is_anonymous = false;
|
||||||
|
|
||||||
void free_conds() {
|
void free_conds() {
|
||||||
if (sip)
|
if (sip)
|
||||||
free(sip);
|
free(sip);
|
||||||
@@ -139,10 +146,11 @@ class network_rule: public dedup_perms_rule_t {
|
|||||||
void move_conditionals(struct cond_entry *conds, ip_conds &ip_cond);
|
void move_conditionals(struct cond_entry *conds, ip_conds &ip_cond);
|
||||||
public:
|
public:
|
||||||
std::unordered_map<unsigned int, std::vector<struct aa_network_entry>> network_map;
|
std::unordered_map<unsigned int, std::vector<struct aa_network_entry>> network_map;
|
||||||
std::unordered_map<unsigned int, perms_t> network_perms;
|
std::unordered_map<unsigned int, std::pair<unsigned int, unsigned int>> network_perms;
|
||||||
|
|
||||||
ip_conds peer;
|
ip_conds peer;
|
||||||
ip_conds local;
|
ip_conds local;
|
||||||
|
char *label;
|
||||||
|
|
||||||
bool has_local_conds(void) { return local.sip || local.sport; }
|
bool has_local_conds(void) { return local.sip || local.sport; }
|
||||||
bool has_peer_conds(void) { return peer.sip || peer.sport; }
|
bool has_peer_conds(void) { return peer.sip || peer.sport; }
|
||||||
@@ -178,9 +186,9 @@ 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);
|
bool gen_net_rule(Profile &prof, u16 family, unsigned int type_mask, unsigned int protocol);
|
||||||
void set_netperm(unsigned int family, unsigned int type);
|
void set_netperm(unsigned int family, unsigned int type, unsigned int protocol);
|
||||||
void update_compat_net(void);
|
void update_compat_net(void);
|
||||||
bool parse_address(ip_conds &entry);
|
bool parse_address(ip_conds &entry);
|
||||||
bool parse_port(ip_conds &entry);
|
bool parse_port(ip_conds &entry);
|
||||||
|
@@ -921,7 +921,7 @@ void set_supported_features()
|
|||||||
"network_v8");
|
"network_v8");
|
||||||
features_supports_inet = features_intersect(kernel_features,
|
features_supports_inet = features_intersect(kernel_features,
|
||||||
policy_features,
|
policy_features,
|
||||||
"network/af_inet");
|
"network_v8/af_inet");
|
||||||
features_supports_unix = features_intersect(kernel_features,
|
features_supports_unix = features_intersect(kernel_features,
|
||||||
policy_features,
|
policy_features,
|
||||||
"network/af_unix");
|
"network/af_unix");
|
||||||
|
@@ -31,6 +31,10 @@
|
|||||||
/{usr/,}lib/@{multiarch}/security/pam_*.so mr,
|
/{usr/,}lib/@{multiarch}/security/pam_*.so mr,
|
||||||
/{usr/,}lib/@{multiarch}/security/ r,
|
/{usr/,}lib/@{multiarch}/security/ r,
|
||||||
|
|
||||||
|
# pam_unix
|
||||||
|
owner /proc/@{pid}/loginuid r,
|
||||||
|
/{,usr/}{,s}bin/unix_chkpwd Px,
|
||||||
|
|
||||||
# gssapi
|
# gssapi
|
||||||
@{etc_ro}/gss/mech r,
|
@{etc_ro}/gss/mech r,
|
||||||
@{etc_ro}/gss/mech.d/ r,
|
@{etc_ro}/gss/mech.d/ r,
|
||||||
|
@@ -13,6 +13,9 @@
|
|||||||
|
|
||||||
abi <abi/4.0>,
|
abi <abi/4.0>,
|
||||||
|
|
||||||
|
# Global config of openssl
|
||||||
|
include <abstractions/openssl>
|
||||||
|
|
||||||
@{etc_ro}/gcrypt/hwf.deny r,
|
@{etc_ro}/gcrypt/hwf.deny r,
|
||||||
@{etc_ro}/gcrypt/random.conf r,
|
@{etc_ro}/gcrypt/random.conf r,
|
||||||
@{PROC}/sys/crypto/fips_enabled r,
|
@{PROC}/sys/crypto/fips_enabled r,
|
||||||
@@ -24,4 +27,8 @@
|
|||||||
/etc/crypto-policies/*/*.txt r,
|
/etc/crypto-policies/*/*.txt r,
|
||||||
/usr/share/crypto-policies/*/*.txt r,
|
/usr/share/crypto-policies/*/*.txt r,
|
||||||
|
|
||||||
|
# Global gnutls config
|
||||||
|
@{etc_ro}/gnutls/config r,
|
||||||
|
@{etc_ro}/gnutls/pkcs11.conf r,
|
||||||
|
|
||||||
include if exists <abstractions/crypto.d>
|
include if exists <abstractions/crypto.d>
|
||||||
|
@@ -50,7 +50,6 @@
|
|||||||
include <abstractions/kde-icon-cache-write>
|
include <abstractions/kde-icon-cache-write>
|
||||||
include <abstractions/kde>
|
include <abstractions/kde>
|
||||||
include <abstractions/nameservice> # for IceProcessMessages () from libICE.so (called by libQtCore.so)
|
include <abstractions/nameservice> # for IceProcessMessages () from libICE.so (called by libQtCore.so)
|
||||||
include <abstractions/openssl>
|
|
||||||
include <abstractions/qt5>
|
include <abstractions/qt5>
|
||||||
include <abstractions/recent-documents-write>
|
include <abstractions/recent-documents-write>
|
||||||
include <abstractions/X>
|
include <abstractions/X>
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
abi <abi/4.0>,
|
abi <abi/4.0>,
|
||||||
include <tunables/global>
|
include <tunables/global>
|
||||||
|
|
||||||
profile firefox /usr/lib/firefox{,-esr}/firefox{,-esr} flags=(unconfined) {
|
profile firefox /usr/lib/firefox{,-esr,-beta,-devedition,-nightly}/firefox{,-esr,-bin} flags=(unconfined) {
|
||||||
userns,
|
userns,
|
||||||
|
|
||||||
# Site-specific additions and overrides. See local/README for details.
|
# Site-specific additions and overrides. See local/README for details.
|
||||||
|
12
profiles/apparmor.d/geary
Normal file
12
profiles/apparmor.d/geary
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# This profile allows everything and only exists to give the
|
||||||
|
# application a name instead of having the label "unconfined"
|
||||||
|
|
||||||
|
abi <abi/4.0>,
|
||||||
|
include <tunables/global>
|
||||||
|
|
||||||
|
profile geary /usr/bin/geary flags=(unconfined) {
|
||||||
|
userns,
|
||||||
|
|
||||||
|
# Site-specific additions and overrides. See local/README for details.
|
||||||
|
include if exists <local/geary>
|
||||||
|
}
|
12
profiles/apparmor.d/goldendict
Normal file
12
profiles/apparmor.d/goldendict
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# This profile allows everything and only exists to give the
|
||||||
|
# application a name instead of having the label "unconfined"
|
||||||
|
|
||||||
|
abi <abi/4.0>,
|
||||||
|
include <tunables/global>
|
||||||
|
|
||||||
|
profile goldendict /usr/bin/goldendict flags=(unconfined) {
|
||||||
|
userns,
|
||||||
|
|
||||||
|
# Site-specific additions and overrides. See local/README for details.
|
||||||
|
include if exists <local/goldendict>
|
||||||
|
}
|
12
profiles/apparmor.d/kchmviewer
Normal file
12
profiles/apparmor.d/kchmviewer
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# This profile allows everything and only exists to give the
|
||||||
|
# application a name instead of having the label "unconfined"
|
||||||
|
|
||||||
|
abi <abi/4.0>,
|
||||||
|
include <tunables/global>
|
||||||
|
|
||||||
|
profile kchmviewer /usr/bin/kchmviewer flags=(unconfined) {
|
||||||
|
userns,
|
||||||
|
|
||||||
|
# Site-specific additions and overrides. See local/README for details.
|
||||||
|
include if exists <local/kchmviewer>
|
||||||
|
}
|
12
profiles/apparmor.d/loupe
Normal file
12
profiles/apparmor.d/loupe
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# This profile allows everything and only exists to give the
|
||||||
|
# application a name instead of having the label "unconfined"
|
||||||
|
|
||||||
|
abi <abi/4.0>,
|
||||||
|
include <tunables/global>
|
||||||
|
|
||||||
|
profile loupe /usr/bin/loupe flags=(unconfined) {
|
||||||
|
userns,
|
||||||
|
|
||||||
|
# Site-specific additions and overrides. See local/README for details.
|
||||||
|
include if exists <local/loupe>
|
||||||
|
}
|
12
profiles/apparmor.d/notepadqq
Normal file
12
profiles/apparmor.d/notepadqq
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# This profile allows everything and only exists to give the
|
||||||
|
# application a name instead of having the label "unconfined"
|
||||||
|
|
||||||
|
abi <abi/4.0>,
|
||||||
|
include <tunables/global>
|
||||||
|
|
||||||
|
profile notepadqq /{{usr/bin,etc/alternatives}/notepadqq,usr/lib/notepadqq/notepadqq.sh} flags=(unconfined) {
|
||||||
|
userns,
|
||||||
|
|
||||||
|
# Site-specific additions and overrides. See local/README for details.
|
||||||
|
include if exists <local/notepadqq>
|
||||||
|
}
|
12
profiles/apparmor.d/pageedit
Normal file
12
profiles/apparmor.d/pageedit
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# This profile allows everything and only exists to give the
|
||||||
|
# application a name instead of having the label "unconfined"
|
||||||
|
|
||||||
|
abi <abi/4.0>,
|
||||||
|
include <tunables/global>
|
||||||
|
|
||||||
|
profile pageedit /usr/bin/pageedit flags=(unconfined) {
|
||||||
|
userns,
|
||||||
|
|
||||||
|
# Site-specific additions and overrides. See local/README for details.
|
||||||
|
include if exists <local/pageedit>
|
||||||
|
}
|
@@ -11,8 +11,6 @@ profile php-fpm /usr/sbin/php-fpm* flags=(attach_disconnected) {
|
|||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
# common php files and support files that php needs
|
# common php files and support files that php needs
|
||||||
include <abstractions/php>
|
include <abstractions/php>
|
||||||
# read openssl configuration
|
|
||||||
include <abstractions/openssl>
|
|
||||||
# read the system certificates
|
# read the system certificates
|
||||||
include <abstractions/ssl_certs>
|
include <abstractions/ssl_certs>
|
||||||
|
|
||||||
|
12
profiles/apparmor.d/privacybrowser
Normal file
12
profiles/apparmor.d/privacybrowser
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# This profile allows everything and only exists to give the
|
||||||
|
# application a name instead of having the label "unconfined"
|
||||||
|
|
||||||
|
abi <abi/4.0>,
|
||||||
|
include <tunables/global>
|
||||||
|
|
||||||
|
profile privacybrowser /usr/bin/privacybrowser flags=(unconfined) {
|
||||||
|
userns,
|
||||||
|
|
||||||
|
# Site-specific additions and overrides. See local/README for details.
|
||||||
|
include if exists <local/privacybrowser>
|
||||||
|
}
|
12
profiles/apparmor.d/qmapshack
Normal file
12
profiles/apparmor.d/qmapshack
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# This profile allows everything and only exists to give the
|
||||||
|
# application a name instead of having the label "unconfined"
|
||||||
|
|
||||||
|
abi <abi/4.0>,
|
||||||
|
include <tunables/global>
|
||||||
|
|
||||||
|
profile qmapshack /usr/bin/qmapshack flags=(unconfined) {
|
||||||
|
userns,
|
||||||
|
|
||||||
|
# Site-specific additions and overrides. See local/README for details.
|
||||||
|
include if exists <local/qmapshack>
|
||||||
|
}
|
12
profiles/apparmor.d/qutebrowser
Normal file
12
profiles/apparmor.d/qutebrowser
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# This profile allows everything and only exists to give the
|
||||||
|
# application a name instead of having the label "unconfined"
|
||||||
|
|
||||||
|
abi <abi/4.0>,
|
||||||
|
include <tunables/global>
|
||||||
|
|
||||||
|
profile qutebrowser /usr/bin/qutebrowser flags=(unconfined) {
|
||||||
|
userns,
|
||||||
|
|
||||||
|
# Site-specific additions and overrides. See local/README for details.
|
||||||
|
include if exists <local/qutebrowser>
|
||||||
|
}
|
12
profiles/apparmor.d/rssguard
Normal file
12
profiles/apparmor.d/rssguard
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# This profile allows everything and only exists to give the
|
||||||
|
# application a name instead of having the label "unconfined"
|
||||||
|
|
||||||
|
abi <abi/4.0>,
|
||||||
|
include <tunables/global>
|
||||||
|
|
||||||
|
profile rssguard /usr/bin/rssguard flags=(unconfined) {
|
||||||
|
userns,
|
||||||
|
|
||||||
|
# Site-specific additions and overrides. See local/README for details.
|
||||||
|
include if exists <local/rssguard>
|
||||||
|
}
|
@@ -6,7 +6,6 @@ profile samba-bgqd /usr/lib*/samba/{,samba/}samba-bgqd {
|
|||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/cups-client>
|
include <abstractions/cups-client>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/openssl>
|
|
||||||
include <abstractions/samba>
|
include <abstractions/samba>
|
||||||
|
|
||||||
signal receive set=term peer=smbd,
|
signal receive set=term peer=smbd,
|
||||||
|
@@ -22,7 +22,6 @@ profile syslog-ng /{usr/,}{bin,sbin}/syslog-ng {
|
|||||||
include <abstractions/consoles>
|
include <abstractions/consoles>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/mysql>
|
include <abstractions/mysql>
|
||||||
include <abstractions/openssl>
|
|
||||||
include <abstractions/python>
|
include <abstractions/python>
|
||||||
include <abstractions/hosts_access>
|
include <abstractions/hosts_access>
|
||||||
|
|
||||||
|
13
profiles/apparmor.d/scide
Normal file
13
profiles/apparmor.d/scide
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# This profile allows everything and only exists to give the
|
||||||
|
# application a name instead of having the label "unconfined"
|
||||||
|
|
||||||
|
abi <abi/4.0>,
|
||||||
|
include <tunables/global>
|
||||||
|
|
||||||
|
#supercollider-ide
|
||||||
|
profile scide /usr/bin/scide flags=(unconfined) {
|
||||||
|
userns,
|
||||||
|
|
||||||
|
# Site-specific additions and overrides. See local/README for details.
|
||||||
|
include if exists <local/scide>
|
||||||
|
}
|
35
profiles/apparmor.d/unix-chkpwd
Normal file
35
profiles/apparmor.d/unix-chkpwd
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# apparmor.d - Full set of apparmor profiles
|
||||||
|
# Copyright (C) 2019-2021 Mikhail Morfikov
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
# The apparmor.d project comes with several variables and abstractions
|
||||||
|
# that are not part of upstream AppArmor yet. Therefore this profile was
|
||||||
|
# adopted to use abstractions and variables that are available.
|
||||||
|
# Copyright (C) Christian Boltz 2024
|
||||||
|
|
||||||
|
abi <abi/4.0>,
|
||||||
|
|
||||||
|
include <tunables/global>
|
||||||
|
|
||||||
|
profile unix-chkpwd /{,usr/}{,s}bin/unix_chkpwd {
|
||||||
|
include <abstractions/base>
|
||||||
|
include <abstractions/nameservice>
|
||||||
|
|
||||||
|
# To write records to the kernel auditing log.
|
||||||
|
capability audit_write,
|
||||||
|
|
||||||
|
network netlink raw,
|
||||||
|
|
||||||
|
/{,usr/}{,s}bin/unix_chkpwd mr,
|
||||||
|
|
||||||
|
/etc/shadow r,
|
||||||
|
|
||||||
|
# systemd userdb, used in nspawn
|
||||||
|
/run/host/userdb/*.user r,
|
||||||
|
/run/host/userdb/*.user-privileged r,
|
||||||
|
|
||||||
|
# file_inherit
|
||||||
|
owner /dev/tty[0-9]* rw,
|
||||||
|
|
||||||
|
include if exists <local/unix-chkpwd>
|
||||||
|
}
|
@@ -19,7 +19,6 @@ profile dovecot-auth /usr/lib*/dovecot/auth {
|
|||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/mysql>
|
include <abstractions/mysql>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/openssl>
|
|
||||||
include <abstractions/wutmp>
|
include <abstractions/wutmp>
|
||||||
include <abstractions/dovecot-common>
|
include <abstractions/dovecot-common>
|
||||||
|
|
||||||
|
@@ -17,7 +17,6 @@ profile dovecot-dict /usr/lib*/dovecot/dict {
|
|||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/mysql>
|
include <abstractions/mysql>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/openssl>
|
|
||||||
include <abstractions/dovecot-common>
|
include <abstractions/dovecot-common>
|
||||||
|
|
||||||
capability setuid,
|
capability setuid,
|
||||||
|
@@ -17,7 +17,6 @@ include <tunables/global>
|
|||||||
profile dovecot-imap-login /usr/lib*/dovecot/imap-login {
|
profile dovecot-imap-login /usr/lib*/dovecot/imap-login {
|
||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/dovecot-common>
|
include <abstractions/dovecot-common>
|
||||||
include <abstractions/openssl>
|
|
||||||
|
|
||||||
capability setuid,
|
capability setuid,
|
||||||
capability sys_chroot,
|
capability sys_chroot,
|
||||||
|
@@ -18,7 +18,6 @@ profile dovecot-lmtp /usr/lib*/dovecot/lmtp {
|
|||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/dovecot-common>
|
include <abstractions/dovecot-common>
|
||||||
include <abstractions/openssl>
|
|
||||||
include <abstractions/ssl_certs>
|
include <abstractions/ssl_certs>
|
||||||
include <abstractions/ssl_keys>
|
include <abstractions/ssl_keys>
|
||||||
|
|
||||||
|
@@ -19,7 +19,6 @@ include <tunables/global>
|
|||||||
profile dovecot-managesieve-login /usr/lib*/dovecot/managesieve-login {
|
profile dovecot-managesieve-login /usr/lib*/dovecot/managesieve-login {
|
||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/dovecot-common>
|
include <abstractions/dovecot-common>
|
||||||
include <abstractions/openssl>
|
|
||||||
|
|
||||||
capability setuid,
|
capability setuid,
|
||||||
capability sys_chroot,
|
capability sys_chroot,
|
||||||
|
@@ -17,7 +17,6 @@ include <tunables/global>
|
|||||||
profile dovecot-pop3-login /usr/lib*/dovecot/pop3-login {
|
profile dovecot-pop3-login /usr/lib*/dovecot/pop3-login {
|
||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/dovecot-common>
|
include <abstractions/dovecot-common>
|
||||||
include <abstractions/openssl>
|
|
||||||
|
|
||||||
capability setuid,
|
capability setuid,
|
||||||
capability sys_chroot,
|
capability sys_chroot,
|
||||||
|
@@ -16,7 +16,6 @@ include <tunables/ntpd>
|
|||||||
profile ntpd /usr/{bin,sbin}/{,open}ntpd flags=(attach_disconnected) {
|
profile ntpd /usr/{bin,sbin}/{,open}ntpd flags=(attach_disconnected) {
|
||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/openssl>
|
|
||||||
include <abstractions/ssl_certs>
|
include <abstractions/ssl_certs>
|
||||||
include <abstractions/xad>
|
include <abstractions/xad>
|
||||||
|
|
||||||
|
@@ -8,7 +8,6 @@ profile smbd /usr/{bin,sbin}/smbd {
|
|||||||
include <abstractions/consoles>
|
include <abstractions/consoles>
|
||||||
include <abstractions/cups-client>
|
include <abstractions/cups-client>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/openssl>
|
|
||||||
include <abstractions/samba>
|
include <abstractions/samba>
|
||||||
include <abstractions/user-tmp>
|
include <abstractions/user-tmp>
|
||||||
include <abstractions/wutmp>
|
include <abstractions/wutmp>
|
||||||
@@ -50,7 +49,6 @@ profile smbd /usr/{bin,sbin}/smbd {
|
|||||||
/usr/share/samba/** r,
|
/usr/share/samba/** r,
|
||||||
/usr/{bin,sbin}/smbd mr,
|
/usr/{bin,sbin}/smbd mr,
|
||||||
/usr/{bin,sbin}/smbldap-useradd Px,
|
/usr/{bin,sbin}/smbldap-useradd Px,
|
||||||
/usr/sbin/unix_chkpwd Px,
|
|
||||||
/var/cache/samba/** rwk,
|
/var/cache/samba/** rwk,
|
||||||
/var/{cache,lib}/samba/printing/printers.tdb mrw,
|
/var/{cache,lib}/samba/printing/printers.tdb mrw,
|
||||||
/var/lib/nscd/netgroup r,
|
/var/lib/nscd/netgroup r,
|
||||||
@@ -63,8 +61,6 @@ profile smbd /usr/{bin,sbin}/smbd {
|
|||||||
@{run}/samba/ncalrpc/** rw,
|
@{run}/samba/ncalrpc/** rw,
|
||||||
/var/spool/samba/** rw,
|
/var/spool/samba/** rw,
|
||||||
|
|
||||||
owner /proc/@{pid}/loginuid r,
|
|
||||||
|
|
||||||
@{HOMEDIRS}/** lrwk,
|
@{HOMEDIRS}/** lrwk,
|
||||||
/var/lib/samba/usershares/{,**} lrwk,
|
/var/lib/samba/usershares/{,**} lrwk,
|
||||||
|
|
||||||
|
@@ -17,7 +17,6 @@ include <tunables/global>
|
|||||||
profile postfix-proxymap /usr/lib/postfix/{bin/,sbin/,}proxymap {
|
profile postfix-proxymap /usr/lib/postfix/{bin/,sbin/,}proxymap {
|
||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/openssl>
|
|
||||||
include <abstractions/postfix-common>
|
include <abstractions/postfix-common>
|
||||||
|
|
||||||
/etc/my.cnf r,
|
/etc/my.cnf r,
|
||||||
|
@@ -18,7 +18,6 @@ profile postfix-smtp /usr/lib/postfix/{bin/,sbin/,}smtp {
|
|||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/postfix-common>
|
include <abstractions/postfix-common>
|
||||||
include <abstractions/openssl>
|
|
||||||
|
|
||||||
capability dac_override,
|
capability dac_override,
|
||||||
capability dac_read_search,
|
capability dac_read_search,
|
||||||
|
@@ -18,7 +18,6 @@ profile postfix-smtpd /usr/lib/postfix/{bin/,sbin/,}smtpd {
|
|||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/postfix-common>
|
include <abstractions/postfix-common>
|
||||||
include <abstractions/openssl>
|
|
||||||
include <abstractions/ssl_certs>
|
include <abstractions/ssl_certs>
|
||||||
include <abstractions/ssl_keys>
|
include <abstractions/ssl_keys>
|
||||||
|
|
||||||
|
@@ -17,7 +17,6 @@ include <tunables/global>
|
|||||||
profile postfix-tlsmgr /usr/lib/postfix/{bin/,sbin/,}tlsmgr {
|
profile postfix-tlsmgr /usr/lib/postfix/{bin/,sbin/,}tlsmgr {
|
||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/openssl>
|
|
||||||
include <abstractions/postfix-common>
|
include <abstractions/postfix-common>
|
||||||
|
|
||||||
/usr/lib/postfix/{bin/,sbin/,}tlsmgr mrix,
|
/usr/lib/postfix/{bin/,sbin/,}tlsmgr mrix,
|
||||||
|
@@ -26,7 +26,6 @@ include <tunables/global>
|
|||||||
profile dhclient /{usr/,}sbin/dhclient {
|
profile dhclient /{usr/,}sbin/dhclient {
|
||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/bash>
|
include <abstractions/bash>
|
||||||
include <abstractions/openssl>
|
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
|
|
||||||
capability net_raw,
|
capability net_raw,
|
||||||
|
@@ -17,7 +17,6 @@ include <tunables/global>
|
|||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/consoles>
|
include <abstractions/consoles>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/openssl>
|
|
||||||
|
|
||||||
capability setgid,
|
capability setgid,
|
||||||
capability setuid,
|
capability setuid,
|
||||||
|
@@ -13,7 +13,6 @@ include <tunables/global>
|
|||||||
profile clamd /usr/sbin/clamd {
|
profile clamd /usr/sbin/clamd {
|
||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/openssl>
|
|
||||||
|
|
||||||
capability setgid,
|
capability setgid,
|
||||||
capability setuid,
|
capability setuid,
|
||||||
|
@@ -13,7 +13,6 @@ include <tunables/global>
|
|||||||
profile haproxy /usr/sbin/haproxy {
|
profile haproxy /usr/sbin/haproxy {
|
||||||
include <abstractions/base>
|
include <abstractions/base>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/openssl>
|
|
||||||
capability net_admin,
|
capability net_admin,
|
||||||
capability net_bind_service,
|
capability net_bind_service,
|
||||||
capability setgid,
|
capability setgid,
|
||||||
|
@@ -20,7 +20,6 @@ include <tunables/global>
|
|||||||
include <abstractions/kerberosclient>
|
include <abstractions/kerberosclient>
|
||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/perl>
|
include <abstractions/perl>
|
||||||
include <abstractions/openssl>
|
|
||||||
|
|
||||||
capability kill,
|
capability kill,
|
||||||
capability net_bind_service,
|
capability net_bind_service,
|
||||||
|
@@ -17,7 +17,6 @@ include <tunables/global>
|
|||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/authentication>
|
include <abstractions/authentication>
|
||||||
include <abstractions/user-mail>
|
include <abstractions/user-mail>
|
||||||
include <abstractions/openssl>
|
|
||||||
|
|
||||||
/dev/urandom r,
|
/dev/urandom r,
|
||||||
/tmp/* rwl,
|
/tmp/* rwl,
|
||||||
|
@@ -17,7 +17,6 @@ include <tunables/global>
|
|||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/authentication>
|
include <abstractions/authentication>
|
||||||
include <abstractions/user-mail>
|
include <abstractions/user-mail>
|
||||||
include <abstractions/openssl>
|
|
||||||
|
|
||||||
/dev/urandom r ,
|
/dev/urandom r ,
|
||||||
/tmp/.* rwl ,
|
/tmp/.* rwl ,
|
||||||
|
@@ -17,7 +17,6 @@ include <tunables/global>
|
|||||||
include <abstractions/nameservice>
|
include <abstractions/nameservice>
|
||||||
include <abstractions/authentication>
|
include <abstractions/authentication>
|
||||||
include <abstractions/user-mail>
|
include <abstractions/user-mail>
|
||||||
include <abstractions/openssl>
|
|
||||||
|
|
||||||
/dev/urandom r ,
|
/dev/urandom r ,
|
||||||
/tmp/.* rwl ,
|
/tmp/.* rwl ,
|
||||||
|
@@ -97,16 +97,20 @@ do_tests "ipv4 udp no conds" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remot
|
|||||||
generate_profile="genprofile network $sender:px -- image=$sender network"
|
generate_profile="genprofile network $sender:px -- image=$sender network"
|
||||||
do_tests "ipv4 tcp no conds" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
|
do_tests "ipv4 tcp no conds" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
|
||||||
|
|
||||||
generate_profile="genprofile network;ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port)"
|
setsockopt_rules="network;(setopt,getopt);ip=0.0.0.0;port=0"
|
||||||
|
rcv_rules="network;ip=$bind_ipv4;peer=(ip=anon)"
|
||||||
|
snd_rules="network;ip=$remote_ipv4;peer=(ip=anon)"
|
||||||
|
|
||||||
|
generate_profile="genprofile network;ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $setsockopt_rules $rcv_rules $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port) $setsockopt_rules $snd_rules"
|
||||||
do_tests "ipv4 udp generic perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile"
|
do_tests "ipv4 udp generic perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile"
|
||||||
|
|
||||||
generate_profile="genprofile network;ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port)"
|
generate_profile="genprofile network;ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $setsockopt_rules $rcv_rules $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port) $setsockopt_rules $snd_rules"
|
||||||
do_tests "ipv4 tcp generic perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
|
do_tests "ipv4 tcp generic perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
|
||||||
|
|
||||||
generate_profile="genprofile network;(connect,receive,send);ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port)"
|
generate_profile="genprofile network;(connect,receive,send);ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $setsockopt_rules $rcv_rules $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port) $setsockopt_rules $snd_rules"
|
||||||
do_tests "ipv4 udp specific perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile"
|
do_tests "ipv4 udp specific perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile"
|
||||||
|
|
||||||
generate_profile="genprofile network;(connect,receive,send);ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port)"
|
generate_profile="genprofile network;(connect,receive,send);ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $setsockopt_rules $rcv_rules $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port) $setsockopt_rules $snd_rules"
|
||||||
do_tests "ipv4 tcp specific perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
|
do_tests "ipv4 tcp specific perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
|
||||||
|
|
||||||
removeprofile
|
removeprofile
|
||||||
@@ -122,10 +126,14 @@ do_tests "ipv6 udp no conds" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remot
|
|||||||
generate_profile="genprofile network $sender:px -- image=$sender network"
|
generate_profile="genprofile network $sender:px -- image=$sender network"
|
||||||
do_tests "ipv6 tcp no conds" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"
|
do_tests "ipv6 tcp no conds" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"
|
||||||
|
|
||||||
generate_profile="genprofile network;ip=$bind_ipv6;port=$bind_port;peer=(ip=$remote_ipv6,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv6;port=$remote_port;peer=(ip=$bind_ipv6,port=$bind_port)"
|
setsockopt_rules="network;(setopt,getopt);ip=::0;port=0"
|
||||||
|
rcv_rules="network;ip=$bind_ipv6;peer=(ip=anon)"
|
||||||
|
snd_rules="network;ip=$remote_ipv6;peer=(ip=anon)"
|
||||||
|
|
||||||
|
generate_profile="genprofile network;ip=$bind_ipv6;port=$bind_port;peer=(ip=$remote_ipv6,port=$remote_port) $setsockopt_rules $rcv_rules $sender:px -- image=$sender network;ip=$remote_ipv6;port=$remote_port;peer=(ip=$bind_ipv6,port=$bind_port) $setsockopt_rules $snd_rules"
|
||||||
do_tests "ipv6 udp generic perms" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port udp "$generate_profile"
|
do_tests "ipv6 udp generic perms" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port udp "$generate_profile"
|
||||||
|
|
||||||
generate_profile="genprofile network;ip=$bind_ipv6;port=$bind_port;peer=(ip=$remote_ipv6,port=$remote_port) $sender:px -- image=$sender network;ip=$remote_ipv6;port=$remote_port;peer=(ip=$bind_ipv6,port=$bind_port)"
|
generate_profile="genprofile network;ip=$bind_ipv6;port=$bind_port;peer=(ip=$remote_ipv6,port=$remote_port) $setsockopt_rules $rcv_rules $sender:px -- image=$sender network;ip=$remote_ipv6;port=$remote_port;peer=(ip=$bind_ipv6,port=$bind_port) $setsockopt_rules $snd_rules"
|
||||||
do_tests "ipv6 tcp generic perms" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"
|
do_tests "ipv6 tcp generic perms" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"
|
||||||
|
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@ import re
|
|||||||
from apparmor.common import AppArmorBug, AppArmorException
|
from apparmor.common import AppArmorBug, AppArmorException
|
||||||
|
|
||||||
from apparmor.regex import RE_PROFILE_MOUNT, RE_PROFILE_PATH_OR_VAR, strip_parenthesis
|
from apparmor.regex import RE_PROFILE_MOUNT, RE_PROFILE_PATH_OR_VAR, strip_parenthesis
|
||||||
# from apparmor.rule import AARE
|
from apparmor.rule import AARE
|
||||||
from apparmor.rule import BaseRule, BaseRuleset, parse_modifiers, logprof_value_or_all, check_and_split_list
|
from apparmor.rule import BaseRule, BaseRuleset, parse_modifiers, logprof_value_or_all, check_and_split_list
|
||||||
|
|
||||||
from apparmor.translations import init_translation
|
from apparmor.translations import init_translation
|
||||||
@@ -25,7 +25,7 @@ _ = init_translation()
|
|||||||
|
|
||||||
# TODO :
|
# TODO :
|
||||||
# - match correctly AARE on every field
|
# - match correctly AARE on every field
|
||||||
# - Find the actual list of supported filesystems. This one comes from /proc/filesystems
|
# - Find the actual list of supported filesystems. This one comes from /proc/filesystems. We also blindly accept fuse.*
|
||||||
# - Support path that begin by { (e.g. {,/usr}/lib/...) This syntax is not a valid AARE but is used by usr.lib.snapd.snap-confine.real in Ubuntu and will currently raise an error in genprof if these lines are not modified.
|
# - Support path that begin by { (e.g. {,/usr}/lib/...) This syntax is not a valid AARE but is used by usr.lib.snapd.snap-confine.real in Ubuntu and will currently raise an error in genprof if these lines are not modified.
|
||||||
# - Apparmor remount logs are displayed as mount (with remount flag). Profiles generated with aa-genprof are therefore mount rules. It could be interesting to make them remount rules.
|
# - Apparmor remount logs are displayed as mount (with remount flag). Profiles generated with aa-genprof are therefore mount rules. It could be interesting to make them remount rules.
|
||||||
|
|
||||||
@@ -33,8 +33,10 @@ valid_fs = [
|
|||||||
'sysfs', 'tmpfs', 'bdevfs', 'procfs', 'cgroup', 'cgroup2', 'cpuset', 'devtmpfs', 'configfs', 'debugfs', 'tracefs',
|
'sysfs', 'tmpfs', 'bdevfs', 'procfs', 'cgroup', 'cgroup2', 'cpuset', 'devtmpfs', 'configfs', 'debugfs', 'tracefs',
|
||||||
'securityfs', 'sockfs', 'bpf', 'npipefs', 'ramfs', 'hugetlbfs', 'devpts', 'ext3', 'ext2', 'ext4', 'squashfs',
|
'securityfs', 'sockfs', 'bpf', 'npipefs', 'ramfs', 'hugetlbfs', 'devpts', 'ext3', 'ext2', 'ext4', 'squashfs',
|
||||||
'vfat', 'ecryptfs', 'fuseblk', 'fuse', 'fusectl', 'efivarfs', 'mqueue', 'store', 'autofs', 'binfmt_misc', 'overlay',
|
'vfat', 'ecryptfs', 'fuseblk', 'fuse', 'fusectl', 'efivarfs', 'mqueue', 'store', 'autofs', 'binfmt_misc', 'overlay',
|
||||||
'none', 'bdev', 'proc', 'pipefs', 'pstore', 'btrfs', 'xfs', '9p',
|
'none', 'bdev', 'proc', 'pipefs', 'pstore', 'btrfs', 'xfs', '9p', 'resctrl', 'zfs', 'iso9660', 'udf', 'ntfs3',
|
||||||
|
'nfs', 'cifs',
|
||||||
]
|
]
|
||||||
|
|
||||||
flags_keywords = [
|
flags_keywords = [
|
||||||
# keep in sync with parser/mount.cc mnt_opts_table!
|
# keep in sync with parser/mount.cc mnt_opts_table!
|
||||||
'ro', 'r', 'read-only', 'rw', 'w', 'suid', 'nosuid', 'dev', 'nodev', 'exec', 'noexec', 'sync', 'async', 'remount',
|
'ro', 'r', 'read-only', 'rw', 'w', 'suid', 'nosuid', 'dev', 'nodev', 'exec', 'noexec', 'sync', 'async', 'remount',
|
||||||
@@ -43,16 +45,19 @@ flags_keywords = [
|
|||||||
'make-runbindable', 'private', 'make-private', 'rprivate', 'make-rprivate', 'slave', 'make-slave', 'rslave', 'make-rslave',
|
'make-runbindable', 'private', 'make-private', 'rprivate', 'make-rprivate', 'slave', 'make-slave', 'rslave', 'make-rslave',
|
||||||
'shared', 'make-shared', 'rshared', 'make-rshared', 'relatime', 'norelatime', 'iversion', 'noiversion', 'strictatime',
|
'shared', 'make-shared', 'rshared', 'make-rshared', 'relatime', 'norelatime', 'iversion', 'noiversion', 'strictatime',
|
||||||
'nostrictatime', 'lazytime', 'nolazytime', 'user', 'nouser',
|
'nostrictatime', 'lazytime', 'nolazytime', 'user', 'nouser',
|
||||||
'([A-Za-z0-9]|AARE)', # TODO: handle AARE
|
'([A-Za-z0-9])',
|
||||||
]
|
]
|
||||||
join_valid_flags = '|'.join(flags_keywords)
|
join_valid_flags = '|'.join(flags_keywords)
|
||||||
join_valid_fs = '|'.join(valid_fs)
|
join_valid_fs = '|'.join(valid_fs)
|
||||||
|
|
||||||
sep = r'\s*[\s,]\s*'
|
sep = r'\s*[\s,]\s*'
|
||||||
|
|
||||||
|
# We aim to be a bit more restrictive than \S+ used in regex.py
|
||||||
|
FS_AARE = r'([][".*@{}\w^-]+)'
|
||||||
|
|
||||||
fs_type_pattern = r'\b(?P<fstype_or_vfstype>fstype|vfstype)\b\s*(?P<fstype_equals_or_in>=|in)\s*'\
|
fs_type_pattern = r'\b(?P<fstype_or_vfstype>fstype|vfstype)\b\s*(?P<fstype_equals_or_in>=|in)\s*'\
|
||||||
r'(?P<fstype>\(\s*(' + join_valid_fs + r')(' + sep + r'(' + join_valid_fs + r'))*\s*\)|'\
|
r'(?P<fstype>\(\s*(' + FS_AARE + r')(' + sep + r'(' + FS_AARE + r'))*\s*\)|'\
|
||||||
r'\{\s*(' + join_valid_fs + r')(' + sep + r'(' + join_valid_fs + r'))*\s*\}|(\s*' + join_valid_fs + r'))'\
|
r'\{\s*(' + FS_AARE + r')(' + sep + r'(' + FS_AARE + r'))*\s*\}|(\s*' + FS_AARE + r'))'\
|
||||||
|
|
||||||
|
|
||||||
option_pattern = r'\s*(\boption(s?)\b\s*(?P<options_equals_or_in>=|in)\s*'\
|
option_pattern = r'\s*(\boption(s?)\b\s*(?P<options_equals_or_in>=|in)\s*'\
|
||||||
@@ -63,9 +68,12 @@ mount_condition_pattern = rf'({fs_type_pattern})?\s*({option_pattern})?'
|
|||||||
|
|
||||||
# Source can either be
|
# Source can either be
|
||||||
# - A path : /foo
|
# - A path : /foo
|
||||||
|
# - A globbed Path : {,/usr}/lib{,32,64,x32}/modules/
|
||||||
# - A filesystem : sysfs (sudo mount -t tmpfs tmpfs /tmp/bar)
|
# - A filesystem : sysfs (sudo mount -t tmpfs tmpfs /tmp/bar)
|
||||||
# - Any label : mntlabel (sudo mount -t tmpfs mntlabel /tmp/bar)
|
# - Any label : mntlabel (sudo mount -t tmpfs mntlabel /tmp/bar)
|
||||||
source_fileglob_pattern = r'(\s*' + (RE_PROFILE_PATH_OR_VAR % 'source_file')[:-1] + r'|' + r'\w+' + r'))'
|
# Thus we cannot use directly RE_PROFILE_PATH_OR_VAR
|
||||||
|
|
||||||
|
source_fileglob_pattern = r'(\s*(?P<source_file>([/{]\S*|"[/{][^"]*"|@{\S+}\S*|"@{\S+}[^"]*")|\w+))'
|
||||||
dest_fileglob_pattern = r'(\s*' + RE_PROFILE_PATH_OR_VAR % 'dest_file' + r')'
|
dest_fileglob_pattern = r'(\s*' + RE_PROFILE_PATH_OR_VAR % 'dest_file' + r')'
|
||||||
|
|
||||||
RE_MOUNT_DETAILS = re.compile(r'^\s*' + mount_condition_pattern + rf'(\s+{source_fileglob_pattern})?' + rf'(\s+->\s+{dest_fileglob_pattern})?\s*' + r'$')
|
RE_MOUNT_DETAILS = re.compile(r'^\s*' + mount_condition_pattern + rf'(\s+{source_fileglob_pattern})?' + rf'(\s+->\s+{dest_fileglob_pattern})?\s*' + r'$')
|
||||||
@@ -95,8 +103,25 @@ class MountRule(BaseRule):
|
|||||||
self.operation = operation
|
self.operation = operation
|
||||||
|
|
||||||
self.fstype, self.all_fstype, unknown_items = check_and_split_list(fstype[1] if fstype != self.ALL else fstype, valid_fs, self.ALL, type(self).__name__, 'fstype')
|
self.fstype, self.all_fstype, unknown_items = check_and_split_list(fstype[1] if fstype != self.ALL else fstype, valid_fs, self.ALL, type(self).__name__, 'fstype')
|
||||||
|
|
||||||
if unknown_items:
|
if unknown_items:
|
||||||
raise AppArmorException(_('Passed unknown fstype keyword to %s: %s') % (type(self).__name__, ' '.join(unknown_items)))
|
for it in unknown_items:
|
||||||
|
|
||||||
|
# Several filesystems use fuse internally and are referred as fuse.<software_name> (e.g. fuse.jmtpfs, fuse.s3fs, fuse.obexfs).
|
||||||
|
# Since this list seems to evolve too fast for a fixed list to work in practice, we just accept fuse.*
|
||||||
|
# See https://github.com/libfuse/libfuse/wiki/Filesystems and, https://doc.ubuntu-fr.org/fuse
|
||||||
|
if it.startswith('fuse.') and len(it) > 5:
|
||||||
|
continue
|
||||||
|
|
||||||
|
it = AARE(it, is_path=False)
|
||||||
|
found = False
|
||||||
|
for fs in valid_fs:
|
||||||
|
if self._is_covered_aare(it, self.all_fstype, AARE(fs, False), self.all_fstype, 'fstype'):
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
if not found:
|
||||||
|
raise AppArmorException(_('Passed unknown fstype keyword to %s: %s') % (type(self).__name__, ' '.join(unknown_items)))
|
||||||
|
|
||||||
self.is_fstype_equal = fstype[0] if not self.all_fstype else None
|
self.is_fstype_equal = fstype[0] if not self.all_fstype else None
|
||||||
|
|
||||||
self.options, self.all_options, unknown_items = check_and_split_list(options[1] if options != self.ALL else options, flags_keywords, self.ALL, type(self).__name__, 'options')
|
self.options, self.all_options, unknown_items = check_and_split_list(options[1] if options != self.ALL else options, flags_keywords, self.ALL, type(self).__name__, 'options')
|
||||||
@@ -213,8 +238,15 @@ class MountRule(BaseRule):
|
|||||||
return False
|
return False
|
||||||
if self.is_options_equal != other_rule.is_options_equal:
|
if self.is_options_equal != other_rule.is_options_equal:
|
||||||
return False
|
return False
|
||||||
if not self._is_covered_list(self.fstype, self.all_fstype, other_rule.fstype, other_rule.all_fstype, 'fstype'):
|
|
||||||
return False
|
for o_it in other_rule.fstype or []:
|
||||||
|
found = False
|
||||||
|
for s_it in self.fstype or []:
|
||||||
|
if self._is_covered_aare(AARE(s_it, False), self.all_fstype, AARE(o_it, False), other_rule.all_fstype, 'fstype'):
|
||||||
|
found = True
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
return False
|
||||||
if not self._is_covered_list(self.options, self.all_options, other_rule.options, other_rule.all_options, 'options'):
|
if not self._is_covered_list(self.options, self.all_options, other_rule.options, other_rule.all_options, 'options'):
|
||||||
return False
|
return False
|
||||||
if not self._is_covered_aare(self.source, self.all_source, other_rule.source, other_rule.all_source, 'source'):
|
if not self._is_covered_aare(self.source, self.all_source, other_rule.source, other_rule.all_source, 'source'):
|
||||||
|
@@ -140,7 +140,8 @@ Feb 4 13:40:38 XPS-13-9370 kernel: [128552.880347] audit: type=1400 audit({epoc
|
|||||||
if 'SUDO_USER' in os.environ:
|
if 'SUDO_USER' in os.environ:
|
||||||
username = os.environ.get('SUDO_USER')
|
username = os.environ.get('SUDO_USER')
|
||||||
|
|
||||||
return_code, output = cmd(['last', '-1', username, '--time-format', 'iso'])
|
return_code, output = cmd(['last', username, '--time-format', 'iso'])
|
||||||
|
output = output.split('\n')[0] # the first line is enough
|
||||||
# example of output:
|
# example of output:
|
||||||
# ubuntu tty7 :0 2024-01-05T14:29:11-03:00 gone - no logout
|
# ubuntu tty7 :0 2024-01-05T14:29:11-03:00 gone - no logout
|
||||||
if output.startswith(username):
|
if output.startswith(username):
|
||||||
|
@@ -30,7 +30,9 @@ class MountTestParse(AATest):
|
|||||||
tests = (
|
tests = (
|
||||||
# Rule Operation Filesystem Options Source Destination Audit Deny Allow Comment
|
# Rule Operation Filesystem Options Source Destination Audit Deny Allow Comment
|
||||||
('mount fstype=bpf options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ('bpf')), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )),
|
('mount fstype=bpf options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ('bpf')), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )),
|
||||||
('mount fstype=bpf options=(rw) random_label -> /sys/fs/bpf/,', MountRule('mount', ('=', ('bpf')), ('=', ('rw')), 'random_label', '/sys/fs/bpf/', False, False, False, '' )),
|
('mount fstype=fuse.obex* options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ('fuse.obex*')), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )),
|
||||||
|
('mount fstype=fuse.* options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ('fuse.*')), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )),
|
||||||
|
('mount fstype=bpf options=(rw) random_label -> /sys/fs/bpf/,', MountRule('mount', ('=', ("bpf")), ('=', ('rw')), 'random_label', '/sys/fs/bpf/', False, False, False, '' )),
|
||||||
('mount,', MountRule('mount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
('mount,', MountRule('mount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
||||||
('mount fstype=(ext3, ext4),', MountRule('mount', ('=', ('ext3', 'ext4')), MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
('mount fstype=(ext3, ext4),', MountRule('mount', ('=', ('ext3', 'ext4')), MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
||||||
('mount bpf,', MountRule('mount', MountRule.ALL, MountRule.ALL, 'bpf', MountRule.ALL, False, False, False, '' )),
|
('mount bpf,', MountRule('mount', MountRule.ALL, MountRule.ALL, 'bpf', MountRule.ALL, False, False, False, '' )),
|
||||||
@@ -45,8 +47,8 @@ class MountTestParse(AATest):
|
|||||||
('mount fstype in (ext3, ext4) options=(ro, rbind) /a -> /b, #cmt', MountRule('mount', ('in', ('ext3', 'ext4')), ('=', ('ro', 'rbind')), '/a', '/b', False, False, False, ' #cmt')),
|
('mount fstype in (ext3, ext4) options=(ro, rbind) /a -> /b, #cmt', MountRule('mount', ('in', ('ext3', 'ext4')), ('=', ('ro', 'rbind')), '/a', '/b', False, False, False, ' #cmt')),
|
||||||
('mount fstype in (ext3, ext4) option in (ro, rbind) /a, #cmt', MountRule('mount', ('in', ('ext3', 'ext4')), ('in', ('ro', 'rbind')), '/a', MountRule.ALL, False, False, False, ' #cmt')),
|
('mount fstype in (ext3, ext4) option in (ro, rbind) /a, #cmt', MountRule('mount', ('in', ('ext3', 'ext4')), ('in', ('ro', 'rbind')), '/a', MountRule.ALL, False, False, False, ' #cmt')),
|
||||||
('mount fstype=(ext3, ext4) option=(ro, rbind) /a -> /b, #cmt', MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro', 'rbind')), '/a', '/b', False, False, False, ' #cmt')),
|
('mount fstype=(ext3, ext4) option=(ro, rbind) /a -> /b, #cmt', MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro', 'rbind')), '/a', '/b', False, False, False, ' #cmt')),
|
||||||
('mount options=(rw, rbind) /usr/lib{,32,64,x32}/modules/ -> /tmp/snap.rootfs_*{,/usr}/lib/modules/,',
|
('mount options=(rw, rbind) {,/usr}/lib{,32,64,x32}/modules/ -> /tmp/snap.rootfs_*{,/usr}/lib/modules/,',
|
||||||
MountRule('mount', MountRule.ALL, ('=', ('rw', 'rbind')), '/usr/lib{,32,64,x32}/modules/',
|
MountRule('mount', MountRule.ALL, ('=', ('rw', 'rbind')), '{,/usr}/lib{,32,64,x32}/modules/',
|
||||||
'/tmp/snap.rootfs_*{,/usr}/lib/modules/',
|
'/tmp/snap.rootfs_*{,/usr}/lib/modules/',
|
||||||
False, False, False, '' )),
|
False, False, False, '' )),
|
||||||
('umount,', MountRule('umount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
('umount,', MountRule('umount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
||||||
@@ -207,6 +209,16 @@ class MountIsCoveredTest(AATest):
|
|||||||
self.assertTrue(obj.is_covered(MountRule('mount', ('=', ('ext3')), ('=', ('ro')), 'tmpfs', MountRule.ALL)))
|
self.assertTrue(obj.is_covered(MountRule('mount', ('=', ('ext3')), ('=', ('ro')), 'tmpfs', MountRule.ALL)))
|
||||||
self.assertFalse(obj.is_equal(MountRule('mount', ('=', ('ext3')), ('=', ('ro')), 'tmpfs', MountRule.ALL)))
|
self.assertFalse(obj.is_equal(MountRule('mount', ('=', ('ext3')), ('=', ('ro')), 'tmpfs', MountRule.ALL)))
|
||||||
|
|
||||||
|
def test_is_covered_regex(self):
|
||||||
|
obj = MountRule('mount', ('=', ('sys*', 'fuse.*')), ('=', ('ro')), 'tmpfs', MountRule.ALL)
|
||||||
|
tests = [
|
||||||
|
('mount', ('=', ('sysfs', 'fuse.s3fs')), ('=', ('ro')), 'tmpfs', MountRule.ALL),
|
||||||
|
('mount', ('=', ('sysfs', 'fuse.jmtpfs', 'fuse.s3fs', 'fuse.obexfs', 'fuse.obexautofs', 'fuse.fuseiso')), ('=', ('ro')), 'tmpfs', MountRule.ALL)
|
||||||
|
]
|
||||||
|
for test in tests:
|
||||||
|
self.assertTrue(obj.is_covered(MountRule(*test)))
|
||||||
|
self.assertFalse(obj.is_equal(MountRule(*test)))
|
||||||
|
|
||||||
def test_is_notcovered(self):
|
def test_is_notcovered(self):
|
||||||
obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), '/foo/b*', '/b*')
|
obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), '/foo/b*', '/b*')
|
||||||
tests = [
|
tests = [
|
||||||
@@ -231,6 +243,12 @@ class MountIsCoveredTest(AATest):
|
|||||||
self.assertFalse(obj.is_covered(MountRule(*test)))
|
self.assertFalse(obj.is_covered(MountRule(*test)))
|
||||||
self.assertFalse(obj.is_equal(MountRule(*test)))
|
self.assertFalse(obj.is_equal(MountRule(*test)))
|
||||||
|
|
||||||
|
def test_is_not_covered_fs_options(self):
|
||||||
|
obj = MountRule('mount', MountRule.ALL, ('=', ('ro')), 'tmpfs', MountRule.ALL)
|
||||||
|
test = ('mount', MountRule.ALL, ('=', ('rw')), 'procfs', MountRule.ALL)
|
||||||
|
self.assertFalse(obj.is_covered(MountRule(*test)))
|
||||||
|
self.assertFalse(obj.is_equal(MountRule(*test)))
|
||||||
|
|
||||||
|
|
||||||
setup_all_loops(__name__)
|
setup_all_loops(__name__)
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
Reference in New Issue
Block a user