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