summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2004-11-09 06:11:33 +0000
committerColin Walters <walters@verbum.org>2004-11-09 06:11:33 +0000
commit935a41a04c3f638134fa905503fc41ddbd18902f (patch)
tree0f6dee53c28bba5a8ce6658b634c66ba1cc5abda
parent2f5e949851f7704b296f55ce1d1fcc4480176107 (diff)
2004-11-09 Colin Walters <walters@verbum.org>
* dbus/dbus-string.c (_dbus_string_get_length): New function, writes DBusString to C buffer. * dbus/dbus-string.h: Prototype it. * dbus/dbus-message.c (dbus_message_type_to_string): New function, converts message type into C string. * dbus/dbus-message.h: Prototype it. * bus/selinux.c (bus_selinux_check): Take source pid, target pid, and audit data. Pass audit data to avc_has_perm. (log_audit_callback): New function, appends extra audit information. (bus_selinux_allows_acquire_service): Also take service name, add it to audit data. (bus_selinux_allows_send): Also take message type, interface, method member, error name, and destination, and add them to audit data. (log_cb): Initialize func_audit. * bus/selinux.h (bus_selinux_allows_acquire_service) (bus_selinux_allows_send): Update prototypes * bus/services.c (bus_registry_acquire_service): Pass service name to bus_selinux_allows_acquire_service. * bus/bus.c (bus_context_check_security_policy): Pass additional audit data. Move assignment of dest to its own line.
-rw-r--r--ChangeLog34
-rw-r--r--bus/bus.c24
-rw-r--r--bus/selinux.c98
-rw-r--r--bus/selinux.h12
-rw-r--r--bus/services.c3
-rw-r--r--dbus/dbus-message.c31
-rw-r--r--dbus/dbus-message.h1
-rw-r--r--dbus/dbus-string.c24
-rw-r--r--dbus/dbus-string.h3
9 files changed, 211 insertions, 19 deletions
diff --git a/ChangeLog b/ChangeLog
index 612db5d8..118fa6f2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,37 @@
+2004-11-09 Colin Walters <walters@verbum.org>
+
+ * dbus/dbus-string.c (_dbus_string_get_length): New
+ function, writes DBusString to C buffer.
+
+ * dbus/dbus-string.h: Prototype it.
+
+ * dbus/dbus-message.c (dbus_message_type_to_string): New
+ function, converts message type into C string.
+
+ * dbus/dbus-message.h: Prototype it.
+
+ * bus/selinux.c (bus_selinux_check): Take source pid,
+ target pid, and audit data. Pass audit data to
+ avc_has_perm.
+ (log_audit_callback): New function, appends extra
+ audit information.
+ (bus_selinux_allows_acquire_service): Also take
+ service name, add it to audit data.
+ (bus_selinux_allows_send): Also take message
+ type, interface, method member, error name,
+ and destination, and add them to audit data.
+ (log_cb): Initialize func_audit.
+
+ * bus/selinux.h (bus_selinux_allows_acquire_service)
+ (bus_selinux_allows_send): Update prototypes
+
+ * bus/services.c (bus_registry_acquire_service): Pass
+ service name to bus_selinux_allows_acquire_service.
+
+ * bus/bus.c (bus_context_check_security_policy): Pass
+ additional audit data. Move assignment of dest
+ to its own line.
+
2004-11-07 Colin Walters <walters@verbum.org>
* dbus/dbus-transport-unix.c (do_authentication): Always
diff --git a/bus/bus.c b/bus/bus.c
index 65e396c3..a80636b1 100644
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -1127,12 +1127,20 @@ bus_context_check_security_policy (BusContext *context,
if (sender != NULL)
{
+ const char *dest;
+
+ dest = dbus_message_get_destination (message);
+
/* First verify the SELinux access controls. If allowed then
* go on with the standard checks.
*/
- if (!bus_selinux_allows_send (sender, proposed_recipient))
+ if (!bus_selinux_allows_send (sender, proposed_recipient,
+ dbus_message_type_to_string (dbus_message_get_type (message)),
+ dbus_message_get_interface (message),
+ dbus_message_get_member (message),
+ dbus_message_get_error_name (message),
+ dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
{
- const char *dest = dbus_message_get_destination (message);
dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
"An SELinux policy prevents this sender "
"from sending this message to this recipient "
@@ -1255,7 +1263,9 @@ bus_context_check_security_policy (BusContext *context,
proposed_recipient,
message))
{
- const char *dest = dbus_message_get_destination (message);
+ const char *dest;
+
+ dest = dbus_message_get_destination (message);
dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
"A security policy in place prevents this sender "
"from sending this message to this recipient, "
@@ -1280,7 +1290,9 @@ bus_context_check_security_policy (BusContext *context,
addressed_recipient, proposed_recipient,
message))
{
- const char *dest = dbus_message_get_destination (message);
+ const char *dest;
+
+ dest = dbus_message_get_destination (message);
dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
"A security policy in place prevents this recipient "
"from receiving this message from this sender, "
@@ -1304,7 +1316,9 @@ bus_context_check_security_policy (BusContext *context,
dbus_connection_get_outgoing_size (proposed_recipient) >
context->limits.max_outgoing_bytes)
{
- const char *dest = dbus_message_get_destination (message);
+ const char *dest;
+
+ dest = dbus_message_get_destination (message);
dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
"The destination service \"%s\" has a full message queue",
dest ? dest : (proposed_recipient ?
diff --git a/bus/selinux.c b/bus/selinux.c
index 0a3dec70..9527489f 100644
--- a/bus/selinux.c
+++ b/bus/selinux.c
@@ -57,6 +57,7 @@ static pthread_t avc_notify_thread;
/* Prototypes for AVC callback functions. */
static void log_callback (const char *fmt, ...);
+static void log_audit_callback (void *data, security_class_t class, char *buf, size_t bufleft);
static void *avc_create_thread (void (*run) (void));
static void avc_stop_thread (void *thread);
static void *avc_alloc_lock (void);
@@ -73,7 +74,7 @@ static const struct avc_memory_callback mem_cb =
static const struct avc_log_callback log_cb =
{
.func_log = log_callback,
- .func_audit = NULL
+ .func_audit = log_audit_callback
};
static const struct avc_thread_callback thread_cb =
{
@@ -123,6 +124,18 @@ policy_reload_callback (u_int32_t event, security_id_t ssid,
}
/**
+ * Log any auxiliary data
+ */
+static void
+log_audit_callback (void *data, security_class_t class, char *buf, size_t bufleft)
+{
+ DBusString *audmsg = data;
+ _dbus_string_copy_to_buffer (audmsg, buf, bufleft);
+ _dbus_string_free (audmsg);
+ dbus_free (audmsg);
+}
+
+/**
* Create thread to notify the AVC of enforcing and policy reload
* changes via netlink.
*
@@ -349,17 +362,28 @@ static dbus_bool_t
bus_selinux_check (BusSELinuxID *sender_sid,
BusSELinuxID *override_sid,
security_class_t target_class,
- access_vector_t requested)
+ access_vector_t requested,
+ unsigned long spid,
+ unsigned long tpid,
+ DBusString *auxdata)
{
if (!selinux_enabled)
return TRUE;
+ if (auxdata)
+ {
+ if (spid && _dbus_string_append (auxdata, " spid="))
+ _dbus_string_append_uint (auxdata, spid);
+ if (tpid && _dbus_string_append (auxdata, " tpid="))
+ _dbus_string_append_uint (auxdata, tpid);
+ }
+
/* Make the security check. AVC checks enforcing mode here as well. */
if (avc_has_perm (SELINUX_SID_FROM_BUS (sender_sid),
override_sid ?
SELINUX_SID_FROM_BUS (override_sid) :
SELINUX_SID_FROM_BUS (bus_sid),
- target_class, requested, &aeref, NULL) < 0)
+ target_class, requested, &aeref, auxdata) < 0)
{
_dbus_verbose ("SELinux denying due to security policy.\n");
return FALSE;
@@ -379,20 +403,40 @@ bus_selinux_check (BusSELinuxID *sender_sid,
*/
dbus_bool_t
bus_selinux_allows_acquire_service (DBusConnection *connection,
- BusSELinuxID *service_sid)
+ BusSELinuxID *service_sid,
+ const char *service_name)
{
#ifdef HAVE_SELINUX
BusSELinuxID *connection_sid;
+ unsigned long spid;
+ DBusString *auxdata;
if (!selinux_enabled)
return TRUE;
connection_sid = bus_connection_get_selinux_id (connection);
+ if (!dbus_connection_get_unix_process_id (connection, &spid))
+ spid = 0;
+
+ auxdata = dbus_new0 (DBusString, 1);
+ if (auxdata)
+ {
+ if (!_dbus_string_init (auxdata))
+ {
+ dbus_free (auxdata);
+ auxdata = NULL;
+ }
+ else if (_dbus_string_append (auxdata, "service="))
+ _dbus_string_append (auxdata, service_name);
+ }
return bus_selinux_check (connection_sid,
- service_sid,
- SECCLASS_DBUS,
- DBUS__ACQUIRE_SVC);
+ service_sid,
+ SECCLASS_DBUS,
+ DBUS__ACQUIRE_SVC,
+ spid,
+ 0,
+ auxdata);
#else
return TRUE;
#endif /* HAVE_SELINUX */
@@ -410,15 +454,50 @@ bus_selinux_allows_acquire_service (DBusConnection *connection,
*/
dbus_bool_t
bus_selinux_allows_send (DBusConnection *sender,
- DBusConnection *proposed_recipient)
+ DBusConnection *proposed_recipient,
+ const char *msgtype,
+ const char *interface,
+ const char *member,
+ const char *error_name,
+ const char *destination)
{
#ifdef HAVE_SELINUX
BusSELinuxID *recipient_sid;
BusSELinuxID *sender_sid;
+ unsigned long spid, tpid;
+ DBusString *auxdata;
if (!selinux_enabled)
return TRUE;
+ if (!dbus_connection_get_unix_process_id (sender, &spid))
+ spid = 0;
+ if (!dbus_connection_get_unix_process_id (proposed_recipient, &tpid))
+ tpid = 0;
+
+ auxdata = dbus_new0 (DBusString, 1);
+ if (auxdata)
+ {
+ if (!_dbus_string_init (auxdata))
+ {
+ dbus_free (auxdata);
+ auxdata = NULL;
+ }
+ else
+ {
+ if (_dbus_string_append (auxdata, "msgtype="))
+ _dbus_string_append (auxdata, msgtype);
+ if (interface && _dbus_string_append (auxdata, " interface="))
+ _dbus_string_append (auxdata, interface);
+ if (member && _dbus_string_append (auxdata, " member="))
+ _dbus_string_append (auxdata, member);
+ if (error_name && _dbus_string_append (auxdata, " error_name="))
+ _dbus_string_append (auxdata, error_name);
+ if (destination && _dbus_string_append (auxdata, " dest="))
+ _dbus_string_append (auxdata, destination);
+ }
+ }
+
sender_sid = bus_connection_get_selinux_id (sender);
/* A NULL proposed_recipient means the bus itself. */
if (proposed_recipient)
@@ -427,7 +506,8 @@ bus_selinux_allows_send (DBusConnection *sender,
recipient_sid = BUS_SID_FROM_SELINUX (bus_sid);
return bus_selinux_check (sender_sid, recipient_sid,
- SECCLASS_DBUS, DBUS__SEND_MSG);
+ SECCLASS_DBUS, DBUS__SEND_MSG,
+ spid, tpid, auxdata);
#else
return TRUE;
#endif /* HAVE_SELINUX */
diff --git a/bus/selinux.h b/bus/selinux.h
index 71271fab..3627126c 100644
--- a/bus/selinux.h
+++ b/bus/selinux.h
@@ -47,11 +47,15 @@ const char* bus_selinux_get_policy_root (void);
dbus_bool_t bus_selinux_allows_acquire_service (DBusConnection *connection,
- BusSELinuxID *service_sid);
+ BusSELinuxID *service_sid,
+ const char *service_name);
dbus_bool_t bus_selinux_allows_send (DBusConnection *sender,
- DBusConnection *proposed_recipient);
-
-
+ DBusConnection *proposed_recipient,
+ const char *msgtype, /* Supplementary audit data */
+ const char *interface,
+ const char *member,
+ const char *error_name,
+ const char *destination);
BusSELinuxID* bus_selinux_init_connection_id (DBusConnection *connection,
DBusError *error);
diff --git a/bus/services.c b/bus/services.c
index 31041c37..1036947a 100644
--- a/bus/services.c
+++ b/bus/services.c
@@ -310,7 +310,8 @@ bus_registry_acquire_service (BusRegistry *registry,
sid = bus_selinux_id_table_lookup (registry->service_sid_table,
service_name);
- if (!bus_selinux_allows_acquire_service (connection, sid))
+ if (!bus_selinux_allows_acquire_service (connection, sid,
+ _dbus_string_get_const_data (service_name)))
{
dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
"Connection \"%s\" is not allowed to own the service \"%s\" due "
diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
index b191337e..df0ade26 100644
--- a/dbus/dbus-message.c
+++ b/dbus/dbus-message.c
@@ -5778,6 +5778,37 @@ dbus_message_type_from_string (const char *type_str)
return DBUS_MESSAGE_TYPE_INVALID;
}
+/**
+ * Utility function to convert a D-BUS message type into a
+ * machine-readable string (not translated).
+ *
+ * @code
+ * DBUS_MESSAGE_TYPE_METHOD_CALL -> "method_call"
+ * DBUS_MESSAGE_TYPE_METHOD_RETURN -> "method_return"
+ * DBUS_MESSAGE_TYPE_SIGNAL -> "signal"
+ * DBUS_MESSAGE_TYPE_ERROR -> "error"
+ * DBUS_MESSAGE_TYPE_INVALID -> "invalid"
+ * @endcode
+ *
+ */
+const char *
+dbus_message_type_to_string (int type)
+{
+ switch (type)
+ {
+ case DBUS_MESSAGE_TYPE_METHOD_CALL:
+ return "method_call";
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ return "method_return";
+ case DBUS_MESSAGE_TYPE_SIGNAL:
+ return "signal";
+ case DBUS_MESSAGE_TYPE_ERROR:
+ return "error";
+ default:
+ return "invalid";
+ }
+}
+
/** @} */
#ifdef DBUS_BUILD_TESTS
#include "dbus-test.h"
diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h
index 50ec22c1..e1894c72 100644
--- a/dbus/dbus-message.h
+++ b/dbus/dbus-message.h
@@ -295,6 +295,7 @@ void* dbus_message_get_data (DBusMessage *message,
dbus_int32_t slot);
int dbus_message_type_from_string (const char *type_str);
+const char * dbus_message_type_to_string (int type);
DBUS_END_DECLS
diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c
index 2061e8be..7381dab2 100644
--- a/dbus/dbus-string.c
+++ b/dbus/dbus-string.c
@@ -757,6 +757,30 @@ _dbus_string_copy_data_len (const DBusString *str,
}
/**
+ * Copies the contents of a DBusString into a different
+ * buffer. The resulting buffer will be nul-terminated.
+ *
+ * @param str a string
+ * @param buffer a C buffer to copy data to
+ * @param len maximum length of C buffer
+ */
+void
+_dbus_string_copy_to_buffer (const DBusString *str,
+ char *buffer,
+ int avail_len)
+{
+ int copy_len;
+ DBUS_CONST_STRING_PREAMBLE (str);
+
+ _dbus_assert (avail_len >= 0);
+
+ copy_len = MIN (avail_len, real->len+1);
+ memcpy (buffer, real->str, copy_len);
+ if (avail_len > 0 && avail_len == copy_len)
+ buffer[avail_len-1] = '\0';
+}
+
+/**
* Gets the length of a string (not including nul termination).
*
* @returns the length.
diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h
index 2dda2b0f..1a0236d4 100644
--- a/dbus/dbus-string.h
+++ b/dbus/dbus-string.h
@@ -88,6 +88,9 @@ dbus_bool_t _dbus_string_copy_data_len (const DBusString *str,
char **data_return,
int start,
int len);
+void _dbus_string_copy_to_buffer (const DBusString *str,
+ char *buffer,
+ int len);
int _dbus_string_get_length (const DBusString *str);
dbus_bool_t _dbus_string_lengthen (DBusString *str,
int additional_length);