1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2  * apparmor.c  AppArmor security checks for D-Bus
3  *
4  * Based on selinux.c
5  *
6  * Copyright © 2014-2015 Canonical, Ltd.
7  *
8  * Licensed under the Academic Free License version 2.1
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
23  *
24  */
25 
26 #include <config.h>
27 #include "apparmor.h"
28 
29 #ifdef HAVE_APPARMOR
30 
31 #include <dbus/dbus-internals.h>
32 #include <dbus/dbus-string.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <limits.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/apparmor.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <syslog.h>
43 #include <unistd.h>
44 
45 #ifdef HAVE_LIBAUDIT
46 #include <libaudit.h>
47 #endif /* HAVE_LIBAUDIT */
48 
49 #include "activation.h"
50 #include "audit.h"
51 #include "connection.h"
52 #include "utils.h"
53 
54 /* Store the value telling us if AppArmor D-Bus mediation is enabled. */
55 static dbus_bool_t apparmor_enabled = FALSE;
56 
57 typedef enum {
58   APPARMOR_DISABLED,
59   APPARMOR_ENABLED,
60   APPARMOR_REQUIRED
61 } AppArmorConfigMode;
62 
63 /* Store the value of the AppArmor mediation mode in the bus configuration */
64 static AppArmorConfigMode apparmor_config_mode = APPARMOR_ENABLED;
65 
66 /* The AppArmor context, consisting of a label and a mode. */
67 struct BusAppArmorConfinement
68 {
69   int refcount; /* Reference count */
70 
71   char *label; /* AppArmor confinement label */
72   const char *mode; /* AppArmor confinement mode (freed by freeing *label) */
73 };
74 
75 static BusAppArmorConfinement *bus_con = NULL;
76 
77 /**
78  * Callers of this function give up ownership of the *label and *mode
79  * pointers.
80  *
81  * Additionally, the responsibility of freeing *label and *mode becomes the
82  * responsibility of the bus_apparmor_confinement_unref() function. However, it
83  * does not free *mode because libapparmor's aa_getcon(), and libapparmor's
84  * other related functions, allocate a single buffer for *label and *mode and
85  * then separate the two char arrays with a NUL char. See the aa_getcon(2) man
86  * page for more details.
87  */
88 static BusAppArmorConfinement*
bus_apparmor_confinement_new(char * label,const char * mode)89 bus_apparmor_confinement_new (char       *label,
90                               const char *mode)
91 {
92   BusAppArmorConfinement *confinement;
93 
94   confinement = dbus_new0 (BusAppArmorConfinement, 1);
95   if (confinement != NULL)
96     {
97       confinement->refcount = 1;
98       confinement->label = label;
99       confinement->mode = mode;
100     }
101 
102   return confinement;
103 }
104 
105 /*
106  * Return TRUE on successful check, FALSE on OOM.
107  * Set *is_supported to whether AA has D-Bus features.
108  */
109 static dbus_bool_t
_bus_apparmor_detect_aa_dbus_support(dbus_bool_t * is_supported)110 _bus_apparmor_detect_aa_dbus_support (dbus_bool_t *is_supported)
111 {
112   int mask_file;
113   DBusString aa_dbus;
114   char *aa_securityfs = NULL;
115   dbus_bool_t retval = FALSE;
116 
117   *is_supported = FALSE;
118 
119   if (!_dbus_string_init (&aa_dbus))
120     return FALSE;
121 
122   if (aa_find_mountpoint (&aa_securityfs) != 0)
123     goto out;
124 
125   /*
126    * John Johansen has confirmed that the mainline kernel will not have
127    * the apparmorfs/features/dbus/mask file until the mainline kernel
128    * has AppArmor getpeersec support.
129    */
130   if (!_dbus_string_append (&aa_dbus, aa_securityfs) ||
131       !_dbus_string_append (&aa_dbus, "/features/dbus/mask"))
132     goto out;
133 
134   /* We need to open() the flag file, not just stat() it, because AppArmor
135    * does not mediate stat() in the apparmorfs. If you have a
136    * dbus-daemon inside an LXC container, with insufficiently broad
137    * AppArmor privileges to do its own AppArmor mediation, the desired
138    * result is that it behaves as if AppArmor was not present; but a stat()
139    * here would succeed, and result in it trying and failing to do full
140    * mediation. https://bugs.launchpad.net/ubuntu/+source/dbus/+bug/1238267 */
141   mask_file = open (_dbus_string_get_const_data (&aa_dbus),
142                     O_RDONLY | O_CLOEXEC);
143   if (mask_file != -1)
144     {
145       *is_supported = TRUE;
146       close (mask_file);
147     }
148 
149   retval = TRUE;
150 
151 out:
152   free (aa_securityfs);
153   _dbus_string_free (&aa_dbus);
154 
155   return retval;
156 }
157 
158 static dbus_bool_t
modestr_is_complain(const char * mode)159 modestr_is_complain (const char *mode)
160 {
161   if (mode && strcmp (mode, "complain") == 0)
162     return TRUE;
163   return FALSE;
164 }
165 
166 static void
log_message(dbus_bool_t allow,const char * op,DBusString * data)167 log_message (dbus_bool_t allow, const char *op, DBusString *data)
168 {
169   const char *mstr;
170 #ifdef HAVE_LIBAUDIT
171   int audit_fd;
172 #endif
173 
174   if (allow)
175     mstr = "ALLOWED";
176   else
177     mstr = "DENIED";
178 
179 #ifdef HAVE_LIBAUDIT
180   audit_fd = bus_audit_get_fd ();
181 
182   if (audit_fd >= 0)
183   {
184     DBusString avc;
185 
186     if (!_dbus_string_init (&avc))
187       goto syslog;
188 
189     if (!_dbus_string_append_printf (&avc,
190           "apparmor=\"%s\" operation=\"dbus_%s\" %s\n",
191           mstr, op, _dbus_string_get_const_data (data)))
192       {
193         _dbus_string_free (&avc);
194         goto syslog;
195       }
196 
197     /* FIXME: need to change this to show real user */
198     audit_log_user_avc_message (audit_fd, AUDIT_USER_AVC,
199                                 _dbus_string_get_const_data (&avc),
200                                 NULL, NULL, NULL, getuid ());
201     _dbus_string_free (&avc);
202     return;
203   }
204 
205 syslog:
206 #endif /* HAVE_LIBAUDIT */
207 
208   syslog (LOG_USER | LOG_NOTICE, "apparmor=\"%s\" operation=\"dbus_%s\" %s\n",
209           mstr, op, _dbus_string_get_const_data (data));
210 }
211 
212 static dbus_bool_t
_dbus_append_pair_uint(DBusString * auxdata,const char * name,unsigned long value)213 _dbus_append_pair_uint (DBusString *auxdata, const char *name,
214                        unsigned long value)
215 {
216   return _dbus_string_append (auxdata, " ") &&
217          _dbus_string_append (auxdata, name) &&
218          _dbus_string_append (auxdata, "=") &&
219          _dbus_string_append_uint (auxdata, value);
220 }
221 
222 static dbus_bool_t
_dbus_append_pair_str(DBusString * auxdata,const char * name,const char * value)223 _dbus_append_pair_str (DBusString *auxdata, const char *name, const char *value)
224 {
225   return _dbus_string_append (auxdata, " ") &&
226          _dbus_string_append (auxdata, name) &&
227          _dbus_string_append (auxdata, "=\"") &&
228          _dbus_string_append (auxdata, value) &&
229          _dbus_string_append (auxdata, "\"");
230 }
231 
232 static dbus_bool_t
_dbus_append_mask(DBusString * auxdata,uint32_t mask)233 _dbus_append_mask (DBusString *auxdata, uint32_t mask)
234 {
235   const char *mask_str;
236 
237   /* Only one permission bit can be set */
238   if (mask == AA_DBUS_SEND)
239     mask_str = "send";
240   else if (mask == AA_DBUS_RECEIVE)
241     mask_str = "receive";
242   else if (mask == AA_DBUS_BIND)
243     mask_str = "bind";
244   else
245     return FALSE;
246 
247   return _dbus_append_pair_str (auxdata, "mask", mask_str);
248 }
249 
250 static dbus_bool_t
is_unconfined(const char * con,const char * mode)251 is_unconfined (const char *con, const char *mode)
252 {
253   /* treat con == NULL as confined as it is going to result in a denial */
254   if ((!mode && con && strcmp (con, "unconfined") == 0) ||
255       strcmp (mode, "unconfined") == 0)
256     {
257       return TRUE;
258     }
259 
260   return FALSE;
261 }
262 
263 static dbus_bool_t
query_append(DBusString * query,const char * buffer)264 query_append (DBusString *query, const char *buffer)
265 {
266   if (!_dbus_string_append_byte (query, '\0'))
267     return FALSE;
268 
269   if (buffer && !_dbus_string_append (query, buffer))
270     return FALSE;
271 
272   return TRUE;
273 }
274 
275 static dbus_bool_t
build_common_query(DBusString * query,const char * con,const char * bustype)276 build_common_query (DBusString *query, const char *con, const char *bustype)
277 {
278   /**
279    * libapparmor's aa_query_label() function scribbles over the first
280    * AA_QUERY_CMD_LABEL_SIZE bytes of the query string with a private value.
281    */
282   return _dbus_string_insert_bytes (query, 0, AA_QUERY_CMD_LABEL_SIZE, 0) &&
283          _dbus_string_append (query, con) &&
284          _dbus_string_append_byte (query, '\0') &&
285          _dbus_string_append_byte (query, AA_CLASS_DBUS) &&
286          _dbus_string_append (query, bustype ? bustype : "");
287 }
288 
289 static dbus_bool_t
build_service_query(DBusString * query,const char * con,const char * bustype,const char * name)290 build_service_query (DBusString *query,
291                      const char *con,
292                      const char *bustype,
293                      const char *name)
294 {
295   return build_common_query (query, con, bustype) &&
296          query_append (query, name);
297 }
298 
299 static dbus_bool_t
build_message_query(DBusString * query,const char * src_con,const char * bustype,const char * name,const char * dst_con,const char * path,const char * interface,const char * member)300 build_message_query (DBusString *query,
301                      const char *src_con,
302                      const char *bustype,
303                      const char *name,
304                      const char *dst_con,
305                      const char *path,
306                      const char *interface,
307                      const char *member)
308 {
309   return build_common_query (query, src_con, bustype) &&
310          query_append (query, name) &&
311          query_append (query, dst_con) &&
312          query_append (query, path) &&
313          query_append (query, interface) &&
314          query_append (query, member);
315 }
316 
317 static dbus_bool_t
build_eavesdrop_query(DBusString * query,const char * con,const char * bustype)318 build_eavesdrop_query (DBusString *query, const char *con, const char *bustype)
319 {
320   return build_common_query (query, con, bustype);
321 }
322 
323 static void
set_error_from_query_errno(DBusError * error,int error_number)324 set_error_from_query_errno (DBusError *error, int error_number)
325 {
326   dbus_set_error (error, _dbus_error_from_errno (error_number),
327                   "Failed to query AppArmor policy: %s",
328                   _dbus_strerror (error_number));
329 }
330 
331 static void
set_error_from_denied_message(DBusError * error,DBusConnection * sender,DBusConnection * proposed_recipient,dbus_bool_t requested_reply,const char * msgtype,const char * path,const char * interface,const char * member,const char * error_name,const char * destination)332 set_error_from_denied_message (DBusError      *error,
333                                DBusConnection *sender,
334                                DBusConnection *proposed_recipient,
335                                dbus_bool_t     requested_reply,
336                                const char     *msgtype,
337                                const char     *path,
338                                const char     *interface,
339                                const char     *member,
340                                const char     *error_name,
341                                const char     *destination)
342 {
343   const char *proposed_recipient_loginfo;
344   const char *unset = "(unset)";
345 
346   proposed_recipient_loginfo = proposed_recipient ?
347                                bus_connection_get_loginfo (proposed_recipient) :
348                                "bus";
349 
350   dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
351                   "An AppArmor policy prevents this sender from sending this "
352                   "message to this recipient; type=\"%s\", "
353                   "sender=\"%s\" (%s) interface=\"%s\" member=\"%s\" "
354                   "error name=\"%s\" requested_reply=\"%d\" "
355                   "destination=\"%s\" (%s)",
356                   msgtype,
357                   bus_connection_get_name (sender),
358                   bus_connection_get_loginfo (sender),
359                   interface ? interface : unset,
360                   member ? member : unset,
361                   error_name ? error_name : unset,
362                   requested_reply,
363                   destination,
364                   proposed_recipient_loginfo);
365 }
366 #endif /* HAVE_APPARMOR */
367 
368 /**
369  * Do early initialization; determine whether AppArmor is enabled.
370  * Return TRUE on successful check (whether AppArmor is actually
371  * enabled or not) or FALSE on OOM.
372  */
373 dbus_bool_t
bus_apparmor_pre_init(void)374 bus_apparmor_pre_init (void)
375 {
376 #ifdef HAVE_APPARMOR
377   apparmor_enabled = FALSE;
378 
379   if (!aa_is_enabled ())
380     return TRUE;
381 
382   if (!_bus_apparmor_detect_aa_dbus_support (&apparmor_enabled))
383     return FALSE;
384 #endif
385 
386   return TRUE;
387 }
388 
389 dbus_bool_t
bus_apparmor_set_mode_from_config(const char * mode,DBusError * error)390 bus_apparmor_set_mode_from_config (const char *mode, DBusError *error)
391 {
392 #ifdef HAVE_APPARMOR
393   if (mode != NULL)
394   {
395     if (strcmp (mode, "disabled") == 0)
396       apparmor_config_mode = APPARMOR_DISABLED;
397     else if (strcmp (mode, "enabled") == 0)
398       apparmor_config_mode = APPARMOR_ENABLED;
399     else if (strcmp (mode, "required") == 0)
400       apparmor_config_mode = APPARMOR_REQUIRED;
401     else
402       {
403         dbus_set_error (error, DBUS_ERROR_FAILED,
404                         "Mode attribute on <apparmor> must have value "
405                         "\"required\", \"enabled\" or \"disabled\", "
406                         "not \"%s\"", mode);
407         return FALSE;
408       }
409   }
410 
411   return TRUE;
412 #else
413   if (mode == NULL || strcmp (mode, "disabled") == 0 ||
414                       strcmp (mode, "enabled") == 0)
415     return TRUE;
416 
417   dbus_set_error (error, DBUS_ERROR_FAILED,
418                   "Mode attribute on <apparmor> must have value \"enabled\" or "
419                   "\"disabled\" but cannot be \"%s\" when D-Bus is built "
420                   "without AppArmor support", mode);
421   return FALSE;
422 #endif
423 }
424 
425 /**
426  * Verify that the config mode is compatible with the kernel's AppArmor
427  * support. If AppArmor mediation will be enabled, determine the bus
428  * confinement label.
429  */
430 dbus_bool_t
bus_apparmor_full_init(DBusError * error)431 bus_apparmor_full_init (DBusError *error)
432 {
433 #ifdef HAVE_APPARMOR
434   char *label, *mode;
435 
436   if (apparmor_enabled)
437     {
438       if (apparmor_config_mode == APPARMOR_DISABLED)
439         {
440           apparmor_enabled = FALSE;
441           return TRUE;
442         }
443 
444       if (bus_con == NULL)
445         {
446           if (aa_getcon (&label, &mode) == -1)
447             {
448               dbus_set_error (error, DBUS_ERROR_FAILED,
449                               "Error getting AppArmor context of bus: %s",
450                               _dbus_strerror (errno));
451               return FALSE;
452             }
453 
454           bus_con = bus_apparmor_confinement_new (label, mode);
455           if (bus_con == NULL)
456             {
457               BUS_SET_OOM (error);
458               free (label);
459               return FALSE;
460             }
461         }
462     }
463   else
464     {
465       if (apparmor_config_mode == APPARMOR_REQUIRED)
466         {
467           dbus_set_error (error, DBUS_ERROR_FAILED,
468                           "AppArmor mediation required but not present");
469           return FALSE;
470         }
471       else if (apparmor_config_mode == APPARMOR_ENABLED)
472         {
473           return TRUE;
474         }
475     }
476 #endif
477 
478   return TRUE;
479 }
480 
481 void
bus_apparmor_shutdown(void)482 bus_apparmor_shutdown (void)
483 {
484 #ifdef HAVE_APPARMOR
485   if (!apparmor_enabled)
486     return;
487 
488   _dbus_verbose ("AppArmor shutdown\n");
489 
490   bus_apparmor_confinement_unref (bus_con);
491   bus_con = NULL;
492 #endif /* HAVE_APPARMOR */
493 }
494 
495 dbus_bool_t
bus_apparmor_enabled(void)496 bus_apparmor_enabled (void)
497 {
498 #ifdef HAVE_APPARMOR
499   return apparmor_enabled;
500 #else
501   return FALSE;
502 #endif
503 }
504 
505 void
bus_apparmor_confinement_unref(BusAppArmorConfinement * confinement)506 bus_apparmor_confinement_unref (BusAppArmorConfinement *confinement)
507 {
508 #ifdef HAVE_APPARMOR
509   if (!apparmor_enabled)
510     return;
511 
512   _dbus_assert (confinement != NULL);
513   _dbus_assert (confinement->refcount > 0);
514 
515   confinement->refcount -= 1;
516 
517   if (confinement->refcount == 0)
518     {
519       /**
520        * Do not free confinement->mode, as libapparmor does a single malloc for
521        * both confinement->label and confinement->mode.
522        */
523       free (confinement->label);
524       dbus_free (confinement);
525     }
526 #endif
527 }
528 
529 void
bus_apparmor_confinement_ref(BusAppArmorConfinement * confinement)530 bus_apparmor_confinement_ref (BusAppArmorConfinement *confinement)
531 {
532 #ifdef HAVE_APPARMOR
533   if (!apparmor_enabled)
534     return;
535 
536   _dbus_assert (confinement != NULL);
537   _dbus_assert (confinement->refcount > 0);
538 
539   confinement->refcount += 1;
540 #endif /* HAVE_APPARMOR */
541 }
542 
543 BusAppArmorConfinement*
bus_apparmor_init_connection_confinement(DBusConnection * connection,DBusError * error)544 bus_apparmor_init_connection_confinement (DBusConnection *connection,
545                                           DBusError      *error)
546 {
547 #ifdef HAVE_APPARMOR
548   BusAppArmorConfinement *confinement;
549   char *label, *mode;
550   int fd;
551 
552   if (!apparmor_enabled)
553     return NULL;
554 
555   _dbus_assert (connection != NULL);
556 
557   if (!dbus_connection_get_socket (connection, &fd))
558     {
559       dbus_set_error (error, DBUS_ERROR_FAILED,
560                       "Failed to get socket file descriptor of connection");
561       return NULL;
562     }
563 
564   if (aa_getpeercon (fd, &label, &mode) == -1)
565     {
566       if (errno == ENOMEM)
567         BUS_SET_OOM (error);
568       else
569         dbus_set_error (error, _dbus_error_from_errno (errno),
570                         "Failed to get AppArmor confinement information of socket peer: %s",
571                         _dbus_strerror (errno));
572       return NULL;
573     }
574 
575   confinement = bus_apparmor_confinement_new (label, mode);
576   if (confinement == NULL)
577     {
578       BUS_SET_OOM (error);
579       free (label);
580       return NULL;
581     }
582 
583   return confinement;
584 #else
585   return NULL;
586 #endif /* HAVE_APPARMOR */
587 }
588 
589 /**
590  * Returns true if the given connection can acquire a service,
591  * using the tasks security context
592  *
593  * @param connection connection that wants to own the service
594  * @param bustype name of the bus
595  * @param service_name the name of the service to acquire
596  * @param error the reason for failure when FALSE is returned
597  * @returns TRUE if acquire is permitted
598  */
599 dbus_bool_t
bus_apparmor_allows_acquire_service(DBusConnection * connection,const char * bustype,const char * service_name,DBusError * error)600 bus_apparmor_allows_acquire_service (DBusConnection     *connection,
601                                      const char         *bustype,
602                                      const char         *service_name,
603                                      DBusError          *error)
604 {
605 
606 #ifdef HAVE_APPARMOR
607   BusAppArmorConfinement *con = NULL;
608   DBusString qstr, auxdata;
609   dbus_bool_t free_auxdata = FALSE;
610   /* the AppArmor API uses pointers to int for pointers to boolean, and
611    * int is not strictly guaranteed to be the same as dbus_bool_t */
612   int allow = FALSE, audit = TRUE;
613   unsigned long pid;
614   int res, serrno = 0;
615 
616   if (!apparmor_enabled)
617     return TRUE;
618 
619   _dbus_assert (connection != NULL);
620 
621   con = bus_connection_dup_apparmor_confinement (connection);
622 
623   if (is_unconfined (con->label, con->mode))
624     {
625       allow = TRUE;
626       audit = FALSE;
627       goto out;
628     }
629 
630   if (!_dbus_string_init (&qstr))
631     goto oom;
632 
633   if (!build_service_query (&qstr, con->label, bustype, service_name))
634     {
635       _dbus_string_free (&qstr);
636       goto oom;
637     }
638 
639   res = aa_query_label (AA_DBUS_BIND,
640                         _dbus_string_get_data (&qstr),
641                         _dbus_string_get_length (&qstr),
642                         &allow, &audit);
643   _dbus_string_free (&qstr);
644   if (res == -1)
645     {
646       serrno = errno;
647       set_error_from_query_errno (error, serrno);
648       goto audit;
649     }
650 
651   /* Don't fail operations on profiles in complain mode */
652   if (modestr_is_complain (con->mode))
653       allow = TRUE;
654 
655   if (!allow)
656     dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
657                     "Connection \"%s\" is not allowed to own the service "
658                     "\"%s\" due to AppArmor policy",
659                     bus_connection_is_active (connection) ?
660                      bus_connection_get_name (connection) : "(inactive)",
661                     service_name);
662 
663   if (!audit)
664     goto out;
665 
666  audit:
667   if (!_dbus_string_init (&auxdata))
668     goto oom;
669   free_auxdata = TRUE;
670 
671   if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
672     goto oom;
673 
674   if (!_dbus_append_pair_str (&auxdata, "name", service_name))
675     goto oom;
676 
677   if (serrno && !_dbus_append_pair_str (&auxdata, "info", strerror (serrno)))
678     goto oom;
679 
680   if (!_dbus_append_mask (&auxdata, AA_DBUS_BIND))
681     goto oom;
682 
683   if (connection && dbus_connection_get_unix_process_id (connection, &pid) &&
684       !_dbus_append_pair_uint (&auxdata, "pid", pid))
685     goto oom;
686 
687   if (con->label && !_dbus_append_pair_str (&auxdata, "label", con->label))
688     goto oom;
689 
690   log_message (allow, "bind", &auxdata);
691 
692  out:
693   if (con != NULL)
694     bus_apparmor_confinement_unref (con);
695   if (free_auxdata)
696     _dbus_string_free (&auxdata);
697   return allow;
698 
699  oom:
700   if (error != NULL && !dbus_error_is_set (error))
701     BUS_SET_OOM (error);
702   allow = FALSE;
703   goto out;
704 
705 #else
706   return TRUE;
707 #endif /* HAVE_APPARMOR */
708 }
709 
710 /**
711  * Check if Apparmor security controls allow the message to be sent to a
712  * particular connection based on the security context of the sender and
713  * that of the receiver. The destination connection need not be the
714  * addressed recipient, it could be an "eavesdropper"
715  *
716  * @param sender the sender of the message.
717  * @param proposed_recipient the connection the message is to be sent to.
718  * @param requested_reply TRUE if the message is a reply requested by
719  *                        proposed_recipient
720  * @param bustype name of the bus
721  * @param msgtype message type (DBUS_MESSAGE_TYPE_METHOD_CALL, etc.)
722  * @param path object path the message should be sent to
723  * @param interface the type of the object instance
724  * @param member the member of the object
725  * @param error_name the name of the error if the message type is error
726  * @param destination name that the message should be sent to
727  * @param source name that the message should be sent from
728  * @param error the reason for failure when FALSE is returned
729  * @returns TRUE if the message is permitted
730  */
731 dbus_bool_t
bus_apparmor_allows_send(DBusConnection * sender,DBusConnection * proposed_recipient,dbus_bool_t requested_reply,const char * bustype,int msgtype,const char * path,const char * interface,const char * member,const char * error_name,const char * destination,const char * source,BusActivationEntry * activation_entry,DBusError * error)732 bus_apparmor_allows_send (DBusConnection     *sender,
733                           DBusConnection     *proposed_recipient,
734                           dbus_bool_t         requested_reply,
735                           const char         *bustype,
736                           int                 msgtype,
737                           const char         *path,
738                           const char         *interface,
739                           const char         *member,
740                           const char         *error_name,
741                           const char         *destination,
742                           const char         *source,
743                           BusActivationEntry *activation_entry,
744                           DBusError          *error)
745 {
746 #ifdef HAVE_APPARMOR
747   BusAppArmorConfinement *src_con = NULL, *dst_con = NULL;
748   DBusString qstr, auxdata;
749   int src_allow = FALSE, dst_allow = FALSE;
750   int src_audit = TRUE, dst_audit = TRUE;
751   dbus_bool_t free_auxdata = FALSE;
752   unsigned long pid;
753   int len, res, src_errno = 0, dst_errno = 0;
754   uint32_t src_perm = AA_DBUS_SEND, dst_perm = AA_DBUS_RECEIVE;
755   const char *msgtypestr = dbus_message_type_to_string(msgtype);
756   const char *dst_label = NULL;
757   const char *dst_mode = NULL;
758 
759   if (!apparmor_enabled)
760     return TRUE;
761 
762   _dbus_assert (sender != NULL);
763 
764   src_con = bus_connection_dup_apparmor_confinement (sender);
765 
766   if (proposed_recipient)
767     {
768       dst_con = bus_connection_dup_apparmor_confinement (proposed_recipient);
769     }
770   else if (activation_entry != NULL)
771     {
772       dst_label = bus_activation_entry_get_assumed_apparmor_label (activation_entry);
773     }
774   else
775     {
776       dst_con = bus_con;
777       bus_apparmor_confinement_ref (dst_con);
778     }
779 
780   if (dst_con != NULL)
781     {
782       dst_label = dst_con->label;
783       dst_mode = dst_con->mode;
784     }
785 
786   /* map reply messages to initial send and receive permission. That is
787    * permission to receive a message from X grants permission to reply to X.
788    * And permission to send a message to Y grants permission to receive a reply
789    * from Y. Note that this only applies to requested replies. Unrequested
790    * replies still require a policy query.
791    */
792   if (requested_reply)
793     {
794       /* ignore requested reply messages and let dbus reply mapping handle them
795        * as the send was already allowed
796        */
797       src_allow = TRUE;
798       dst_allow = TRUE;
799       goto out;
800     }
801 
802   if (is_unconfined (src_con->label, src_con->mode))
803     {
804       src_allow = TRUE;
805       src_audit = FALSE;
806     }
807   else
808     {
809       if (!_dbus_string_init (&qstr))
810         goto oom;
811 
812       if (!build_message_query (&qstr, src_con->label, bustype, destination,
813                                 dst_label, path, interface, member))
814         {
815           _dbus_string_free (&qstr);
816           goto oom;
817         }
818 
819       res = aa_query_label (src_perm,
820                             _dbus_string_get_data (&qstr),
821                             _dbus_string_get_length (&qstr),
822                             &src_allow, &src_audit);
823       _dbus_string_free (&qstr);
824       if (res == -1)
825         {
826           src_errno = errno;
827           set_error_from_query_errno (error, src_errno);
828           goto audit;
829         }
830     }
831 
832   /* When deciding whether we can activate a service, we only check that
833    * we are allowed to send a message to it, not that it is allowed to
834    * receive that message from us.
835    */
836   if (activation_entry != NULL || is_unconfined (dst_label, dst_mode))
837     {
838       dst_allow = TRUE;
839       dst_audit = FALSE;
840     }
841   else
842     {
843       if (!_dbus_string_init (&qstr))
844         goto oom;
845 
846       if (!build_message_query (&qstr, dst_label, bustype, source,
847                                 src_con->label, path, interface, member))
848         {
849           _dbus_string_free (&qstr);
850           goto oom;
851         }
852 
853       res = aa_query_label (dst_perm,
854                             _dbus_string_get_data (&qstr),
855                             _dbus_string_get_length (&qstr),
856                             &dst_allow, &dst_audit);
857       _dbus_string_free (&qstr);
858       if (res == -1)
859         {
860           dst_errno = errno;
861           set_error_from_query_errno (error, dst_errno);
862           goto audit;
863         }
864     }
865 
866   /* Don't fail operations on profiles in complain mode */
867   if (modestr_is_complain (src_con->mode))
868     src_allow = TRUE;
869   if (modestr_is_complain (dst_mode))
870     dst_allow = TRUE;
871 
872   if (!src_allow || !dst_allow)
873     set_error_from_denied_message (error,
874                                    sender,
875                                    proposed_recipient,
876                                    requested_reply,
877                                    msgtypestr,
878                                    path,
879                                    interface,
880                                    member,
881                                    error_name,
882                                    destination);
883 
884   /* Don't audit the message if one of the following conditions is true:
885    *   1) The AppArmor query indicates that auditing should not happen.
886    *   2) The message is a reply type. Reply message are not audited because
887    *      the AppArmor policy language does not have the notion of a reply
888    *      message. Unrequested replies will be silently discarded if the sender
889    *      does not have permission to send to the receiver or if the receiver
890    *      does not have permission to receive from the sender.
891    */
892   if ((!src_audit && !dst_audit) ||
893       (msgtype == DBUS_MESSAGE_TYPE_METHOD_RETURN ||
894        msgtype == DBUS_MESSAGE_TYPE_ERROR))
895     goto out;
896 
897  audit:
898   if (!_dbus_string_init (&auxdata))
899     goto oom;
900   free_auxdata = TRUE;
901 
902   if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
903     goto oom;
904 
905   if (path && !_dbus_append_pair_str (&auxdata, "path", path))
906     goto oom;
907 
908   if (interface && !_dbus_append_pair_str (&auxdata, "interface", interface))
909     goto oom;
910 
911   if (member && !_dbus_append_pair_str (&auxdata, "member", member))
912     goto oom;
913 
914   if (error_name && !_dbus_append_pair_str (&auxdata, "error_name", error_name))
915     goto oom;
916 
917   len = _dbus_string_get_length (&auxdata);
918 
919   if (src_audit)
920     {
921       if (!_dbus_append_mask (&auxdata, src_perm))
922         goto oom;
923 
924       if (destination && !_dbus_append_pair_str (&auxdata, "name", destination))
925         goto oom;
926 
927       if (sender && dbus_connection_get_unix_process_id (sender, &pid) &&
928           !_dbus_append_pair_uint (&auxdata, "pid", pid))
929         goto oom;
930 
931       if (src_con->label &&
932           !_dbus_append_pair_str (&auxdata, "label", src_con->label))
933         goto oom;
934 
935       if (proposed_recipient &&
936           dbus_connection_get_unix_process_id (proposed_recipient, &pid) &&
937           !_dbus_append_pair_uint (&auxdata, "peer_pid", pid))
938         goto oom;
939 
940       if (dst_label &&
941           !_dbus_append_pair_str (&auxdata, "peer_label", dst_label))
942         goto oom;
943 
944       if (src_errno && !_dbus_append_pair_str (&auxdata, "info", strerror (src_errno)))
945         goto oom;
946 
947       if (dst_errno &&
948           !_dbus_append_pair_str (&auxdata, "peer_info", strerror (dst_errno)))
949         goto oom;
950 
951       log_message (src_allow, msgtypestr, &auxdata);
952     }
953   if (dst_audit)
954     {
955       _dbus_string_set_length (&auxdata, len);
956 
957       if (source && !_dbus_append_pair_str (&auxdata, "name", source))
958         goto oom;
959 
960       if (!_dbus_append_mask (&auxdata, dst_perm))
961         goto oom;
962 
963       if (proposed_recipient &&
964           dbus_connection_get_unix_process_id (proposed_recipient, &pid) &&
965           !_dbus_append_pair_uint (&auxdata, "pid", pid))
966         goto oom;
967 
968       if (dst_label &&
969           !_dbus_append_pair_str (&auxdata, "label", dst_label))
970         goto oom;
971 
972       if (sender && dbus_connection_get_unix_process_id (sender, &pid) &&
973           !_dbus_append_pair_uint (&auxdata, "peer_pid", pid))
974         goto oom;
975 
976       if (src_con->label &&
977           !_dbus_append_pair_str (&auxdata, "peer_label", src_con->label))
978         goto oom;
979 
980       if (dst_errno && !_dbus_append_pair_str (&auxdata, "info", strerror (dst_errno)))
981         goto oom;
982 
983       if (src_errno &&
984           !_dbus_append_pair_str (&auxdata, "peer_info", strerror (src_errno)))
985         goto oom;
986 
987       log_message (dst_allow, msgtypestr, &auxdata);
988     }
989 
990  out:
991   if (src_con != NULL)
992     bus_apparmor_confinement_unref (src_con);
993   if (dst_con != NULL)
994     bus_apparmor_confinement_unref (dst_con);
995   if (free_auxdata)
996     _dbus_string_free (&auxdata);
997 
998   return src_allow && dst_allow;
999 
1000  oom:
1001   if (error != NULL && !dbus_error_is_set (error))
1002     BUS_SET_OOM (error);
1003   src_allow = FALSE;
1004   dst_allow = FALSE;
1005   goto out;
1006 
1007 #else
1008   return TRUE;
1009 #endif /* HAVE_APPARMOR */
1010 }
1011 
1012 /**
1013  * Check if Apparmor security controls allow the connection to eavesdrop on
1014  * other connections.
1015  *
1016  * @param connection the connection attempting to eavesdrop.
1017  * @param bustype name of the bus
1018  * @param error the reason for failure when FALSE is returned
1019  * @returns TRUE if eavesdropping is permitted
1020  */
1021 dbus_bool_t
bus_apparmor_allows_eavesdropping(DBusConnection * connection,const char * bustype,DBusError * error)1022 bus_apparmor_allows_eavesdropping (DBusConnection     *connection,
1023                                    const char         *bustype,
1024                                    DBusError          *error)
1025 {
1026 #ifdef HAVE_APPARMOR
1027   BusAppArmorConfinement *con = NULL;
1028   DBusString qstr, auxdata;
1029   int allow = FALSE, audit = TRUE;
1030   dbus_bool_t free_auxdata = FALSE;
1031   unsigned long pid;
1032   int res, serrno = 0;
1033 
1034   if (!apparmor_enabled)
1035     return TRUE;
1036 
1037   con = bus_connection_dup_apparmor_confinement (connection);
1038 
1039   if (is_unconfined (con->label, con->mode))
1040     {
1041       allow = TRUE;
1042       audit = FALSE;
1043       goto out;
1044     }
1045 
1046   if (!_dbus_string_init (&qstr))
1047     goto oom;
1048 
1049   if (!build_eavesdrop_query (&qstr, con->label, bustype))
1050     {
1051       _dbus_string_free (&qstr);
1052       goto oom;
1053     }
1054 
1055   res = aa_query_label (AA_DBUS_EAVESDROP,
1056                         _dbus_string_get_data (&qstr),
1057                         _dbus_string_get_length (&qstr),
1058                         &allow, &audit);
1059   _dbus_string_free (&qstr);
1060   if (res == -1)
1061     {
1062       serrno = errno;
1063       set_error_from_query_errno (error, serrno);
1064       goto audit;
1065     }
1066 
1067   /* Don't fail operations on profiles in complain mode */
1068   if (modestr_is_complain (con->mode))
1069     allow = TRUE;
1070 
1071   if (!allow)
1072     dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
1073                     "Connection \"%s\" is not allowed to eavesdrop due to "
1074                     "AppArmor policy",
1075                     bus_connection_is_active (connection) ?
1076                     bus_connection_get_name (connection) : "(inactive)");
1077 
1078   if (!audit)
1079     goto out;
1080 
1081  audit:
1082   if (!_dbus_string_init (&auxdata))
1083     goto oom;
1084   free_auxdata = TRUE;
1085 
1086   if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
1087     goto oom;
1088 
1089   if (serrno && !_dbus_append_pair_str (&auxdata, "info", strerror (serrno)))
1090     goto oom;
1091 
1092   if (!_dbus_append_pair_str (&auxdata, "mask", "eavesdrop"))
1093     goto oom;
1094 
1095   if (connection && dbus_connection_get_unix_process_id (connection, &pid) &&
1096       !_dbus_append_pair_uint (&auxdata, "pid", pid))
1097     goto oom;
1098 
1099   if (con->label && !_dbus_append_pair_str (&auxdata, "label", con->label))
1100     goto oom;
1101 
1102   log_message (allow, "eavesdrop", &auxdata);
1103 
1104  out:
1105   if (con != NULL)
1106     bus_apparmor_confinement_unref (con);
1107   if (free_auxdata)
1108     _dbus_string_free (&auxdata);
1109 
1110   return allow;
1111 
1112  oom:
1113   if (error != NULL && !dbus_error_is_set (error))
1114     BUS_SET_OOM (error);
1115   allow = FALSE;
1116   goto out;
1117 
1118 #else
1119   return TRUE;
1120 #endif /* HAVE_APPARMOR */
1121 }
1122