1 From 9da49d4eb6982c659fec988231baef8cd1b05be2 Mon Sep 17 00:00:00 2001
2 From: Simon McVittie <simon.mcvittie@collabora.co.uk>
3 Date: Wed, 11 Feb 2015 13:19:15 +0000
4 Subject: [PATCH 3/8] Add LSM-agnostic support for LinuxSecurityLabel
7 Bug: https://bugs.freedesktop.org/show_bug.cgi?id=89041
8 Change-Id: I70512843d1a7661c87461b1b6d86fbfbda934ad5
9 Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
10 Acked-by: Stephen Smalley <sds@tycho.nsa.gov> (for SELinux)
11 Acked-by: John Johansen <john.johansen@canonical.com> (for AppArmor)
12 Acked-by: Casey Schaufler <casey@schaufler-ca.com> (for Smack)
13 Tested-by: Tyler Hicks <tyhicks@canonical.com>
15 bus/driver.c | 19 ++++++++
16 dbus/dbus-auth.c | 11 +++--
17 dbus/dbus-connection-internal.h | 3 ++
18 dbus/dbus-connection.c | 26 ++++++++++
19 dbus/dbus-credentials.c | 68 ++++++++++++++++++++++++++
20 dbus/dbus-credentials.h | 4 ++
21 dbus/dbus-sysdeps-unix.c | 105 ++++++++++++++++++++++++++++++++++++++++
22 dbus/dbus-transport.c | 27 +++++++++++
23 dbus/dbus-transport.h | 3 ++
24 9 files changed, 262 insertions(+), 4 deletions(-)
26 diff --git a/bus/driver.c b/bus/driver.c
27 index 888c7ca..11706f8 100644
33 #include <dbus/dbus-asv-util.h>
34 +#include <dbus/dbus-connection-internal.h>
35 #include <dbus/dbus-string.h>
36 #include <dbus/dbus-internals.h>
37 #include <dbus/dbus-message.h>
38 @@ -1567,6 +1568,7 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
39 DBusMessageIter reply_iter;
40 DBusMessageIter array_iter;
41 unsigned long ulong_val;
45 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
46 @@ -1601,6 +1603,23 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
50 + if (_dbus_connection_get_linux_security_label (conn, &s))
55 + /* use the GVariant bytestring convention for strings of unknown
56 + * encoding: include the \0 in the payload, for zero-copy reading */
57 + if (!_dbus_asv_add_byte_array (&array_iter, "LinuxSecurityLabel",
67 if (!_dbus_asv_close (&reply_iter, &array_iter))
70 diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c
71 index 6a07665..aee877d 100644
72 --- a/dbus/dbus-auth.c
73 +++ b/dbus/dbus-auth.c
74 @@ -1102,20 +1102,23 @@ handle_server_data_external_mech (DBusAuth *auth,
75 auth->desired_identity))
78 - /* also copy process ID from the socket credentials
79 + /* also copy misc process info from the socket credentials
81 if (!_dbus_credentials_add_credential (auth->authorized_identity,
82 DBUS_CREDENTIAL_UNIX_PROCESS_ID,
86 - /* also copy audit data from the socket credentials
88 if (!_dbus_credentials_add_credential (auth->authorized_identity,
89 DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
94 + if (!_dbus_credentials_add_credential (auth->authorized_identity,
95 + DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
102 diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h
103 index 2897404..64ef336 100644
104 --- a/dbus/dbus-connection-internal.h
105 +++ b/dbus/dbus-connection-internal.h
106 @@ -107,6 +107,9 @@ void _dbus_connection_set_pending_fds_function (DBusConnectio
107 DBusPendingFdsChangeFunction callback,
110 +dbus_bool_t _dbus_connection_get_linux_security_label (DBusConnection *connection,
113 /* if DBUS_ENABLE_STATS */
114 void _dbus_connection_get_stats (DBusConnection *connection,
115 dbus_uint32_t *in_messages,
116 diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
117 index b574207..8952b75 100644
118 --- a/dbus/dbus-connection.c
119 +++ b/dbus/dbus-connection.c
120 @@ -5322,6 +5322,32 @@ dbus_connection_set_unix_user_function (DBusConnection *connection,
121 (* old_free_function) (old_data);
124 +/* Same calling convention as dbus_connection_get_windows_user */
126 +_dbus_connection_get_linux_security_label (DBusConnection *connection,
129 + dbus_bool_t result;
131 + _dbus_assert (connection != NULL);
132 + _dbus_assert (label_p != NULL);
134 + CONNECTION_LOCK (connection);
136 + if (!_dbus_transport_try_to_authenticate (connection->transport))
139 + result = _dbus_transport_get_linux_security_label (connection->transport,
142 + _dbus_assert (!result);
145 + CONNECTION_UNLOCK (connection);
151 * Gets the Windows user SID of the connection if known. Returns
152 * #TRUE if the ID is filled in. Always returns #FALSE on non-Windows
153 diff --git a/dbus/dbus-credentials.c b/dbus/dbus-credentials.c
154 index 7325125..151bb00 100644
155 --- a/dbus/dbus-credentials.c
156 +++ b/dbus/dbus-credentials.c
157 @@ -50,6 +50,7 @@ struct DBusCredentials {
161 + char *linux_security_label;
162 void *adt_audit_data;
163 dbus_int32_t adt_audit_data_size;
165 @@ -79,6 +80,7 @@ _dbus_credentials_new (void)
166 creds->unix_uid = DBUS_UID_UNSET;
167 creds->pid = DBUS_PID_UNSET;
168 creds->windows_sid = NULL;
169 + creds->linux_security_label = NULL;
170 creds->adt_audit_data = NULL;
171 creds->adt_audit_data_size = 0;
173 @@ -133,6 +135,7 @@ _dbus_credentials_unref (DBusCredentials *credentials)
174 if (credentials->refcount == 0)
176 dbus_free (credentials->windows_sid);
177 + dbus_free (credentials->linux_security_label);
178 dbus_free (credentials->adt_audit_data);
179 dbus_free (credentials);
181 @@ -193,6 +196,30 @@ _dbus_credentials_add_windows_sid (DBusCredentials *credentials,
185 + * Add a Linux security label, as used by LSMs such as SELinux, Smack and
186 + * AppArmor, to the credentials.
188 + * @param credentials the object
189 + * @param label the label
190 + * @returns #FALSE if no memory
193 +_dbus_credentials_add_linux_security_label (DBusCredentials *credentials,
198 + copy = _dbus_strdup (label);
202 + dbus_free (credentials->linux_security_label);
203 + credentials->linux_security_label = copy;
209 * Add ADT audit data to the credentials.
211 * @param credentials the object
212 @@ -236,6 +263,8 @@ _dbus_credentials_include (DBusCredentials *credentials,
213 return credentials->unix_uid != DBUS_UID_UNSET;
214 case DBUS_CREDENTIAL_WINDOWS_SID:
215 return credentials->windows_sid != NULL;
216 + case DBUS_CREDENTIAL_LINUX_SECURITY_LABEL:
217 + return credentials->linux_security_label != NULL;
218 case DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID:
219 return credentials->adt_audit_data != NULL;
221 @@ -284,6 +313,19 @@ _dbus_credentials_get_windows_sid (DBusCredentials *credentials)
225 + * Gets the Linux security label (as used by LSMs) from the credentials,
226 + * or #NULL if the credentials object doesn't contain a security label.
228 + * @param credentials the object
229 + * @returns the security label
232 +_dbus_credentials_get_linux_security_label (DBusCredentials *credentials)
234 + return credentials->linux_security_label;
238 * Gets the ADT audit data in the credentials, or #NULL if
239 * the credentials object doesn't contain ADT audit data.
241 @@ -329,6 +371,10 @@ _dbus_credentials_are_superset (DBusCredentials *credentials,
242 (possible_subset->windows_sid == NULL ||
243 (credentials->windows_sid && strcmp (possible_subset->windows_sid,
244 credentials->windows_sid) == 0)) &&
245 + (possible_subset->linux_security_label == NULL ||
246 + (credentials->linux_security_label != NULL &&
247 + strcmp (possible_subset->linux_security_label,
248 + credentials->linux_security_label) == 0)) &&
249 (possible_subset->adt_audit_data == NULL ||
250 (credentials->adt_audit_data && memcmp (possible_subset->adt_audit_data,
251 credentials->adt_audit_data,
252 @@ -348,6 +394,7 @@ _dbus_credentials_are_empty (DBusCredentials *credentials)
253 credentials->pid == DBUS_PID_UNSET &&
254 credentials->unix_uid == DBUS_UID_UNSET &&
255 credentials->windows_sid == NULL &&
256 + credentials->linux_security_label == NULL &&
257 credentials->adt_audit_data == NULL;
260 @@ -388,6 +435,9 @@ _dbus_credentials_add_credentials (DBusCredentials *credentials,
261 DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
262 other_credentials) &&
263 _dbus_credentials_add_credential (credentials,
264 + DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
265 + other_credentials) &&
266 + _dbus_credentials_add_credential (credentials,
267 DBUS_CREDENTIAL_WINDOWS_SID,
270 @@ -427,6 +477,13 @@ _dbus_credentials_add_credential (DBusCredentials *credentials,
271 if (!_dbus_credentials_add_windows_sid (credentials, other_credentials->windows_sid))
274 + else if (which == DBUS_CREDENTIAL_LINUX_SECURITY_LABEL &&
275 + other_credentials->linux_security_label != NULL)
277 + if (!_dbus_credentials_add_linux_security_label (credentials,
278 + other_credentials->linux_security_label))
281 else if (which == DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID &&
282 other_credentials->adt_audit_data != NULL)
284 @@ -449,6 +506,8 @@ _dbus_credentials_clear (DBusCredentials *credentials)
285 credentials->unix_uid = DBUS_UID_UNSET;
286 dbus_free (credentials->windows_sid);
287 credentials->windows_sid = NULL;
288 + dbus_free (credentials->linux_security_label);
289 + credentials->linux_security_label = NULL;
290 dbus_free (credentials->adt_audit_data);
291 credentials->adt_audit_data = NULL;
292 credentials->adt_audit_data_size = 0;
293 @@ -540,6 +599,15 @@ _dbus_credentials_to_string_append (DBusCredentials *credentials,
297 + if (credentials->linux_security_label != NULL)
299 + if (!_dbus_string_append_printf (string, "%slsm='%s'",
301 + credentials->linux_security_label))
309 diff --git a/dbus/dbus-credentials.h b/dbus/dbus-credentials.h
310 index abcc4bb..ab74eac 100644
311 --- a/dbus/dbus-credentials.h
312 +++ b/dbus/dbus-credentials.h
313 @@ -34,6 +34,7 @@ typedef enum {
314 DBUS_CREDENTIAL_UNIX_PROCESS_ID,
315 DBUS_CREDENTIAL_UNIX_USER_ID,
316 DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
317 + DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
318 DBUS_CREDENTIAL_WINDOWS_SID
319 } DBusCredentialType;
321 @@ -47,6 +48,8 @@ dbus_bool_t _dbus_credentials_add_unix_uid (DBusCredentials
323 dbus_bool_t _dbus_credentials_add_windows_sid (DBusCredentials *credentials,
324 const char *windows_sid);
325 +dbus_bool_t _dbus_credentials_add_linux_security_label (DBusCredentials *credentials,
326 + const char *label);
327 dbus_bool_t _dbus_credentials_add_adt_audit_data (DBusCredentials *credentials,
330 @@ -55,6 +58,7 @@ dbus_bool_t _dbus_credentials_include (DBusCredentials
331 dbus_pid_t _dbus_credentials_get_pid (DBusCredentials *credentials);
332 dbus_uid_t _dbus_credentials_get_unix_uid (DBusCredentials *credentials);
333 const char* _dbus_credentials_get_windows_sid (DBusCredentials *credentials);
334 +const char * _dbus_credentials_get_linux_security_label (DBusCredentials *credentials);
335 void * _dbus_credentials_get_adt_audit_data (DBusCredentials *credentials);
336 dbus_int32_t _dbus_credentials_get_adt_audit_data_size (DBusCredentials *credentials);
337 dbus_bool_t _dbus_credentials_are_superset (DBusCredentials *credentials,
338 diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
339 index fe891ab..61af423 100644
340 --- a/dbus/dbus-sysdeps-unix.c
341 +++ b/dbus/dbus-sysdeps-unix.c
342 @@ -1639,6 +1639,105 @@ write_credentials_byte (int server_fd,
346 +/* return FALSE on OOM, TRUE otherwise, even if no credentials were found */
348 +add_linux_security_label_to_credentials (int client_fd,
349 + DBusCredentials *credentials)
351 +#if defined(__linux__) && defined(SO_PEERSEC)
353 + socklen_t len = 1024;
354 + dbus_bool_t oom = FALSE;
356 + if (!_dbus_string_init_preallocated (&buf, len) ||
357 + !_dbus_string_set_length (&buf, len))
360 + while (getsockopt (client_fd, SOL_SOCKET, SO_PEERSEC,
361 + _dbus_string_get_data (&buf), &len) < 0)
365 + _dbus_verbose ("getsockopt failed with %s, len now %lu\n",
366 + _dbus_strerror (e), (unsigned long) len);
368 + if (e != ERANGE || len <= _dbus_string_get_length (&buf))
370 + _dbus_verbose ("Failed to getsockopt(SO_PEERSEC): %s\n",
371 + _dbus_strerror (e));
375 + /* If not enough space, len is updated to be enough.
376 + * Try again with a large enough buffer. */
377 + if (!_dbus_string_set_length (&buf, len))
383 + _dbus_verbose ("will try again with %lu\n", (unsigned long) len);
388 + _dbus_verbose ("getsockopt(SO_PEERSEC) yielded <= 0 bytes: %lu\n",
389 + (unsigned long) len);
393 + if (len > _dbus_string_get_length (&buf))
395 + _dbus_verbose ("%lu > %d", (unsigned long) len,
396 + _dbus_string_get_length (&buf));
397 + _dbus_assert_not_reached ("getsockopt(SO_PEERSEC) overflowed");
400 + if (_dbus_string_get_byte (&buf, len - 1) == 0)
402 + /* the kernel included the trailing \0 in its count,
403 + * but DBusString always has an extra \0 after the data anyway */
404 + _dbus_verbose ("subtracting trailing \\0\n");
408 + if (!_dbus_string_set_length (&buf, len))
410 + _dbus_assert_not_reached ("shortening string should not lead to OOM");
415 + if (strlen (_dbus_string_get_const_data (&buf)) != len)
417 + /* LSM people on the linux-security-module@ mailing list say this
418 + * should never happen: the label should be a bytestring with
419 + * an optional trailing \0 */
420 + _dbus_verbose ("security label from kernel had an embedded \\0, "
425 + _dbus_verbose ("getsockopt(SO_PEERSEC): %lu bytes excluding \\0: %s\n",
426 + (unsigned long) len,
427 + _dbus_string_get_const_data (&buf));
429 + if (!_dbus_credentials_add_linux_security_label (credentials,
430 + _dbus_string_get_const_data (&buf)))
437 + _dbus_string_free (&buf);
446 * Reads a single byte which must be nul (an error occurs otherwise),
447 * and reads unix credentials if available. Clears the credentials
448 @@ -1922,6 +2021,12 @@ _dbus_read_credentials_socket (int client_fd,
452 + if (!add_linux_security_label_to_credentials (client_fd, credentials))
454 + _DBUS_SET_OOM (error);
461 diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c
462 index e9dcc56..a43e7bb 100644
463 --- a/dbus/dbus-transport.c
464 +++ b/dbus/dbus-transport.c
465 @@ -1425,6 +1425,33 @@ _dbus_transport_set_unix_user_function (DBusTransport *transport,
466 transport->free_unix_user_data = free_data_function;
470 +_dbus_transport_get_linux_security_label (DBusTransport *transport,
473 + DBusCredentials *auth_identity;
477 + if (!transport->authenticated)
480 + auth_identity = _dbus_auth_get_identity (transport->auth);
482 + if (_dbus_credentials_include (auth_identity,
483 + DBUS_CREDENTIAL_LINUX_SECURITY_LABEL))
485 + /* If no memory, we are supposed to return TRUE and set NULL */
486 + *label_p = _dbus_strdup (_dbus_credentials_get_linux_security_label (auth_identity));
497 * See dbus_connection_get_windows_user().
499 diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h
500 index 39c74c4..843f231 100644
501 --- a/dbus/dbus-transport.h
502 +++ b/dbus/dbus-transport.h
503 @@ -87,6 +87,9 @@ void _dbus_transport_set_unix_user_function (DBusTransport
504 DBusFreeFunction *old_free_data_function);
505 dbus_bool_t _dbus_transport_get_windows_user (DBusTransport *transport,
506 char **windows_sid_p);
507 +dbus_bool_t _dbus_transport_get_linux_security_label (DBusTransport *transport,
510 void _dbus_transport_set_windows_user_function (DBusTransport *transport,
511 DBusAllowWindowsUserFunction function,