(linenum→info "unix/slp.c:2238")

dbus/1.0.2/bus/selinux.c

    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. */
   48: static dbus_bool_t selinux_enabled = FALSE;
   49: 
   50: /* Store an avc_entry_ref to speed AVC decisions. */
   51: static struct avc_entry_ref aeref;
   52: 
   53: /* Store the SID of the bus itself to use as the default. */
   54: static security_id_t bus_sid = SECSID_WILD;
   55: 
   56: /* Thread to listen for SELinux status changes via netlink. */
   57: static pthread_t avc_notify_thread;
   58: 
   59: /* Prototypes for AVC callback functions.  */
   60: static void log_callback (const char *fmt, ...);
   61: static void log_audit_callback (void *data, security_class_t class, char *buf, size_t bufleft);
   62: static void *avc_create_thread (void (*run) (void));
   63: static void avc_stop_thread (void *thread);
   64: static void *avc_alloc_lock (void);
   65: static void avc_get_lock (void *lock);
   66: static void avc_release_lock (void *lock);
   67: static void avc_free_lock (void *lock);
   68: 
   69: /* AVC callback structures for use in avc_init.  */
   70: static const struct avc_memory_callback mem_cb =
   71: {
   72:   .func_malloc = dbus_malloc,
   73:   .func_free = dbus_free
   74: };
   75: static const struct avc_log_callback log_cb =
   76: {
   77:   .func_log = log_callback,
   78:   .func_audit = log_audit_callback
   79: };
   80: static const struct avc_thread_callback thread_cb =
   81: {
   82:   .func_create_thread = avc_create_thread,
   83:   .func_stop_thread = avc_stop_thread
   84: };
   85: static 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
  103: static void 
  104: log_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:  */
  116: static int
  117: policy_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:  */
  130: static void
  131: log_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:  */
  144: static void *
  145: avc_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.  */
  159: static void
  160: avc_stop_thread (void *thread)
  161: {
  162:   pthread_cancel (*(pthread_t *) thread);
  163: }
  164: 
  165: /* Allocate a new AVC lock.  */
  166: static void *
  167: avc_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.  */
  183: static void
  184: avc_get_lock (void *lock)
  185: {
  186:   pthread_mutex_lock (lock);
  187: }
  188: 
  189: /* Release an AVC lock.  */
  190: static void
  191: avc_release_lock (void *lock)
  192: {
  193:   pthread_mutex_unlock (lock);
  194: }
  195: 
  196: /* Free an AVC lock.  */
  197: static void
  198: avc_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:  */
  209: dbus_bool_t
  210: bus_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:  */
  222: dbus_bool_t
  223: bus_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:  */
  249: dbus_bool_t
  250: bus_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:  */
  317: void
  318: bus_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: 
  330: void
  331: bus_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
  360: static dbus_bool_t
  361: bus_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:  */
  393: dbus_bool_t
  394: bus_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:  */
  459: dbus_bool_t
  460: bus_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: 
  574: dbus_bool_t
  575: bus_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
  618: static dbus_bool_t
  619: bus_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:     }