selinux.c revision 9a3145b9f3cb0d7d570230aaa6193f87e3bea604
1/* -*- mode: C; c-file-style: "gnu" -*- 2 * selinux.c SELinux security checks for D-Bus 3 * 4 * Author: Matthew Rickard <mjricka@epoch.ncsc.mil> 5 * 6 * Licensed under the Academic Free License version 2.1 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23#include <dbus/dbus-internals.h> 24#include <dbus/dbus-string.h> 25#include "selinux.h" 26#include "services.h" 27#include "policy.h" 28#include "utils.h" 29#include "config-parser.h" 30 31#ifdef HAVE_SELINUX 32#include <errno.h> 33#include <pthread.h> 34#include <syslog.h> 35#include <selinux/selinux.h> 36#include <selinux/avc.h> 37#include <selinux/av_permissions.h> 38#include <selinux/flask.h> 39#include <signal.h> 40#include <stdarg.h> 41#endif /* HAVE_SELINUX */ 42 43#define BUS_SID_FROM_SELINUX(sid) ((BusSELinuxID*) (sid)) 44#define SELINUX_SID_FROM_BUS(sid) ((security_id_t) (sid)) 45 46#ifdef HAVE_SELINUX 47/* Store the value telling us if SELinux is enabled in the kernel. */ 48static dbus_bool_t selinux_enabled = FALSE; 49 50/* Store an avc_entry_ref to speed AVC decisions. */ 51static struct avc_entry_ref aeref; 52 53/* Store the SID of the bus itself to use as the default. */ 54static security_id_t bus_sid = SECSID_WILD; 55 56/* Thread to listen for SELinux status changes via netlink. */ 57static pthread_t avc_notify_thread; 58 59/* Prototypes for AVC callback functions. */ 60static void log_callback (const char *fmt, ...); 61static void log_audit_callback (void *data, security_class_t class, char *buf, size_t bufleft); 62static void *avc_create_thread (void (*run) (void)); 63static void avc_stop_thread (void *thread); 64static void *avc_alloc_lock (void); 65static void avc_get_lock (void *lock); 66static void avc_release_lock (void *lock); 67static void avc_free_lock (void *lock); 68 69/* AVC callback structures for use in avc_init. */ 70static const struct avc_memory_callback mem_cb = 71{ 72 .func_malloc = dbus_malloc, 73 .func_free = dbus_free 74}; 75static const struct avc_log_callback log_cb = 76{ 77 .func_log = log_callback, 78 .func_audit = log_audit_callback 79}; 80static const struct avc_thread_callback thread_cb = 81{ 82 .func_create_thread = avc_create_thread, 83 .func_stop_thread = avc_stop_thread 84}; 85static const struct avc_lock_callback lock_cb = 86{ 87 .func_alloc_lock = avc_alloc_lock, 88 .func_get_lock = avc_get_lock, 89 .func_release_lock = avc_release_lock, 90 .func_free_lock = avc_free_lock 91}; 92#endif /* HAVE_SELINUX */ 93 94/** 95 * Log callback to log denial messages from the AVC. 96 * This is used in avc_init. Logs to both standard 97 * error and syslogd. 98 * 99 * @param fmt the format string 100 * @param variable argument list 101 */ 102#ifdef HAVE_SELINUX 103static void 104log_callback (const char *fmt, ...) 105{ 106 va_list ap; 107 va_start(ap, fmt); 108 vsyslog (LOG_INFO, fmt, ap); 109 va_end(ap); 110} 111 112/** 113 * On a policy reload we need to reparse the SELinux configuration file, since 114 * this could have changed. Send a SIGHUP to reload all configs. 115 */ 116static int 117policy_reload_callback (u_int32_t event, security_id_t ssid, 118 security_id_t tsid, security_class_t tclass, 119 access_vector_t perms, access_vector_t *out_retained) 120{ 121 if (event == AVC_CALLBACK_RESET) 122 return raise (SIGHUP); 123 124 return 0; 125} 126 127/** 128 * Log any auxiliary data 129 */ 130static void 131log_audit_callback (void *data, security_class_t class, char *buf, size_t bufleft) 132{ 133 DBusString *audmsg = data; 134 _dbus_string_copy_to_buffer (audmsg, buf, bufleft); 135} 136 137/** 138 * Create thread to notify the AVC of enforcing and policy reload 139 * changes via netlink. 140 * 141 * @param run the thread run function 142 * @return pointer to the thread 143 */ 144static void * 145avc_create_thread (void (*run) (void)) 146{ 147 int rc; 148 149 rc = pthread_create (&avc_notify_thread, NULL, (void *(*) (void *)) run, NULL); 150 if (rc != 0) 151 { 152 _dbus_warn ("Failed to start AVC thread: %s\n", _dbus_strerror (rc)); 153 exit (1); 154 } 155 return &avc_notify_thread; 156} 157 158/* Stop AVC netlink thread. */ 159static void 160avc_stop_thread (void *thread) 161{ 162 pthread_cancel (*(pthread_t *) thread); 163} 164 165/* Allocate a new AVC lock. */ 166static void * 167avc_alloc_lock (void) 168{ 169 pthread_mutex_t *avc_mutex; 170 171 avc_mutex = dbus_new (pthread_mutex_t, 1); 172 if (avc_mutex == NULL) 173 { 174 _dbus_warn ("Could not create mutex: %s\n", _dbus_strerror (errno)); 175 exit (1); 176 } 177 pthread_mutex_init (avc_mutex, NULL); 178 179 return avc_mutex; 180} 181 182/* Acquire an AVC lock. */ 183static void 184avc_get_lock (void *lock) 185{ 186 pthread_mutex_lock (lock); 187} 188 189/* Release an AVC lock. */ 190static void 191avc_release_lock (void *lock) 192{ 193 pthread_mutex_unlock (lock); 194} 195 196/* Free an AVC lock. */ 197static void 198avc_free_lock (void *lock) 199{ 200 pthread_mutex_destroy (lock); 201 dbus_free (lock); 202} 203#endif /* HAVE_SELINUX */ 204 205/** 206 * Return whether or not SELinux is enabled; must be 207 * called after bus_selinux_init. 208 */ 209dbus_bool_t 210bus_selinux_enabled (void) 211{ 212#ifdef HAVE_SELINUX 213 return selinux_enabled; 214#else 215 return FALSE; 216#endif /* HAVE_SELINUX */ 217} 218 219/** 220 * Do early initialization; determine whether SELinux is enabled. 221 */ 222dbus_bool_t 223bus_selinux_pre_init (void) 224{ 225#ifdef HAVE_SELINUX 226 int r; 227 _dbus_assert (bus_sid == SECSID_WILD); 228 229 /* Determine if we are running an SELinux kernel. */ 230 r = is_selinux_enabled (); 231 if (r < 0) 232 { 233 _dbus_warn ("Could not tell if SELinux is enabled: %s\n", 234 _dbus_strerror (errno)); 235 return FALSE; 236 } 237 238 selinux_enabled = r != 0; 239 return TRUE; 240#else 241 return TRUE; 242#endif 243} 244 245/** 246 * Initialize the user space access vector cache (AVC) for D-Bus and set up 247 * logging callbacks. 248 */ 249dbus_bool_t 250bus_selinux_full_init (void) 251{ 252#ifdef HAVE_SELINUX 253 char *bus_context; 254 255 _dbus_assert (bus_sid == SECSID_WILD); 256 257 if (!selinux_enabled) 258 { 259 _dbus_verbose ("SELinux not enabled in this kernel.\n"); 260 return TRUE; 261 } 262 263 _dbus_verbose ("SELinux is enabled in this kernel.\n"); 264 265 avc_entry_ref_init (&aeref); 266 if (avc_init ("avc", &mem_cb, &log_cb, &thread_cb, &lock_cb) < 0) 267 { 268 _dbus_warn ("Failed to start Access Vector Cache (AVC).\n"); 269 return FALSE; 270 } 271 else 272 { 273 openlog ("dbus", LOG_PERROR, LOG_USER); 274 _dbus_verbose ("Access Vector Cache (AVC) started.\n"); 275 } 276 277 if (avc_add_callback (policy_reload_callback, AVC_CALLBACK_RESET, 278 NULL, NULL, 0, 0) < 0) 279 { 280 _dbus_warn ("Failed to add policy reload callback: %s\n", 281 _dbus_strerror (errno)); 282 avc_destroy (); 283 return FALSE; 284 } 285 286 bus_context = NULL; 287 bus_sid = SECSID_WILD; 288 289 if (getcon (&bus_context) < 0) 290 { 291 _dbus_verbose ("Error getting context of bus: %s\n", 292 _dbus_strerror (errno)); 293 return FALSE; 294 } 295 296 if (avc_context_to_sid (bus_context, &bus_sid) < 0) 297 { 298 _dbus_verbose ("Error getting SID from bus context: %s\n", 299 _dbus_strerror (errno)); 300 freecon (bus_context); 301 return FALSE; 302 } 303 304 freecon (bus_context); 305 306 return TRUE; 307#else 308 return TRUE; 309#endif /* HAVE_SELINUX */ 310} 311 312/** 313 * Decrement SID reference count. 314 * 315 * @param sid the SID to decrement 316 */ 317void 318bus_selinux_id_unref (BusSELinuxID *sid) 319{ 320#ifdef HAVE_SELINUX 321 if (!selinux_enabled) 322 return; 323 324 _dbus_assert (sid != NULL); 325 326 sidput (SELINUX_SID_FROM_BUS (sid)); 327#endif /* HAVE_SELINUX */ 328} 329 330void 331bus_selinux_id_ref (BusSELinuxID *sid) 332{ 333#ifdef HAVE_SELINUX 334 if (!selinux_enabled) 335 return; 336 337 _dbus_assert (sid != NULL); 338 339 sidget (SELINUX_SID_FROM_BUS (sid)); 340#endif /* HAVE_SELINUX */ 341} 342 343/** 344 * Determine if the SELinux security policy allows the given sender 345 * security context to go to the given recipient security context. 346 * This function determines if the requested permissions are to be 347 * granted from the connection to the message bus or to another 348 * optionally supplied security identifier (e.g. for a service 349 * context). Currently these permissions are either send_msg or 350 * acquire_svc in the dbus class. 351 * 352 * @param sender_sid source security context 353 * @param override_sid is the target security context. If SECSID_WILD this will 354 * use the context of the bus itself (e.g. the default). 355 * @param target_class is the target security class. 356 * @param requested is the requested permissions. 357 * @returns #TRUE if security policy allows the send. 358 */ 359#ifdef HAVE_SELINUX 360static dbus_bool_t 361bus_selinux_check (BusSELinuxID *sender_sid, 362 BusSELinuxID *override_sid, 363 security_class_t target_class, 364 access_vector_t requested, 365 DBusString *auxdata) 366{ 367 if (!selinux_enabled) 368 return TRUE; 369 370 /* Make the security check. AVC checks enforcing mode here as well. */ 371 if (avc_has_perm (SELINUX_SID_FROM_BUS (sender_sid), 372 override_sid ? 373 SELINUX_SID_FROM_BUS (override_sid) : 374 SELINUX_SID_FROM_BUS (bus_sid), 375 target_class, requested, &aeref, auxdata) < 0) 376 { 377 _dbus_verbose ("SELinux denying due to security policy.\n"); 378 return FALSE; 379 } 380 else 381 return TRUE; 382} 383#endif /* HAVE_SELINUX */ 384 385/** 386 * Returns true if the given connection can acquire a service, 387 * assuming the given security ID is needed for that service. 388 * 389 * @param connection connection that wants to own the service 390 * @param service_sid the SID of the service from the table 391 * @returns #TRUE if acquire is permitted. 392 */ 393dbus_bool_t 394bus_selinux_allows_acquire_service (DBusConnection *connection, 395 BusSELinuxID *service_sid, 396 const char *service_name, 397 DBusError *error) 398{ 399#ifdef HAVE_SELINUX 400 BusSELinuxID *connection_sid; 401 unsigned long spid; 402 DBusString auxdata; 403 dbus_bool_t ret; 404 405 if (!selinux_enabled) 406 return TRUE; 407 408 connection_sid = bus_connection_get_selinux_id (connection); 409 if (!dbus_connection_get_unix_process_id (connection, &spid)) 410 spid = 0; 411 412 if (!_dbus_string_init (&auxdata)) 413 goto oom; 414 415 if (!_dbus_string_append (&auxdata, "service=")) 416 goto oom; 417 418 if (!_dbus_string_append (&auxdata, service_name)) 419 goto oom; 420 421 if (spid) 422 { 423 if (!_dbus_string_append (&auxdata, " spid=")) 424 goto oom; 425 426 if (!_dbus_string_append_uint (&auxdata, spid)) 427 goto oom; 428 } 429 430 ret = bus_selinux_check (connection_sid, 431 service_sid, 432 SECCLASS_DBUS, 433 DBUS__ACQUIRE_SVC, 434 &auxdata); 435 436 _dbus_string_free (&auxdata); 437 return ret; 438 439 oom: 440 _dbus_string_free (&auxdata); 441 BUS_SET_OOM (error); 442 return FALSE; 443 444#else 445 return TRUE; 446#endif /* HAVE_SELINUX */ 447} 448 449/** 450 * Check if SELinux security controls allow the message to be sent to a 451 * particular connection based on the security context of the sender and 452 * that of the receiver. The destination connection need not be the 453 * addressed recipient, it could be an "eavesdropper" 454 * 455 * @param sender the sender of the message. 456 * @param proposed_recipient the connection the message is to be sent to. 457 * @returns whether to allow the send 458 */ 459dbus_bool_t 460bus_selinux_allows_send (DBusConnection *sender, 461 DBusConnection *proposed_recipient, 462 const char *msgtype, 463 const char *interface, 464 const char *member, 465 const char *error_name, 466 const char *destination, 467 DBusError *error) 468{ 469#ifdef HAVE_SELINUX 470 BusSELinuxID *recipient_sid; 471 BusSELinuxID *sender_sid; 472 unsigned long spid, tpid; 473 DBusString auxdata; 474 dbus_bool_t ret; 475 dbus_bool_t string_alloced; 476 477 if (!selinux_enabled) 478 return TRUE; 479 480 if (!sender || !dbus_connection_get_unix_process_id (sender, &spid)) 481 spid = 0; 482 if (!proposed_recipient || !dbus_connection_get_unix_process_id (proposed_recipient, &tpid)) 483 tpid = 0; 484 485 string_alloced = FALSE; 486 if (!_dbus_string_init (&auxdata)) 487 goto oom; 488 string_alloced = TRUE; 489 490 if (!_dbus_string_append (&auxdata, "msgtype=")) 491 goto oom; 492 493 if (!_dbus_string_append (&auxdata, msgtype)) 494 goto oom; 495 496 if (interface) 497 { 498 if (!_dbus_string_append (&auxdata, " interface=")) 499 goto oom; 500 if (!_dbus_string_append (&auxdata, interface)) 501 goto oom; 502 } 503 504 if (member) 505 { 506 if (!_dbus_string_append (&auxdata, " member=")) 507 goto oom; 508 if (!_dbus_string_append (&auxdata, member)) 509 goto oom; 510 } 511 512 if (error_name) 513 { 514 if (!_dbus_string_append (&auxdata, " error_name=")) 515 goto oom; 516 if (!_dbus_string_append (&auxdata, error_name)) 517 goto oom; 518 } 519 520 if (destination) 521 { 522 if (!_dbus_string_append (&auxdata, " dest=")) 523 goto oom; 524 if (!_dbus_string_append (&auxdata, destination)) 525 goto oom; 526 } 527 528 if (spid) 529 { 530 if (!_dbus_string_append (&auxdata, " spid=")) 531 goto oom; 532 533 if (!_dbus_string_append_uint (&auxdata, spid)) 534 goto oom; 535 } 536 537 if (tpid) 538 { 539 if (!_dbus_string_append (&auxdata, " tpid=")) 540 goto oom; 541 542 if (!_dbus_string_append_uint (&auxdata, tpid)) 543 goto oom; 544 } 545 546 sender_sid = bus_connection_get_selinux_id (sender); 547 /* A NULL proposed_recipient means the bus itself. */ 548 if (proposed_recipient) 549 recipient_sid = bus_connection_get_selinux_id (proposed_recipient); 550 else 551 recipient_sid = BUS_SID_FROM_SELINUX (bus_sid); 552 553 ret = bus_selinux_check (sender_sid, 554 recipient_sid, 555 SECCLASS_DBUS, 556 DBUS__SEND_MSG, 557 &auxdata); 558 559 _dbus_string_free (&auxdata); 560 561 return ret; 562 563 oom: 564 if (string_alloced) 565 _dbus_string_free (&auxdata); 566 BUS_SET_OOM (error); 567 return FALSE; 568 569#else 570 return TRUE; 571#endif /* HAVE_SELINUX */ 572} 573 574dbus_bool_t 575bus_selinux_append_context (DBusMessage *message, 576 BusSELinuxID *sid, 577 DBusError *error) 578{ 579#ifdef HAVE_SELINUX 580 char *context; 581 582 if (avc_sid_to_context (SELINUX_SID_FROM_BUS (sid), &context) < 0) 583 { 584 if (errno == ENOMEM) 585 BUS_SET_OOM (error); 586 else 587 dbus_set_error (error, DBUS_ERROR_FAILED, 588 "Error getting context from SID: %s\n", 589 _dbus_strerror (errno)); 590 return FALSE; 591 } 592 if (!dbus_message_append_args (message, 593 DBUS_TYPE_ARRAY, 594 DBUS_TYPE_BYTE, 595 &context, 596 strlen (context), 597 DBUS_TYPE_INVALID)) 598 { 599 _DBUS_SET_OOM (error); 600 return FALSE; 601 } 602 freecon (context); 603 return TRUE; 604#else 605 return TRUE; 606#endif 607} 608 609/** 610 * Gets the security context of a connection to the bus. It is up to 611 * the caller to freecon() when they are done. 612 * 613 * @param connection the connection to get the context of. 614 * @param con the location to store the security context. 615 * @returns #TRUE if context is successfully obtained. 616 */ 617#ifdef HAVE_SELINUX 618static dbus_bool_t 619bus_connection_read_selinux_context (DBusConnection *connection, 620 char **con) 621{ 622 int fd; 623 624 if (!selinux_enabled) 625 return FALSE; 626 627 _dbus_assert (connection != NULL); 628 629 if (!dbus_connection_get_unix_fd (connection, &fd)) 630 { 631 _dbus_verbose ("Failed to get file descriptor of socket.\n"); 632 return FALSE; 633 } 634 635 if (getpeercon (fd, con) < 0) 636 { 637 _dbus_verbose ("Error getting context of socket peer: %s\n", 638 _dbus_strerror (errno)); 639 return FALSE; 640 } 641 642 _dbus_verbose ("Successfully read connection context.\n"); 643 return TRUE; 644} 645#endif /* HAVE_SELINUX */ 646 647/** 648 * Read the SELinux ID from the connection. 649 * 650 * @param connection the connection to read from 651 * @returns the SID if successfully determined, #NULL otherwise. 652 */ 653BusSELinuxID* 654bus_selinux_init_connection_id (DBusConnection *connection, 655 DBusError *error) 656{ 657#ifdef HAVE_SELINUX 658 char *con; 659 security_id_t sid; 660 661 if (!selinux_enabled) 662 return NULL; 663 664 if (!bus_connection_read_selinux_context (connection, &con)) 665 { 666 dbus_set_error (error, DBUS_ERROR_FAILED, 667 "Failed to read an SELinux context from connection"); 668 _dbus_verbose ("Error getting peer context.\n"); 669 return NULL; 670 } 671 672 _dbus_verbose ("Converting context to SID to store on connection\n"); 673 674 if (avc_context_to_sid (con, &sid) < 0) 675 { 676 if (errno == ENOMEM) 677 BUS_SET_OOM (error); 678 else 679 dbus_set_error (error, DBUS_ERROR_FAILED, 680 "Error getting SID from context \"%s\": %s\n", 681 con, _dbus_strerror (errno)); 682 683 _dbus_warn ("Error getting SID from context \"%s\": %s\n", 684 con, _dbus_strerror (errno)); 685 686 freecon (con); 687 return NULL; 688 } 689 690 freecon (con); 691 return BUS_SID_FROM_SELINUX (sid); 692#else 693 return NULL; 694#endif /* HAVE_SELINUX */ 695} 696 697 698/** 699 * Function for freeing hash table data. These SIDs 700 * should no longer be referenced. 701 */ 702static void 703bus_selinux_id_table_free_value (BusSELinuxID *sid) 704{ 705#ifdef HAVE_SELINUX 706 /* NULL sometimes due to how DBusHashTable works */ 707 if (sid) 708 bus_selinux_id_unref (sid); 709#endif /* HAVE_SELINUX */ 710} 711 712/** 713 * Creates a new table mapping service names to security ID. 714 * A security ID is a "compiled" security context, a security 715 * context is just a string. 716 * 717 * @returns the new table or #NULL if no memory 718 */ 719DBusHashTable* 720bus_selinux_id_table_new (void) 721{ 722 return _dbus_hash_table_new (DBUS_HASH_STRING, 723 (DBusFreeFunction) dbus_free, 724 (DBusFreeFunction) bus_selinux_id_table_free_value); 725} 726 727/** 728 * Hashes a service name and service context into the service SID 729 * table as a string and a SID. 730 * 731 * @param service_name is the name of the service. 732 * @param service_context is the context of the service. 733 * @param service_table is the table to hash them into. 734 * @return #FALSE if not enough memory 735 */ 736dbus_bool_t 737bus_selinux_id_table_insert (DBusHashTable *service_table, 738 const char *service_name, 739 const char *service_context) 740{ 741#ifdef HAVE_SELINUX 742 dbus_bool_t retval; 743 security_id_t sid; 744 char *key; 745 746 if (!selinux_enabled) 747 return TRUE; 748 749 sid = SECSID_WILD; 750 retval = FALSE; 751 752 key = _dbus_strdup (service_name); 753 if (key == NULL) 754 return retval; 755 756 if (avc_context_to_sid ((char *) service_context, &sid) < 0) 757 { 758 if (errno == ENOMEM) 759 { 760 dbus_free (key); 761 return FALSE; 762 } 763 764 _dbus_warn ("Error getting SID from context \"%s\": %s\n", 765 (char *) service_context, 766 _dbus_strerror (errno)); 767 goto out; 768 } 769 770 if (!_dbus_hash_table_insert_string (service_table, 771 key, 772 BUS_SID_FROM_SELINUX (sid))) 773 goto out; 774 775 _dbus_verbose ("Parsed \tservice: %s \n\t\tcontext: %s\n", 776 key, 777 sid->ctx); 778 779 /* These are owned by the hash, so clear them to avoid unref */ 780 key = NULL; 781 sid = SECSID_WILD; 782 783 retval = TRUE; 784 785 out: 786 if (sid != SECSID_WILD) 787 sidput (sid); 788 789 if (key) 790 dbus_free (key); 791 792 return retval; 793#else 794 return TRUE; 795#endif /* HAVE_SELINUX */ 796} 797 798 799/** 800 * Find the security identifier associated with a particular service 801 * name. Return a pointer to this SID, or #NULL/SECSID_WILD if the 802 * service is not found in the hash table. This should be nearly a 803 * constant time operation. If SELinux support is not available, 804 * always return NULL. 805 * 806 * @param service_table the hash table to check for service name. 807 * @param service_name the name of the service to look for. 808 * @returns the SELinux ID associated with the service 809 */ 810BusSELinuxID* 811bus_selinux_id_table_lookup (DBusHashTable *service_table, 812 const DBusString *service_name) 813{ 814#ifdef HAVE_SELINUX 815 security_id_t sid; 816 817 sid = SECSID_WILD; /* default context */ 818 819 if (!selinux_enabled) 820 return NULL; 821 822 _dbus_verbose ("Looking up service SID for %s\n", 823 _dbus_string_get_const_data (service_name)); 824 825 sid = _dbus_hash_table_lookup_string (service_table, 826 _dbus_string_get_const_data (service_name)); 827 828 if (sid == SECSID_WILD) 829 _dbus_verbose ("Service %s not found\n", 830 _dbus_string_get_const_data (service_name)); 831 else 832 _dbus_verbose ("Service %s found\n", 833 _dbus_string_get_const_data (service_name)); 834 835 return BUS_SID_FROM_SELINUX (sid); 836#endif /* HAVE_SELINUX */ 837 return NULL; 838} 839 840/** 841 * Get the SELinux policy root. This is used to find the D-Bus 842 * specific config file within the policy. 843 */ 844const char * 845bus_selinux_get_policy_root (void) 846{ 847#ifdef HAVE_SELINUX 848 return selinux_policy_root (); 849#else 850 return NULL; 851#endif /* HAVE_SELINUX */ 852} 853 854/** 855 * For debugging: Print out the current hash table of service SIDs. 856 */ 857void 858bus_selinux_id_table_print (DBusHashTable *service_table) 859{ 860#ifdef DBUS_ENABLE_VERBOSE_MODE 861#ifdef HAVE_SELINUX 862 DBusHashIter iter; 863 864 if (!selinux_enabled) 865 return; 866 867 _dbus_verbose ("Service SID Table:\n"); 868 _dbus_hash_iter_init (service_table, &iter); 869 while (_dbus_hash_iter_next (&iter)) 870 { 871 const char *key = _dbus_hash_iter_get_string_key (&iter); 872 security_id_t sid = _dbus_hash_iter_get_value (&iter); 873 _dbus_verbose ("The key is %s\n", key); 874 _dbus_verbose ("The context is %s\n", sid->ctx); 875 _dbus_verbose ("The refcount is %d\n", sid->refcnt); 876 } 877#endif /* HAVE_SELINUX */ 878#endif /* DBUS_ENABLE_VERBOSE_MODE */ 879} 880 881 882#ifdef DBUS_ENABLE_VERBOSE_MODE 883#ifdef HAVE_SELINUX 884/** 885 * Print out some AVC statistics. 886 */ 887static void 888bus_avc_print_stats (void) 889{ 890 struct avc_cache_stats cstats; 891 892 if (!selinux_enabled) 893 return; 894 895 _dbus_verbose ("AVC Statistics:\n"); 896 avc_cache_stats (&cstats); 897 avc_av_stats (); 898 _dbus_verbose ("AVC Cache Statistics:\n"); 899 _dbus_verbose ("Entry lookups: %d\n", cstats.entry_lookups); 900 _dbus_verbose ("Entry hits: %d\n", cstats.entry_hits); 901 _dbus_verbose ("Entry misses %d\n", cstats.entry_misses); 902 _dbus_verbose ("Entry discards: %d\n", cstats.entry_discards); 903 _dbus_verbose ("CAV lookups: %d\n", cstats.cav_lookups); 904 _dbus_verbose ("CAV hits: %d\n", cstats.cav_hits); 905 _dbus_verbose ("CAV probes: %d\n", cstats.cav_probes); 906 _dbus_verbose ("CAV misses: %d\n", cstats.cav_misses); 907} 908#endif /* HAVE_SELINUX */ 909#endif /* DBUS_ENABLE_VERBOSE_MODE */ 910 911 912/** 913 * Destroy the AVC before we terminate. 914 */ 915void 916bus_selinux_shutdown (void) 917{ 918#ifdef HAVE_SELINUX 919 if (!selinux_enabled) 920 return; 921 922 _dbus_verbose ("AVC shutdown\n"); 923 924 if (bus_sid != SECSID_WILD) 925 { 926 sidput (bus_sid); 927 bus_sid = SECSID_WILD; 928 929#ifdef DBUS_ENABLE_VERBOSE_MODE 930 bus_avc_print_stats (); 931#endif /* DBUS_ENABLE_VERBOSE_MODE */ 932 933 avc_destroy (); 934 } 935#endif /* HAVE_SELINUX */ 936} 937 938