X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=meta-security%2Frecipes-core%2Fdbus%2Fdbus-cynara%2F0003-Add-LSM-agnostic-support-for-LinuxSecurityLabel-cred.patch;fp=meta-security%2Frecipes-core%2Fdbus%2Fdbus-cynara%2F0003-Add-LSM-agnostic-support-for-LinuxSecurityLabel-cred.patch;h=fcb85504d32d808ddd5d5b15f191c655f32853da;hb=f70d712e4f505f5c5b50ae17f4f023d20a667568;hp=0000000000000000000000000000000000000000;hpb=3f962c7d202055777dd0238f12dbcf70f09ac07d;p=AGL%2Fmeta-agl.git diff --git a/meta-security/recipes-core/dbus/dbus-cynara/0003-Add-LSM-agnostic-support-for-LinuxSecurityLabel-cred.patch b/meta-security/recipes-core/dbus/dbus-cynara/0003-Add-LSM-agnostic-support-for-LinuxSecurityLabel-cred.patch new file mode 100644 index 000000000..fcb85504d --- /dev/null +++ b/meta-security/recipes-core/dbus/dbus-cynara/0003-Add-LSM-agnostic-support-for-LinuxSecurityLabel-cred.patch @@ -0,0 +1,515 @@ +From 9da49d4eb6982c659fec988231baef8cd1b05be2 Mon Sep 17 00:00:00 2001 +From: Simon McVittie +Date: Wed, 11 Feb 2015 13:19:15 +0000 +Subject: [PATCH 3/8] Add LSM-agnostic support for LinuxSecurityLabel + credential + +Bug: https://bugs.freedesktop.org/show_bug.cgi?id=89041 +Change-Id: I70512843d1a7661c87461b1b6d86fbfbda934ad5 +Reviewed-by: Philip Withnall +Acked-by: Stephen Smalley (for SELinux) +Acked-by: John Johansen (for AppArmor) +Acked-by: Casey Schaufler (for Smack) +Tested-by: Tyler Hicks +--- + bus/driver.c | 19 ++++++++ + dbus/dbus-auth.c | 11 +++-- + dbus/dbus-connection-internal.h | 3 ++ + dbus/dbus-connection.c | 26 ++++++++++ + dbus/dbus-credentials.c | 68 ++++++++++++++++++++++++++ + dbus/dbus-credentials.h | 4 ++ + dbus/dbus-sysdeps-unix.c | 105 ++++++++++++++++++++++++++++++++++++++++ + dbus/dbus-transport.c | 27 +++++++++++ + dbus/dbus-transport.h | 3 ++ + 9 files changed, 262 insertions(+), 4 deletions(-) + +diff --git a/bus/driver.c b/bus/driver.c +index 888c7ca..11706f8 100644 +--- a/bus/driver.c ++++ b/bus/driver.c +@@ -34,6 +34,7 @@ + #include "utils.h" + + #include ++#include + #include + #include + #include +@@ -1567,6 +1568,7 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection, + DBusMessageIter reply_iter; + DBusMessageIter array_iter; + unsigned long ulong_val; ++ char *s; + const char *service; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); +@@ -1601,6 +1603,23 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection, + goto oom; + } + ++ 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)) + goto oom; + +diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c +index 6a07665..aee877d 100644 +--- a/dbus/dbus-auth.c ++++ b/dbus/dbus-auth.c +@@ -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; + +diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h +index 2897404..64ef336 100644 +--- a/dbus/dbus-connection-internal.h ++++ b/dbus/dbus-connection-internal.h +@@ -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, +diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c +index b574207..8952b75 100644 +--- a/dbus/dbus-connection.c ++++ b/dbus/dbus-connection.c +@@ -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 +diff --git a/dbus/dbus-credentials.c b/dbus/dbus-credentials.c +index 7325125..151bb00 100644 +--- a/dbus/dbus-credentials.c ++++ b/dbus/dbus-credentials.c +@@ -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); + } +@@ -193,6 +196,30 @@ _dbus_credentials_add_windows_sid (DBusCredentials *credentials, + } + + /** ++ * 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. + * + * @param credentials the object +@@ -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; + } +@@ -284,6 +313,19 @@ _dbus_credentials_get_windows_sid (DBusCredentials *credentials) + } + + /** ++ * 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; + } + +@@ -388,6 +435,9 @@ _dbus_credentials_add_credentials (DBusCredentials *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; +diff --git a/dbus/dbus-credentials.h b/dbus/dbus-credentials.h +index abcc4bb..ab74eac 100644 +--- a/dbus/dbus-credentials.h ++++ b/dbus/dbus-credentials.h +@@ -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, +diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c +index fe891ab..61af423 100644 +--- a/dbus/dbus-sysdeps-unix.c ++++ b/dbus/dbus-sysdeps-unix.c +@@ -1639,6 +1639,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 +@@ -1922,6 +2021,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; + } + +diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c +index e9dcc56..a43e7bb 100644 +--- a/dbus/dbus-transport.c ++++ b/dbus/dbus-transport.c +@@ -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(). + * +diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h +index 39c74c4..843f231 100644 +--- a/dbus/dbus-transport.h ++++ b/dbus/dbus-transport.h +@@ -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, +-- +2.1.4 +