Skip to content

Commit

Permalink
util/apparmor: add apparmor support
Browse files Browse the repository at this point in the history
Add full AppArmor support using libapparmor. This requires af_unix
mediation support in the kernel (which has not yet landed upstream).

Signed-off-by: Sebastian Reichel <[email protected]>
  • Loading branch information
sre committed Mar 21, 2022
1 parent 8c43d7d commit 92e9e23
Show file tree
Hide file tree
Showing 18 changed files with 935 additions and 51 deletions.
9 changes: 9 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ if use_audit
dep_libcapng = dependency('libcap-ng', version: '>=0.6')
endif

#
# Config: apparmor
#

use_apparmor = get_option('apparmor')
if use_apparmor
dep_libapparmor = dependency('libapparmor', version: '>=3.0')
endif

#
# Config: docs
#
Expand Down
1 change: 1 addition & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
option('apparmor', type: 'boolean', value: false, description: 'AppArmor support')
option('audit', type: 'boolean', value: false, description: 'Audit support')
option('docs', type: 'boolean', value: false, description: 'Build documentation')
option('launcher', type: 'boolean', value: true, description: 'Build compatibility launcher')
Expand Down
8 changes: 8 additions & 0 deletions src/broker/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <sys/types.h>
#include "broker/broker.h"
#include "broker/main.h"
#include "util/apparmor.h"
#include "util/audit.h"
#include "util/error.h"
#include "util/selinux.h"
Expand Down Expand Up @@ -286,9 +287,16 @@ int main(int argc, char **argv) {
goto exit;
}

r = bus_apparmor_init_global();
if (r) {
r = error_fold(r);
goto exit;
}

r = run();

exit:
bus_apparmor_deinit_global();
bus_selinux_deinit_global();
util_audit_deinit_global();

Expand Down
17 changes: 15 additions & 2 deletions src/bus/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ void bus_log_append_policy_send(Bus *bus, int policy_type, uint64_t sender_id, u
case BUS_LOG_POLICY_TYPE_SELINUX:
log_appendf(bus->log, "DBUS_BROKER_POLICY_TYPE=selinux\n");
break;
case BUS_LOG_POLICY_TYPE_APPARMOR:
log_appendf(bus->log, "DBUS_BROKER_POLICY_TYPE=apparmor\n");
break;
default:
c_assert(0);
abort();
Expand All @@ -233,8 +236,18 @@ void bus_log_append_policy_send(Bus *bus, int policy_type, uint64_t sender_id, u
bus_log_append_transaction(bus, sender_id, receiver_id, sender_names, receiver_names, sender_label, receiver_label, message);
}

void bus_log_append_policy_receive(Bus *bus, uint64_t receiver_id, uint64_t sender_id, NameSet *sender_names, NameSet *receiver_names, Message *message) {
log_appendf(bus->log, "DBUS_BROKER_POLICY_TYPE=internal\n");
void bus_log_append_policy_receive(Bus *bus, int policy_type, uint64_t receiver_id, uint64_t sender_id, NameSet *sender_names, NameSet *receiver_names, Message *message) {
switch (policy_type) {
case BUS_LOG_POLICY_TYPE_INTERNAL:
log_appendf(bus->log, "DBUS_BROKER_POLICY_TYPE=internal\n");
break;
case BUS_LOG_POLICY_TYPE_APPARMOR:
log_appendf(bus->log, "DBUS_BROKER_POLICY_TYPE=apparmor\n");
break;
default:
c_assert(0);
abort();
}
log_appendf(bus->log, "DBUS_BROKER_TRANSMIT_ACTION=receive\n");
bus_log_append_transaction(bus, sender_id, receiver_id, sender_names, receiver_names, NULL, NULL, message);
}
3 changes: 2 additions & 1 deletion src/bus/bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ enum {
enum {
BUS_LOG_POLICY_TYPE_INTERNAL,
BUS_LOG_POLICY_TYPE_SELINUX,
BUS_LOG_POLICY_TYPE_APPARMOR,
};

typedef struct Bus Bus;
Expand Down Expand Up @@ -81,4 +82,4 @@ void bus_log_append_receiver(Bus *bus, uint64_t receiver_id, NameSet *receiver_n
void bus_log_append_sender(Bus *bus, uint64_t sender_id, NameSet *sender_names, const char *sender_label);
void bus_log_append_transaction(Bus *bus, uint64_t sender_id, uint64_t receiver_id, NameSet *sender_names, NameSet *receiver_names, const char *sender_label, const char *receiver_label, Message *message);
void bus_log_append_policy_send(Bus *bus, int policy_type, uint64_t sender_id, uint64_t receiver_id, NameSet *sender_names, NameSet *receiver_names, const char *sender_label, const char *receiver_label, Message *message);
void bus_log_append_policy_receive(Bus *bus, uint64_t sender_id, uint64_t receiver_id, NameSet *sender_names, NameSet *receievr_names, Message *message);
void bus_log_append_policy_receive(Bus *bus, int policy_type, uint64_t sender_id, uint64_t receiver_id, NameSet *sender_names, NameSet *receievr_names, Message *message);
51 changes: 43 additions & 8 deletions src/bus/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "dbus/protocol.h"
#include "dbus/socket.h"
#include "util/error.h"
#include "util/apparmor.h"
#include "util/selinux.h"
#include "util/string.h"

Expand Down Expand Up @@ -651,6 +652,9 @@ static int driver_notify_name_owner_changed(Bus *bus, MatchRegistry *matches, co

r = policy_snapshot_check_receive(receiver->policy,
NULL,
receiver->seclabel,
NULL,
0,
metadata.fields.interface,
metadata.fields.member,
metadata.fields.path,
Expand Down Expand Up @@ -1824,6 +1828,12 @@ static int driver_method_become_monitor(Peer *peer, const char *path, CDVar *in_
if (!peer_is_privileged(peer))
return DRIVER_E_PEER_NOT_PRIVILEGED;

r = bus_apparmor_check_eavesdrop(peer->policy->apparmor, peer->policy->seclabel);
if (r == APPARMOR_E_DENIED)
return DRIVER_E_PEER_NOT_PRIVILEGED;
if (r)
return r;

/* first create all the match objects before modifying the peer */
match_owner_init(&owned_matches);

Expand Down Expand Up @@ -2331,6 +2341,17 @@ static int driver_dispatch_method(Peer *peer, const DriverMethod *methods, uint3
return DRIVER_E_UNEXPECTED_METHOD;
}

static int driver_map_denied_error(int err) {
switch (err) {
case POLICY_E_APPARMOR_ACCESS_DENIED:
return BUS_LOG_POLICY_TYPE_APPARMOR;
case POLICY_E_SELINUX_ACCESS_DENIED:
return BUS_LOG_POLICY_TYPE_SELINUX;
default:
return BUS_LOG_POLICY_TYPE_INTERNAL;
}
}

static int driver_dispatch_interface(Peer *peer, uint32_t serial, const char *interface, const char *member, const char *path, const char *signature, Message *message) {
static const DriverInterface interfaces[] = {
{ "org.freedesktop.DBus", driver_methods },
Expand All @@ -2346,24 +2367,29 @@ static int driver_dispatch_interface(Peer *peer, uint32_t serial, const char *in
/* ignore */
return 0;

r = policy_snapshot_check_send(peer->policy, NULL, NULL, interface, member, path, message->header->type, false, message->metadata.fields.unix_fds);
r = policy_snapshot_check_send(peer->policy, peer->policy->seclabel, NULL, NULL, 0, interface, member, path, message->header->type, false, message->metadata.fields.unix_fds);
if (r) {
if (r == POLICY_E_ACCESS_DENIED || r == POLICY_E_SELINUX_ACCESS_DENIED) {
switch (r) {
case POLICY_E_ACCESS_DENIED:
case POLICY_E_APPARMOR_ACCESS_DENIED:
case POLICY_E_SELINUX_ACCESS_DENIED:
{
NameSet names = NAME_SET_INIT_FROM_OWNER(&peer->owned_names);

log_append_here(peer->bus->log, LOG_WARNING, 0, NULL);
bus_log_append_policy_send(peer->bus,
(r == POLICY_E_ACCESS_DENIED ? BUS_LOG_POLICY_TYPE_INTERNAL : BUS_LOG_POLICY_TYPE_SELINUX),
driver_map_denied_error(r),
peer->id, ADDRESS_ID_INVALID, &names, NULL, peer->policy->seclabel, peer->bus->seclabel, message);
r = log_commitf(peer->bus->log, "A security policy denied :1.%llu to send method call %s:%s.%s to org.freedesktop.DBus.",
peer->id, path, interface, member);
if (r)
return error_fold(r);

return DRIVER_E_SEND_DENIED;
}
default:
return error_fold(r);
}

return error_fold(r);
}

if (interface) {
Expand Down Expand Up @@ -2504,23 +2530,32 @@ static int driver_forward_broadcast(Peer *sender, Message *message) {
c_list_unlink(&match_owner->destinations_link);

r = policy_snapshot_check_send(sender->policy,
sender->seclabel,
receiver->seclabel,
&receiver_names,
receiver->id,
message->metadata.fields.interface,
message->metadata.fields.member,
message->metadata.fields.path,
message->metadata.header.type,
true,
message->metadata.fields.unix_fds);
if (r) {
if (r == POLICY_E_ACCESS_DENIED || r == POLICY_E_SELINUX_ACCESS_DENIED)
switch (r) {
case POLICY_E_ACCESS_DENIED:
case POLICY_E_APPARMOR_ACCESS_DENIED:
case POLICY_E_SELINUX_ACCESS_DENIED:
continue;

return error_fold(r);
default:
return error_fold(r);
}
}

r = policy_snapshot_check_receive(receiver->policy,
sender->seclabel,
receiver->seclabel,
&sender_names,
sender->id,
message->metadata.fields.interface,
message->metadata.fields.member,
message->metadata.fields.path,
Expand Down
49 changes: 38 additions & 11 deletions src/bus/peer.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,10 +410,14 @@ int peer_request_name(Peer *peer, const char *name, uint32_t flags, NameChange *

r = policy_snapshot_check_own(peer->policy, name);
if (r) {
if (r == POLICY_E_ACCESS_DENIED || r == POLICY_E_SELINUX_ACCESS_DENIED)
switch (r) {
case POLICY_E_ACCESS_DENIED:
case POLICY_E_APPARMOR_ACCESS_DENIED:
case POLICY_E_SELINUX_ACCESS_DENIED:
return PEER_E_NAME_REFUSED;

return error_fold(r);
default:
return error_fold(r);
}
}

r = name_registry_request_name(&peer->bus->names,
Expand Down Expand Up @@ -720,6 +724,17 @@ void peer_flush_matches(Peer *peer) {
}
}

static int peer_map_denied_error(int err) {
switch (err) {
case POLICY_E_APPARMOR_ACCESS_DENIED:
return BUS_LOG_POLICY_TYPE_APPARMOR;
case POLICY_E_SELINUX_ACCESS_DENIED:
return BUS_LOG_POLICY_TYPE_SELINUX;
default:
return BUS_LOG_POLICY_TYPE_INTERNAL;
}
}

int peer_queue_unicast(PolicySnapshot *sender_policy, NameSet *sender_names, ReplyOwner *sender_replies, User *sender_user, uint64_t sender_id, Peer *receiver, Message *message) {
_c_cleanup_(reply_slot_freep) ReplySlot *slot = NULL;
NameSet receiver_names = NAME_SET_INIT_FROM_OWNER(&receiver->owned_names);
Expand All @@ -740,17 +755,24 @@ int peer_queue_unicast(PolicySnapshot *sender_policy, NameSet *sender_names, Rep
}

r = policy_snapshot_check_receive(receiver->policy,
sender_policy->seclabel,
receiver->seclabel,
sender_names,
sender_id,
message->metadata.fields.interface,
message->metadata.fields.member,
message->metadata.fields.path,
message->header->type,
false,
message->metadata.fields.unix_fds);
if (r) {
if (r == POLICY_E_ACCESS_DENIED) {
switch (r) {
case POLICY_E_ACCESS_DENIED:
case POLICY_E_APPARMOR_ACCESS_DENIED:
log_append_here(receiver->bus->log, LOG_WARNING, 0, NULL);
bus_log_append_policy_receive(receiver->bus, receiver->id, sender_id, sender_names, &receiver_names, message);
bus_log_append_policy_receive(receiver->bus,
peer_map_denied_error(r),
receiver->id, sender_id, sender_names, &receiver_names, message);
r = log_commitf(receiver->bus->log, "A security policy denied %s to receive %s %s:%s.%s from :1.%llu.",
message->metadata.fields.destination,
message->header->type == DBUS_MESSAGE_TYPE_METHOD_CALL ? "method call" : "signal",
Expand All @@ -760,25 +782,30 @@ int peer_queue_unicast(PolicySnapshot *sender_policy, NameSet *sender_names, Rep
return error_fold(r);

return PEER_E_RECEIVE_DENIED;
default:
return error_fold(r);
}

return error_fold(r);
}

r = policy_snapshot_check_send(sender_policy,
sender_policy->seclabel,
receiver->seclabel,
&receiver_names,
receiver->id,
message->metadata.fields.interface,
message->metadata.fields.member,
message->metadata.fields.path,
message->header->type,
false,
message->metadata.fields.unix_fds);
if (r) {
if (r == POLICY_E_ACCESS_DENIED || r == POLICY_E_SELINUX_ACCESS_DENIED) {
switch (r) {
case POLICY_E_ACCESS_DENIED:
case POLICY_E_APPARMOR_ACCESS_DENIED:
case POLICY_E_SELINUX_ACCESS_DENIED:
log_append_here(receiver->bus->log, LOG_WARNING, 0, NULL);
bus_log_append_policy_send(receiver->bus,
(r == POLICY_E_ACCESS_DENIED ? BUS_LOG_POLICY_TYPE_INTERNAL : BUS_LOG_POLICY_TYPE_SELINUX),
peer_map_denied_error(r),
sender_id, receiver->id, sender_names, &receiver_names,
sender_policy->seclabel, receiver->policy->seclabel, message);
r = log_commitf(receiver->bus->log, "A security policy denied :1.%llu to send %s %s:%s.%s to %s.",
Expand All @@ -790,9 +817,9 @@ int peer_queue_unicast(PolicySnapshot *sender_policy, NameSet *sender_names, Rep
return error_fold(r);

return PEER_E_SEND_DENIED;
default:
return error_fold(r);
}

return error_fold(r);
}

r = connection_queue(&receiver->connection, sender_user, message);
Expand Down
Loading

0 comments on commit 92e9e23

Please sign in to comment.