mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-05-08 09:08:15 +02:00
Add LSM-agnostic support for LinuxSecurityLabel credential
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=89041 Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk> Acked-by: Stephen Smalley <sds@tycho.nsa.gov> (for SELinux) Acked-by: John Johansen <john.johansen@canonical.com> (for AppArmor) Acked-by: Casey Schaufler <casey@schaufler-ca.com> (for Smack) Tested-by: Tyler Hicks <tyhicks@canonical.com>
This commit is contained in:
parent
c966d90374
commit
96c3bcec77
9 changed files with 268 additions and 11 deletions
32
bus/driver.c
32
bus/driver.c
|
|
@ -34,6 +34,7 @@
|
|||
#include "utils.h"
|
||||
|
||||
#include <dbus/dbus-asv-util.h>
|
||||
#include <dbus/dbus-connection-internal.h>
|
||||
#include <dbus/dbus-string.h>
|
||||
#include <dbus/dbus-internals.h>
|
||||
#include <dbus/dbus-message.h>
|
||||
|
|
@ -1647,7 +1648,7 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
|
|||
DBusMessageIter reply_iter;
|
||||
DBusMessageIter array_iter;
|
||||
unsigned long ulong_val;
|
||||
char *windows_sid;
|
||||
char *s;
|
||||
const char *service;
|
||||
|
||||
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
|
||||
|
|
@ -1682,26 +1683,43 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
|
|||
goto oom;
|
||||
}
|
||||
|
||||
if (dbus_connection_get_windows_user (conn, &windows_sid))
|
||||
if (dbus_connection_get_windows_user (conn, &s))
|
||||
{
|
||||
DBusString str;
|
||||
dbus_bool_t result;
|
||||
|
||||
if (windows_sid == NULL)
|
||||
if (s == NULL)
|
||||
goto oom;
|
||||
|
||||
_dbus_string_init_const (&str, windows_sid);
|
||||
_dbus_string_init_const (&str, s);
|
||||
result = _dbus_validate_utf8 (&str, 0, _dbus_string_get_length (&str));
|
||||
_dbus_string_free (&str);
|
||||
if (result)
|
||||
{
|
||||
if (!_dbus_asv_add_string (&array_iter, "WindowsSID", windows_sid))
|
||||
if (!_dbus_asv_add_string (&array_iter, "WindowsSID", s))
|
||||
{
|
||||
dbus_free(windows_sid);
|
||||
dbus_free (s);
|
||||
goto oom;
|
||||
}
|
||||
}
|
||||
dbus_free(windows_sid);
|
||||
dbus_free (s);
|
||||
}
|
||||
|
||||
if (_dbus_connection_get_linux_security_label (conn, &s))
|
||||
{
|
||||
if (s == NULL)
|
||||
goto oom;
|
||||
|
||||
/* use the GVariant bytestring convention for strings of unknown
|
||||
* encoding: include the \0 in the payload, for zero-copy reading */
|
||||
if (!_dbus_asv_add_byte_array (&array_iter, "LinuxSecurityLabel",
|
||||
s, strlen (s) + 1))
|
||||
{
|
||||
dbus_free (s);
|
||||
goto oom;
|
||||
}
|
||||
|
||||
dbus_free (s);
|
||||
}
|
||||
|
||||
if (!_dbus_asv_close (&reply_iter, &array_iter))
|
||||
|
|
|
|||
|
|
@ -1102,20 +1102,23 @@ handle_server_data_external_mech (DBusAuth *auth,
|
|||
auth->desired_identity))
|
||||
return FALSE;
|
||||
|
||||
/* also copy process ID from the socket credentials
|
||||
/* also copy misc process info from the socket credentials
|
||||
*/
|
||||
if (!_dbus_credentials_add_credential (auth->authorized_identity,
|
||||
DBUS_CREDENTIAL_UNIX_PROCESS_ID,
|
||||
auth->credentials))
|
||||
return FALSE;
|
||||
|
||||
/* also copy audit data from the socket credentials
|
||||
*/
|
||||
if (!_dbus_credentials_add_credential (auth->authorized_identity,
|
||||
DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
|
||||
auth->credentials))
|
||||
return FALSE;
|
||||
|
||||
|
||||
if (!_dbus_credentials_add_credential (auth->authorized_identity,
|
||||
DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
|
||||
auth->credentials))
|
||||
return FALSE;
|
||||
|
||||
if (!send_ok (auth))
|
||||
return FALSE;
|
||||
|
||||
|
|
|
|||
|
|
@ -107,6 +107,9 @@ void _dbus_connection_set_pending_fds_function (DBusConnectio
|
|||
DBusPendingFdsChangeFunction callback,
|
||||
void *data);
|
||||
|
||||
dbus_bool_t _dbus_connection_get_linux_security_label (DBusConnection *connection,
|
||||
char **label_p);
|
||||
|
||||
/* if DBUS_ENABLE_STATS */
|
||||
void _dbus_connection_get_stats (DBusConnection *connection,
|
||||
dbus_uint32_t *in_messages,
|
||||
|
|
|
|||
|
|
@ -5322,6 +5322,32 @@ dbus_connection_set_unix_user_function (DBusConnection *connection,
|
|||
(* old_free_function) (old_data);
|
||||
}
|
||||
|
||||
/* Same calling convention as dbus_connection_get_windows_user */
|
||||
dbus_bool_t
|
||||
_dbus_connection_get_linux_security_label (DBusConnection *connection,
|
||||
char **label_p)
|
||||
{
|
||||
dbus_bool_t result;
|
||||
|
||||
_dbus_assert (connection != NULL);
|
||||
_dbus_assert (label_p != NULL);
|
||||
|
||||
CONNECTION_LOCK (connection);
|
||||
|
||||
if (!_dbus_transport_try_to_authenticate (connection->transport))
|
||||
result = FALSE;
|
||||
else
|
||||
result = _dbus_transport_get_linux_security_label (connection->transport,
|
||||
label_p);
|
||||
#ifndef __linux__
|
||||
_dbus_assert (!result);
|
||||
#endif
|
||||
|
||||
CONNECTION_UNLOCK (connection);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Windows user SID of the connection if known. Returns
|
||||
* #TRUE if the ID is filled in. Always returns #FALSE on non-Windows
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ struct DBusCredentials {
|
|||
dbus_uid_t unix_uid;
|
||||
dbus_pid_t pid;
|
||||
char *windows_sid;
|
||||
char *linux_security_label;
|
||||
void *adt_audit_data;
|
||||
dbus_int32_t adt_audit_data_size;
|
||||
};
|
||||
|
|
@ -79,6 +80,7 @@ _dbus_credentials_new (void)
|
|||
creds->unix_uid = DBUS_UID_UNSET;
|
||||
creds->pid = DBUS_PID_UNSET;
|
||||
creds->windows_sid = NULL;
|
||||
creds->linux_security_label = NULL;
|
||||
creds->adt_audit_data = NULL;
|
||||
creds->adt_audit_data_size = 0;
|
||||
|
||||
|
|
@ -133,6 +135,7 @@ _dbus_credentials_unref (DBusCredentials *credentials)
|
|||
if (credentials->refcount == 0)
|
||||
{
|
||||
dbus_free (credentials->windows_sid);
|
||||
dbus_free (credentials->linux_security_label);
|
||||
dbus_free (credentials->adt_audit_data);
|
||||
dbus_free (credentials);
|
||||
}
|
||||
|
|
@ -192,6 +195,30 @@ _dbus_credentials_add_windows_sid (DBusCredentials *credentials,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Linux security label, as used by LSMs such as SELinux, Smack and
|
||||
* AppArmor, to the credentials.
|
||||
*
|
||||
* @param credentials the object
|
||||
* @param label the label
|
||||
* @returns #FALSE if no memory
|
||||
*/
|
||||
dbus_bool_t
|
||||
_dbus_credentials_add_linux_security_label (DBusCredentials *credentials,
|
||||
const char *label)
|
||||
{
|
||||
char *copy;
|
||||
|
||||
copy = _dbus_strdup (label);
|
||||
if (copy == NULL)
|
||||
return FALSE;
|
||||
|
||||
dbus_free (credentials->linux_security_label);
|
||||
credentials->linux_security_label = copy;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ADT audit data to the credentials.
|
||||
*
|
||||
|
|
@ -236,6 +263,8 @@ _dbus_credentials_include (DBusCredentials *credentials,
|
|||
return credentials->unix_uid != DBUS_UID_UNSET;
|
||||
case DBUS_CREDENTIAL_WINDOWS_SID:
|
||||
return credentials->windows_sid != NULL;
|
||||
case DBUS_CREDENTIAL_LINUX_SECURITY_LABEL:
|
||||
return credentials->linux_security_label != NULL;
|
||||
case DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID:
|
||||
return credentials->adt_audit_data != NULL;
|
||||
}
|
||||
|
|
@ -283,6 +312,19 @@ _dbus_credentials_get_windows_sid (DBusCredentials *credentials)
|
|||
return credentials->windows_sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Linux security label (as used by LSMs) from the credentials,
|
||||
* or #NULL if the credentials object doesn't contain a security label.
|
||||
*
|
||||
* @param credentials the object
|
||||
* @returns the security label
|
||||
*/
|
||||
const char *
|
||||
_dbus_credentials_get_linux_security_label (DBusCredentials *credentials)
|
||||
{
|
||||
return credentials->linux_security_label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ADT audit data in the credentials, or #NULL if
|
||||
* the credentials object doesn't contain ADT audit data.
|
||||
|
|
@ -329,6 +371,10 @@ _dbus_credentials_are_superset (DBusCredentials *credentials,
|
|||
(possible_subset->windows_sid == NULL ||
|
||||
(credentials->windows_sid && strcmp (possible_subset->windows_sid,
|
||||
credentials->windows_sid) == 0)) &&
|
||||
(possible_subset->linux_security_label == NULL ||
|
||||
(credentials->linux_security_label != NULL &&
|
||||
strcmp (possible_subset->linux_security_label,
|
||||
credentials->linux_security_label) == 0)) &&
|
||||
(possible_subset->adt_audit_data == NULL ||
|
||||
(credentials->adt_audit_data && memcmp (possible_subset->adt_audit_data,
|
||||
credentials->adt_audit_data,
|
||||
|
|
@ -348,6 +394,7 @@ _dbus_credentials_are_empty (DBusCredentials *credentials)
|
|||
credentials->pid == DBUS_PID_UNSET &&
|
||||
credentials->unix_uid == DBUS_UID_UNSET &&
|
||||
credentials->windows_sid == NULL &&
|
||||
credentials->linux_security_label == NULL &&
|
||||
credentials->adt_audit_data == NULL;
|
||||
}
|
||||
|
||||
|
|
@ -387,6 +434,9 @@ _dbus_credentials_add_credentials (DBusCredentials *credentials,
|
|||
_dbus_credentials_add_credential (credentials,
|
||||
DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
|
||||
other_credentials) &&
|
||||
_dbus_credentials_add_credential (credentials,
|
||||
DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
|
||||
other_credentials) &&
|
||||
_dbus_credentials_add_credential (credentials,
|
||||
DBUS_CREDENTIAL_WINDOWS_SID,
|
||||
other_credentials);
|
||||
|
|
@ -427,6 +477,13 @@ _dbus_credentials_add_credential (DBusCredentials *credentials,
|
|||
if (!_dbus_credentials_add_windows_sid (credentials, other_credentials->windows_sid))
|
||||
return FALSE;
|
||||
}
|
||||
else if (which == DBUS_CREDENTIAL_LINUX_SECURITY_LABEL &&
|
||||
other_credentials->linux_security_label != NULL)
|
||||
{
|
||||
if (!_dbus_credentials_add_linux_security_label (credentials,
|
||||
other_credentials->linux_security_label))
|
||||
return FALSE;
|
||||
}
|
||||
else if (which == DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID &&
|
||||
other_credentials->adt_audit_data != NULL)
|
||||
{
|
||||
|
|
@ -449,6 +506,8 @@ _dbus_credentials_clear (DBusCredentials *credentials)
|
|||
credentials->unix_uid = DBUS_UID_UNSET;
|
||||
dbus_free (credentials->windows_sid);
|
||||
credentials->windows_sid = NULL;
|
||||
dbus_free (credentials->linux_security_label);
|
||||
credentials->linux_security_label = NULL;
|
||||
dbus_free (credentials->adt_audit_data);
|
||||
credentials->adt_audit_data = NULL;
|
||||
credentials->adt_audit_data_size = 0;
|
||||
|
|
@ -540,6 +599,15 @@ _dbus_credentials_to_string_append (DBusCredentials *credentials,
|
|||
else
|
||||
join = FALSE;
|
||||
|
||||
if (credentials->linux_security_label != NULL)
|
||||
{
|
||||
if (!_dbus_string_append_printf (string, "%slsm='%s'",
|
||||
join ? " " : "",
|
||||
credentials->linux_security_label))
|
||||
goto oom;
|
||||
join = TRUE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
oom:
|
||||
return FALSE;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ typedef enum {
|
|||
DBUS_CREDENTIAL_UNIX_PROCESS_ID,
|
||||
DBUS_CREDENTIAL_UNIX_USER_ID,
|
||||
DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
|
||||
DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
|
||||
DBUS_CREDENTIAL_WINDOWS_SID
|
||||
} DBusCredentialType;
|
||||
|
||||
|
|
@ -47,6 +48,8 @@ dbus_bool_t _dbus_credentials_add_unix_uid (DBusCredentials
|
|||
dbus_uid_t uid);
|
||||
dbus_bool_t _dbus_credentials_add_windows_sid (DBusCredentials *credentials,
|
||||
const char *windows_sid);
|
||||
dbus_bool_t _dbus_credentials_add_linux_security_label (DBusCredentials *credentials,
|
||||
const char *label);
|
||||
dbus_bool_t _dbus_credentials_add_adt_audit_data (DBusCredentials *credentials,
|
||||
void *audit_data,
|
||||
dbus_int32_t size);
|
||||
|
|
@ -55,6 +58,7 @@ dbus_bool_t _dbus_credentials_include (DBusCredentials
|
|||
dbus_pid_t _dbus_credentials_get_pid (DBusCredentials *credentials);
|
||||
dbus_uid_t _dbus_credentials_get_unix_uid (DBusCredentials *credentials);
|
||||
const char* _dbus_credentials_get_windows_sid (DBusCredentials *credentials);
|
||||
const char * _dbus_credentials_get_linux_security_label (DBusCredentials *credentials);
|
||||
void * _dbus_credentials_get_adt_audit_data (DBusCredentials *credentials);
|
||||
dbus_int32_t _dbus_credentials_get_adt_audit_data_size (DBusCredentials *credentials);
|
||||
dbus_bool_t _dbus_credentials_are_superset (DBusCredentials *credentials,
|
||||
|
|
|
|||
|
|
@ -1666,6 +1666,105 @@ write_credentials_byte (int server_fd,
|
|||
}
|
||||
}
|
||||
|
||||
/* return FALSE on OOM, TRUE otherwise, even if no credentials were found */
|
||||
static dbus_bool_t
|
||||
add_linux_security_label_to_credentials (int client_fd,
|
||||
DBusCredentials *credentials)
|
||||
{
|
||||
#if defined(__linux__) && defined(SO_PEERSEC)
|
||||
DBusString buf;
|
||||
socklen_t len = 1024;
|
||||
dbus_bool_t oom = FALSE;
|
||||
|
||||
if (!_dbus_string_init_preallocated (&buf, len) ||
|
||||
!_dbus_string_set_length (&buf, len))
|
||||
return FALSE;
|
||||
|
||||
while (getsockopt (client_fd, SOL_SOCKET, SO_PEERSEC,
|
||||
_dbus_string_get_data (&buf), &len) < 0)
|
||||
{
|
||||
int e = errno;
|
||||
|
||||
_dbus_verbose ("getsockopt failed with %s, len now %lu\n",
|
||||
_dbus_strerror (e), (unsigned long) len);
|
||||
|
||||
if (e != ERANGE || len <= _dbus_string_get_length (&buf))
|
||||
{
|
||||
_dbus_verbose ("Failed to getsockopt(SO_PEERSEC): %s\n",
|
||||
_dbus_strerror (e));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If not enough space, len is updated to be enough.
|
||||
* Try again with a large enough buffer. */
|
||||
if (!_dbus_string_set_length (&buf, len))
|
||||
{
|
||||
oom = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
_dbus_verbose ("will try again with %lu\n", (unsigned long) len);
|
||||
}
|
||||
|
||||
if (len <= 0)
|
||||
{
|
||||
_dbus_verbose ("getsockopt(SO_PEERSEC) yielded <= 0 bytes: %lu\n",
|
||||
(unsigned long) len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (len > _dbus_string_get_length (&buf))
|
||||
{
|
||||
_dbus_verbose ("%lu > %d", (unsigned long) len,
|
||||
_dbus_string_get_length (&buf));
|
||||
_dbus_assert_not_reached ("getsockopt(SO_PEERSEC) overflowed");
|
||||
}
|
||||
|
||||
if (_dbus_string_get_byte (&buf, len - 1) == 0)
|
||||
{
|
||||
/* the kernel included the trailing \0 in its count,
|
||||
* but DBusString always has an extra \0 after the data anyway */
|
||||
_dbus_verbose ("subtracting trailing \\0\n");
|
||||
len--;
|
||||
}
|
||||
|
||||
if (!_dbus_string_set_length (&buf, len))
|
||||
{
|
||||
_dbus_assert_not_reached ("shortening string should not lead to OOM");
|
||||
oom = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (strlen (_dbus_string_get_const_data (&buf)) != len)
|
||||
{
|
||||
/* LSM people on the linux-security-module@ mailing list say this
|
||||
* should never happen: the label should be a bytestring with
|
||||
* an optional trailing \0 */
|
||||
_dbus_verbose ("security label from kernel had an embedded \\0, "
|
||||
"ignoring it\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
_dbus_verbose ("getsockopt(SO_PEERSEC): %lu bytes excluding \\0: %s\n",
|
||||
(unsigned long) len,
|
||||
_dbus_string_get_const_data (&buf));
|
||||
|
||||
if (!_dbus_credentials_add_linux_security_label (credentials,
|
||||
_dbus_string_get_const_data (&buf)))
|
||||
{
|
||||
oom = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
_dbus_string_free (&buf);
|
||||
return !oom;
|
||||
#else
|
||||
/* no error */
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a single byte which must be nul (an error occurs otherwise),
|
||||
* and reads unix credentials if available. Clears the credentials
|
||||
|
|
@ -1993,6 +2092,12 @@ _dbus_read_credentials_socket (int client_fd,
|
|||
}
|
||||
}
|
||||
|
||||
if (!add_linux_security_label_to_credentials (client_fd, credentials))
|
||||
{
|
||||
_DBUS_SET_OOM (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1425,6 +1425,33 @@ _dbus_transport_set_unix_user_function (DBusTransport *transport,
|
|||
transport->free_unix_user_data = free_data_function;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
_dbus_transport_get_linux_security_label (DBusTransport *transport,
|
||||
char **label_p)
|
||||
{
|
||||
DBusCredentials *auth_identity;
|
||||
|
||||
*label_p = NULL;
|
||||
|
||||
if (!transport->authenticated)
|
||||
return FALSE;
|
||||
|
||||
auth_identity = _dbus_auth_get_identity (transport->auth);
|
||||
|
||||
if (_dbus_credentials_include (auth_identity,
|
||||
DBUS_CREDENTIAL_LINUX_SECURITY_LABEL))
|
||||
{
|
||||
/* If no memory, we are supposed to return TRUE and set NULL */
|
||||
*label_p = _dbus_strdup (_dbus_credentials_get_linux_security_label (auth_identity));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See dbus_connection_get_windows_user().
|
||||
*
|
||||
|
|
|
|||
|
|
@ -87,6 +87,9 @@ void _dbus_transport_set_unix_user_function (DBusTransport
|
|||
DBusFreeFunction *old_free_data_function);
|
||||
dbus_bool_t _dbus_transport_get_windows_user (DBusTransport *transport,
|
||||
char **windows_sid_p);
|
||||
dbus_bool_t _dbus_transport_get_linux_security_label (DBusTransport *transport,
|
||||
char **label_p);
|
||||
|
||||
void _dbus_transport_set_windows_user_function (DBusTransport *transport,
|
||||
DBusAllowWindowsUserFunction function,
|
||||
void *data,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue