Integrate parts of meta-intel-iot-security
[AGL/meta-agl.git] / meta-security / recipes-core / dbus / dbus-cynara / 0003-Add-LSM-agnostic-support-for-LinuxSecurityLabel-cred.patch
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
5  credential
6
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>
14 ---
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(-)
25
26 diff --git a/bus/driver.c b/bus/driver.c
27 index 888c7ca..11706f8 100644
28 --- a/bus/driver.c
29 +++ b/bus/driver.c
30 @@ -34,6 +34,7 @@
31  #include "utils.h"
32  
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;
42 +  char *s;
43    const char *service;
44  
45    _DBUS_ASSERT_ERROR_IS_CLEAR (error);
46 @@ -1601,6 +1603,23 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
47          goto oom;
48      }
49  
50 +  if (_dbus_connection_get_linux_security_label (conn, &s))
51 +    {
52 +      if (s == NULL)
53 +        goto oom;
54 +
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",
58 +                                     s, strlen (s) + 1))
59 +        {
60 +          dbus_free (s);
61 +          goto oom;
62 +        }
63 +
64 +      dbus_free (s);
65 +    }
66 +
67    if (!_dbus_asv_close (&reply_iter, &array_iter))
68      goto oom;
69  
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))
76          return FALSE;
77  
78 -      /* also copy process ID from the socket credentials
79 +      /* also copy misc process info from the socket credentials
80         */
81        if (!_dbus_credentials_add_credential (auth->authorized_identity,
82                                               DBUS_CREDENTIAL_UNIX_PROCESS_ID,
83                                               auth->credentials))
84          return FALSE;
85  
86 -      /* also copy audit data from the socket credentials
87 -       */
88        if (!_dbus_credentials_add_credential (auth->authorized_identity,
89                                               DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
90                                               auth->credentials))
91          return FALSE;
92 -      
93 +
94 +      if (!_dbus_credentials_add_credential (auth->authorized_identity,
95 +                                             DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
96 +                                             auth->credentials))
97 +        return FALSE;
98 +
99        if (!send_ok (auth))
100          return FALSE;
101  
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,
108                                                                     void *data);
109  
110 +dbus_bool_t       _dbus_connection_get_linux_security_label       (DBusConnection  *connection,
111 +                                                                   char           **label_p);
112 +
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);
122  }
123  
124 +/* Same calling convention as dbus_connection_get_windows_user */
125 +dbus_bool_t
126 +_dbus_connection_get_linux_security_label (DBusConnection  *connection,
127 +                                           char           **label_p)
128 +{
129 +  dbus_bool_t result;
130 +
131 +  _dbus_assert (connection != NULL);
132 +  _dbus_assert (label_p != NULL);
133 +
134 +  CONNECTION_LOCK (connection);
135 +
136 +  if (!_dbus_transport_try_to_authenticate (connection->transport))
137 +    result = FALSE;
138 +  else
139 +    result = _dbus_transport_get_linux_security_label (connection->transport,
140 +                                                       label_p);
141 +#ifndef __linux__
142 +  _dbus_assert (!result);
143 +#endif
144 +
145 +  CONNECTION_UNLOCK (connection);
146 +
147 +  return result;
148 +}
149 +
150  /**
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 {
158    dbus_uid_t unix_uid;
159    dbus_pid_t pid;
160    char *windows_sid;
161 +  char *linux_security_label;
162    void *adt_audit_data;
163    dbus_int32_t adt_audit_data_size;
164  };
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;
172  
173 @@ -133,6 +135,7 @@ _dbus_credentials_unref (DBusCredentials    *credentials)
174    if (credentials->refcount == 0)
175      {
176        dbus_free (credentials->windows_sid);
177 +      dbus_free (credentials->linux_security_label);
178        dbus_free (credentials->adt_audit_data);
179        dbus_free (credentials);
180      }
181 @@ -193,6 +196,30 @@ _dbus_credentials_add_windows_sid (DBusCredentials    *credentials,
182  }
183  
184  /**
185 + * Add a Linux security label, as used by LSMs such as SELinux, Smack and
186 + * AppArmor, to the credentials.
187 + *
188 + * @param credentials the object
189 + * @param label the label
190 + * @returns #FALSE if no memory
191 + */
192 +dbus_bool_t
193 +_dbus_credentials_add_linux_security_label (DBusCredentials    *credentials,
194 +                                            const char         *label)
195 +{
196 +  char *copy;
197 +
198 +  copy = _dbus_strdup (label);
199 +  if (copy == NULL)
200 +    return FALSE;
201 +
202 +  dbus_free (credentials->linux_security_label);
203 +  credentials->linux_security_label = copy;
204 +
205 +  return TRUE;
206 +}
207 +
208 +/**
209   * Add ADT audit data to the credentials.
210   *
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;
220      }
221 @@ -284,6 +313,19 @@ _dbus_credentials_get_windows_sid (DBusCredentials    *credentials)
222  }
223  
224  /**
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.
227 + *
228 + * @param credentials the object
229 + * @returns the security label
230 + */
231 +const char *
232 +_dbus_credentials_get_linux_security_label (DBusCredentials *credentials)
233 +{
234 +  return credentials->linux_security_label;
235 +}
236 +
237 +/**
238   * Gets the ADT audit data in the credentials, or #NULL if
239   * the credentials object doesn't contain ADT audit data.
240   *
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;
258  }
259  
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,
268                                        other_credentials);
269  }
270 @@ -427,6 +477,13 @@ _dbus_credentials_add_credential (DBusCredentials    *credentials,
271        if (!_dbus_credentials_add_windows_sid (credentials, other_credentials->windows_sid))
272          return FALSE;
273      } 
274 +  else if (which == DBUS_CREDENTIAL_LINUX_SECURITY_LABEL &&
275 +           other_credentials->linux_security_label != NULL)
276 +    {
277 +      if (!_dbus_credentials_add_linux_security_label (credentials,
278 +            other_credentials->linux_security_label))
279 +        return FALSE;
280 +    }
281    else if (which == DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID &&
282             other_credentials->adt_audit_data != NULL) 
283      {
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,
294    else
295      join = FALSE;
296  
297 +  if (credentials->linux_security_label != NULL)
298 +    {
299 +      if (!_dbus_string_append_printf (string, "%slsm='%s'",
300 +                                       join ? " " : "",
301 +                                       credentials->linux_security_label))
302 +        goto oom;
303 +      join = TRUE;
304 +    }
305 +
306    return TRUE;
307  oom:
308    return FALSE;
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;
320  
321 @@ -47,6 +48,8 @@ dbus_bool_t      _dbus_credentials_add_unix_uid             (DBusCredentials
322                                                               dbus_uid_t          uid);
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,
328                                                               void               *audit_data,
329                                                               dbus_int32_t        size);
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,
343      }
344  }
345  
346 +/* return FALSE on OOM, TRUE otherwise, even if no credentials were found */
347 +static dbus_bool_t
348 +add_linux_security_label_to_credentials (int              client_fd,
349 +                                         DBusCredentials *credentials)
350 +{
351 +#if defined(__linux__) && defined(SO_PEERSEC)
352 +  DBusString buf;
353 +  socklen_t len = 1024;
354 +  dbus_bool_t oom = FALSE;
355 +
356 +  if (!_dbus_string_init_preallocated (&buf, len) ||
357 +      !_dbus_string_set_length (&buf, len))
358 +    return FALSE;
359 +
360 +  while (getsockopt (client_fd, SOL_SOCKET, SO_PEERSEC,
361 +         _dbus_string_get_data (&buf), &len) < 0)
362 +    {
363 +      int e = errno;
364 +
365 +      _dbus_verbose ("getsockopt failed with %s, len now %lu\n",
366 +                     _dbus_strerror (e), (unsigned long) len);
367 +
368 +      if (e != ERANGE || len <= _dbus_string_get_length (&buf))
369 +        {
370 +          _dbus_verbose ("Failed to getsockopt(SO_PEERSEC): %s\n",
371 +                         _dbus_strerror (e));
372 +          goto out;
373 +        }
374 +
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))
378 +        {
379 +          oom = TRUE;
380 +          goto out;
381 +        }
382 +
383 +      _dbus_verbose ("will try again with %lu\n", (unsigned long) len);
384 +    }
385 +
386 +  if (len <= 0)
387 +    {
388 +      _dbus_verbose ("getsockopt(SO_PEERSEC) yielded <= 0 bytes: %lu\n",
389 +                     (unsigned long) len);
390 +      goto out;
391 +    }
392 +
393 +  if (len > _dbus_string_get_length (&buf))
394 +    {
395 +      _dbus_verbose ("%lu > %d", (unsigned long) len,
396 +                     _dbus_string_get_length (&buf));
397 +      _dbus_assert_not_reached ("getsockopt(SO_PEERSEC) overflowed");
398 +    }
399 +
400 +  if (_dbus_string_get_byte (&buf, len - 1) == 0)
401 +    {
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");
405 +      len--;
406 +    }
407 +
408 +  if (!_dbus_string_set_length (&buf, len))
409 +    {
410 +      _dbus_assert_not_reached ("shortening string should not lead to OOM");
411 +      oom = TRUE;
412 +      goto out;
413 +    }
414 +
415 +  if (strlen (_dbus_string_get_const_data (&buf)) != len)
416 +    {
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, "
421 +                     "ignoring it\n");
422 +      goto out;
423 +    }
424 +
425 +  _dbus_verbose ("getsockopt(SO_PEERSEC): %lu bytes excluding \\0: %s\n",
426 +                 (unsigned long) len,
427 +                 _dbus_string_get_const_data (&buf));
428 +
429 +  if (!_dbus_credentials_add_linux_security_label (credentials,
430 +        _dbus_string_get_const_data (&buf)))
431 +    {
432 +      oom = TRUE;
433 +      goto out;
434 +    }
435 +
436 +out:
437 +  _dbus_string_free (&buf);
438 +  return !oom;
439 +#else
440 +  /* no error */
441 +  return TRUE;
442 +#endif
443 +}
444 +
445  /**
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,
449          }
450      }
451  
452 +  if (!add_linux_security_label_to_credentials (client_fd, credentials))
453 +    {
454 +      _DBUS_SET_OOM (error);
455 +      return FALSE;
456 +    }
457 +
458    return TRUE;
459  }
460  
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;
467  }
468  
469 +dbus_bool_t
470 +_dbus_transport_get_linux_security_label (DBusTransport  *transport,
471 +                                          char          **label_p)
472 +{
473 +  DBusCredentials *auth_identity;
474 +
475 +  *label_p = NULL;
476 +
477 +  if (!transport->authenticated)
478 +    return FALSE;
479 +
480 +  auth_identity = _dbus_auth_get_identity (transport->auth);
481 +
482 +  if (_dbus_credentials_include (auth_identity,
483 +                                 DBUS_CREDENTIAL_LINUX_SECURITY_LABEL))
484 +    {
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));
487 +
488 +      return TRUE;
489 +    }
490 +  else
491 +    {
492 +      return FALSE;
493 +    }
494 +}
495 +
496  /**
497   * See dbus_connection_get_windows_user().
498   *
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,
508 +                                                           char                      **label_p);
509 +
510  void               _dbus_transport_set_windows_user_function (DBusTransport              *transport,
511                                                                DBusAllowWindowsUserFunction   function,
512                                                                void                       *data,
513 -- 
514 2.1.4
515