selinux.c revision 44656f538f69e8f8709ddb6ab285db29f65f62dd
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 476 if (!selinux_enabled) 477 return TRUE; 478 479 if (!sender || !dbus_connection_get_unix_process_id (sender, &spid)) 480 spid = 0; 481 if (!proposed_recipient || !dbus_connection_get_unix_process_id (proposed_recipient, &tpid)) 482 tpid = 0; 483 484 if (!_dbus_string_init (&auxdata)) 485 goto oom; 486 487 if (!_dbus_string_append (&auxdata, "msgtype=")) 488 goto oom; 489 490 if (!_dbus_string_append (&auxdata, msgtype)) 491 goto oom; 492 493 if (interface) 494 { 495 if (!_dbus_string_append (&auxdata, " interface=")) 496 goto oom; 497 if (!_dbus_string_append (&auxdata, interface)) 498 goto oom; 499 } 500 501 if (member) 502 { 503 if (!_dbus_string_append (&auxdata, " member=")) 504 goto oom; 505 if (!_dbus_string_append (&auxdata, member)) 506 goto oom; 507 } 508 509 if (error_name) 510 { 511 if (!_dbus_string_append (&auxdata, " error_name=")) 512 goto oom; 513 if (!_dbus_string_append (&auxdata, error_name)) 514 goto oom; 515 } 516 517 if (destination) 518 { 519 if (!_dbus_string_append (&auxdata, " dest=")) 520 goto oom; 521 if (!_dbus_string_append (&auxdata, destination)) 522 goto oom; 523 } 524 525 if (spid) 526 { 527 if (!_dbus_string_append (&auxdata, " spid=")) 528 goto oom; 529 530 if (!_dbus_string_append_uint (&auxdata, spid)) 531 goto oom; 532 } 533 534 if (tpid) 535 { 536 if (!_dbus_string_append (&auxdata, " tpid=")) 537 goto oom; 538 539 if (!_dbus_string_append_uint (&auxdata, tpid)) 540 goto oom; 541 } 542 543 sender_sid = bus_connection_get_selinux_id (sender); 544 /* A NULL proposed_recipient means the bus itself. */ 545 if (proposed_recipient) 546 recipient_sid = bus_connection_get_selinux_id (proposed_recipient); 547 else 548 recipient_sid = BUS_SID_FROM_SELINUX (bus_sid); 549 550 ret = bus_selinux_check (sender_sid, 551 recipient_sid, 552 SECCLASS_DBUS, 553 DBUS__SEND_MSG, 554 &auxdata); 555 556 _dbus_string_free (&auxdata); 557 558 return ret; 559 560 oom: 561 _dbus_string_free (&auxdata); 562 BUS_SET_OOM (error); 563 return FALSE; 564 565#else 566 return TRUE; 567#endif /* HAVE_SELINUX */ 568} 569 570/** 571 * Gets the security context of a connection to the bus. It is up to 572 * the caller to freecon() when they are done. 573 * 574 * @param connection the connection to get the context of. 575 * @param con the location to store the security context. 576 * @returns #TRUE if context is successfully obtained. 577 */ 578#ifdef HAVE_SELINUX 579static dbus_bool_t 580bus_connection_read_selinux_context (DBusConnection *connection, 581 char **con) 582{ 583 int fd; 584 585 if (!selinux_enabled) 586 return FALSE; 587 588 _dbus_assert (connection != NULL); 589 590 if (!dbus_connection_get_unix_fd (connection, &fd)) 591 { 592 _dbus_verbose ("Failed to get file descriptor of socket.\n"); 593 return FALSE; 594 } 595 596 if (getpeercon (fd, con) < 0) 597 { 598 _dbus_verbose ("Error getting context of socket peer: %s\n", 599 _dbus_strerror (errno)); 600 return FALSE; 601 } 602 603 _dbus_verbose ("Successfully read connection context.\n"); 604 return TRUE; 605} 606#endif /* HAVE_SELINUX */ 607 608/** 609 * Read the SELinux ID from the connection. 610 * 611 * @param connection the connection to read from 612 * @returns the SID if successfully determined, #NULL otherwise. 613 */ 614BusSELinuxID* 615bus_selinux_init_connection_id (DBusConnection *connection, 616 DBusError *error) 617{ 618#ifdef HAVE_SELINUX 619 char *con; 620 security_id_t sid; 621 622 if (!selinux_enabled) 623 return NULL; 624 625 if (!bus_connection_read_selinux_context (connection, &con)) 626 { 627 dbus_set_error (error, DBUS_ERROR_FAILED, 628 "Failed to read an SELinux context from connection"); 629 _dbus_verbose ("Error getting peer context.\n"); 630 return NULL; 631 } 632 633 _dbus_verbose ("Converting context to SID to store on connection\n"); 634 635 if (avc_context_to_sid (con, &sid) < 0) 636 { 637 if (errno == ENOMEM) 638 BUS_SET_OOM (error); 639 else 640 dbus_set_error (error, DBUS_ERROR_FAILED, 641 "Error getting SID from context \"%s\": %s\n", 642 con, _dbus_strerror (errno)); 643 644 _dbus_warn ("Error getting SID from context \"%s\": %s\n", 645 con, _dbus_strerror (errno)); 646 647 freecon (con); 648 return NULL; 649 } 650 651 freecon (con); 652 return BUS_SID_FROM_SELINUX (sid); 653#else 654 return NULL; 655#endif /* HAVE_SELINUX */ 656} 657 658 659/** 660 * Function for freeing hash table data. These SIDs 661 * should no longer be referenced. 662 */ 663static void 664bus_selinux_id_table_free_value (BusSELinuxID *sid) 665{ 666#ifdef HAVE_SELINUX 667 /* NULL sometimes due to how DBusHashTable works */ 668 if (sid) 669 bus_selinux_id_unref (sid); 670#endif /* HAVE_SELINUX */ 671} 672 673/** 674 * Creates a new table mapping service names to security ID. 675 * A security ID is a "compiled" security context, a security 676 * context is just a string. 677 * 678 * @returns the new table or #NULL if no memory 679 */ 680DBusHashTable* 681bus_selinux_id_table_new (void) 682{ 683 return _dbus_hash_table_new (DBUS_HASH_STRING, 684 (DBusFreeFunction) dbus_free, 685 (DBusFreeFunction) bus_selinux_id_table_free_value); 686} 687 688/** 689 * Hashes a service name and service context into the service SID 690 * table as a string and a SID. 691 * 692 * @param service_name is the name of the service. 693 * @param service_context is the context of the service. 694 * @param service_table is the table to hash them into. 695 * @return #FALSE if not enough memory 696 */ 697dbus_bool_t 698bus_selinux_id_table_insert (DBusHashTable *service_table, 699 const char *service_name, 700 const char *service_context) 701{ 702#ifdef HAVE_SELINUX 703 dbus_bool_t retval; 704 security_id_t sid; 705 char *key; 706 707 if (!selinux_enabled) 708 return TRUE; 709 710 sid = SECSID_WILD; 711 retval = FALSE; 712 713 key = _dbus_strdup (service_name); 714 if (key == NULL) 715 return retval; 716 717 if (avc_context_to_sid ((char *) service_context, &sid) < 0) 718 { 719 if (errno == ENOMEM) 720 return FALSE; 721 _dbus_warn ("Error getting SID from context \"%s\": %s\n", 722 (char *) service_context, 723 _dbus_strerror (errno)); 724 goto out; 725 } 726 727 if (!_dbus_hash_table_insert_string (service_table, 728 key, 729 BUS_SID_FROM_SELINUX (sid))) 730 goto out; 731 732 _dbus_verbose ("Parsed \tservice: %s \n\t\tcontext: %s\n", 733 key, 734 sid->ctx); 735 736 /* These are owned by the hash, so clear them to avoid unref */ 737 key = NULL; 738 sid = SECSID_WILD; 739 740 retval = TRUE; 741 742 out: 743 if (sid != SECSID_WILD) 744 sidput (sid); 745 746 if (key) 747 dbus_free (key); 748 749 return retval; 750#else 751 return TRUE; 752#endif /* HAVE_SELINUX */ 753} 754 755 756/** 757 * Find the security identifier associated with a particular service 758 * name. Return a pointer to this SID, or #NULL/SECSID_WILD if the 759 * service is not found in the hash table. This should be nearly a 760 * constant time operation. If SELinux support is not available, 761 * always return NULL. 762 * 763 * @param service_table the hash table to check for service name. 764 * @param service_name the name of the service to look for. 765 * @returns the SELinux ID associated with the service 766 */ 767BusSELinuxID* 768bus_selinux_id_table_lookup (DBusHashTable *service_table, 769 const DBusString *service_name) 770{ 771#ifdef HAVE_SELINUX 772 security_id_t sid; 773 774 sid = SECSID_WILD; /* default context */ 775 776 if (!selinux_enabled) 777 return NULL; 778 779 _dbus_verbose ("Looking up service SID for %s\n", 780 _dbus_string_get_const_data (service_name)); 781 782 sid = _dbus_hash_table_lookup_string (service_table, 783 _dbus_string_get_const_data (service_name)); 784 785 if (sid == SECSID_WILD) 786 _dbus_verbose ("Service %s not found\n", 787 _dbus_string_get_const_data (service_name)); 788 else 789 _dbus_verbose ("Service %s found\n", 790 _dbus_string_get_const_data (service_name)); 791 792 return BUS_SID_FROM_SELINUX (sid); 793#endif /* HAVE_SELINUX */ 794 return NULL; 795} 796 797/** 798 * Get the SELinux policy root. This is used to find the D-BUS 799 * specific config file within the policy. 800 */ 801const char * 802bus_selinux_get_policy_root (void) 803{ 804#ifdef HAVE_SELINUX 805 return selinux_policy_root (); 806#else 807 return NULL; 808#endif /* HAVE_SELINUX */ 809} 810 811/** 812 * For debugging: Print out the current hash table of service SIDs. 813 */ 814void 815bus_selinux_id_table_print (DBusHashTable *service_table) 816{ 817#ifdef DBUS_ENABLE_VERBOSE_MODE 818#ifdef HAVE_SELINUX 819 DBusHashIter iter; 820 821 if (!selinux_enabled) 822 return; 823 824 _dbus_verbose ("Service SID Table:\n"); 825 _dbus_hash_iter_init (service_table, &iter); 826 while (_dbus_hash_iter_next (&iter)) 827 { 828 const char *key = _dbus_hash_iter_get_string_key (&iter); 829 security_id_t sid = _dbus_hash_iter_get_value (&iter); 830 _dbus_verbose ("The key is %s\n", key); 831 _dbus_verbose ("The context is %s\n", sid->ctx); 832 _dbus_verbose ("The refcount is %d\n", sid->refcnt); 833 } 834#endif /* HAVE_SELINUX */ 835#endif /* DBUS_ENABLE_VERBOSE_MODE */ 836} 837 838 839#ifdef DBUS_ENABLE_VERBOSE_MODE 840#ifdef HAVE_SELINUX 841/** 842 * Print out some AVC statistics. 843 */ 844static void 845bus_avc_print_stats (void) 846{ 847 struct avc_cache_stats cstats; 848 849 if (!selinux_enabled) 850 return; 851 852 _dbus_verbose ("AVC Statistics:\n"); 853 avc_cache_stats (&cstats); 854 avc_av_stats (); 855 _dbus_verbose ("AVC Cache Statistics:\n"); 856 _dbus_verbose ("Entry lookups: %d\n", cstats.entry_lookups); 857 _dbus_verbose ("Entry hits: %d\n", cstats.entry_hits); 858 _dbus_verbose ("Entry misses %d\n", cstats.entry_misses); 859 _dbus_verbose ("Entry discards: %d\n", cstats.entry_discards); 860 _dbus_verbose ("CAV lookups: %d\n", cstats.cav_lookups); 861 _dbus_verbose ("CAV hits: %d\n", cstats.cav_hits); 862 _dbus_verbose ("CAV probes: %d\n", cstats.cav_probes); 863 _dbus_verbose ("CAV misses: %d\n", cstats.cav_misses); 864} 865#endif /* HAVE_SELINUX */ 866#endif /* DBUS_ENABLE_VERBOSE_MODE */ 867 868 869/** 870 * Destroy the AVC before we terminate. 871 */ 872void 873bus_selinux_shutdown (void) 874{ 875#ifdef HAVE_SELINUX 876 if (!selinux_enabled) 877 return; 878 879 sidput (bus_sid); 880 bus_sid = SECSID_WILD; 881 882#ifdef DBUS_ENABLE_VERBOSE_MODE 883 bus_avc_print_stats (); 884#endif /* DBUS_ENABLE_VERBOSE_MODE */ 885 886 avc_destroy (); 887#endif /* HAVE_SELINUX */ 888} 889 890