mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-02-12 05:20:37 +01:00
Merge branch 'selinux_replycheck' into 'main'
WIP: SELinux: add option to control checking of reply messages See merge request dbus/dbus!199
This commit is contained in:
commit
a446c4df14
12 changed files with 177 additions and 5 deletions
26
bus/bus.c
26
bus/bus.c
|
|
@ -60,6 +60,7 @@ struct BusContext
|
|||
char *config_file;
|
||||
char *type;
|
||||
char *servicehelper;
|
||||
char *replycheck_verb;
|
||||
char *address;
|
||||
char *pidfile;
|
||||
char *user;
|
||||
|
|
@ -571,6 +572,7 @@ process_config_every_time (BusContext *context,
|
|||
DBusList **dirs;
|
||||
char *addr;
|
||||
const char *servicehelper;
|
||||
const char *replycheck_verb;
|
||||
char *s;
|
||||
|
||||
dbus_bool_t retval;
|
||||
|
|
@ -667,6 +669,21 @@ process_config_every_time (BusContext *context,
|
|||
context->servicehelper = s;
|
||||
}
|
||||
|
||||
/* and the replycheck */
|
||||
replycheck_verb = bus_selinux_convert_replycheck_option (bus_config_parser_get_replycheck (parser));
|
||||
|
||||
s = _dbus_strdup(replycheck_verb);
|
||||
if (s == NULL && replycheck_verb != NULL)
|
||||
{
|
||||
BUS_SET_OOM (error);
|
||||
goto failed;
|
||||
}
|
||||
else
|
||||
{
|
||||
dbus_free(context->replycheck_verb);
|
||||
context->replycheck_verb = s;
|
||||
}
|
||||
|
||||
/* Create activation subsystem */
|
||||
if (context->activation)
|
||||
{
|
||||
|
|
@ -1307,6 +1324,7 @@ bus_context_unref (BusContext *context)
|
|||
dbus_free (context->address);
|
||||
dbus_free (context->user);
|
||||
dbus_free (context->servicehelper);
|
||||
dbus_free (context->replycheck_verb);
|
||||
|
||||
if (context->pidfile)
|
||||
{
|
||||
|
|
@ -1349,6 +1367,12 @@ bus_context_get_servicehelper (BusContext *context)
|
|||
return context->servicehelper;
|
||||
}
|
||||
|
||||
const char*
|
||||
bus_context_get_replycheck_verb (BusContext *context)
|
||||
{
|
||||
return context->replycheck_verb;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
bus_context_get_systemd_activation (BusContext *context)
|
||||
{
|
||||
|
|
@ -1793,6 +1817,8 @@ bus_context_check_security_policy (BusContext *context,
|
|||
* go on with the standard checks.
|
||||
*/
|
||||
if (!bus_selinux_allows_send (sender, proposed_recipient,
|
||||
requested_reply,
|
||||
bus_context_get_replycheck_verb (context),
|
||||
dbus_message_type_to_string (dbus_message_get_type (message)),
|
||||
dbus_message_get_interface (message),
|
||||
dbus_message_get_member (message),
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ dbus_bool_t bus_context_get_id (BusContext
|
|||
const char* bus_context_get_type (BusContext *context);
|
||||
const char* bus_context_get_address (BusContext *context);
|
||||
const char* bus_context_get_servicehelper (BusContext *context);
|
||||
const char* bus_context_get_replycheck_verb (BusContext *context);
|
||||
dbus_bool_t bus_context_get_systemd_activation (BusContext *context);
|
||||
BusRegistry* bus_context_get_registry (BusContext *context);
|
||||
BusConnections* bus_context_get_connections (BusContext *context);
|
||||
|
|
|
|||
|
|
@ -113,6 +113,10 @@ bus_config_parser_element_name_to_type (const char *name)
|
|||
{
|
||||
return ELEMENT_ASSOCIATE;
|
||||
}
|
||||
else if (strcmp (name, "replycheck") == 0)
|
||||
{
|
||||
return ELEMENT_REPLYCHECK;
|
||||
}
|
||||
else if (strcmp (name, "syslog") == 0)
|
||||
{
|
||||
return ELEMENT_SYSLOG;
|
||||
|
|
@ -177,6 +181,8 @@ bus_config_parser_element_type_to_name (ElementType type)
|
|||
return "selinux";
|
||||
case ELEMENT_ASSOCIATE:
|
||||
return "associate";
|
||||
case ELEMENT_REPLYCHECK:
|
||||
return "replycheck";
|
||||
case ELEMENT_SYSLOG:
|
||||
return "syslog";
|
||||
case ELEMENT_KEEP_UMASK:
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ typedef enum
|
|||
ELEMENT_CONFIGTYPE,
|
||||
ELEMENT_SELINUX,
|
||||
ELEMENT_ASSOCIATE,
|
||||
ELEMENT_REPLYCHECK,
|
||||
ELEMENT_STANDARD_SESSION_SERVICEDIRS,
|
||||
ELEMENT_STANDARD_SYSTEM_SERVICEDIRS,
|
||||
ELEMENT_KEEP_UMASK,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ struct BusConfigParser
|
|||
DBusString user; /**< User the dbus-daemon runs as */
|
||||
DBusString bus_type; /**< Message bus type */
|
||||
DBusString service_helper; /**< Location of the setuid helper */
|
||||
DBusString replycheck; /**< SELinux checking of reply messages */
|
||||
DBusList *service_dirs; /**< Directories to look for services in */
|
||||
};
|
||||
|
||||
|
|
@ -103,11 +104,15 @@ bus_config_parser_new (const DBusString *basedir,
|
|||
goto failed_type;
|
||||
if (!_dbus_string_init (&parser->service_helper))
|
||||
goto failed_helper;
|
||||
if (!_dbus_string_init (&parser->replycheck))
|
||||
goto failed_reply;
|
||||
|
||||
/* woot! */
|
||||
return parser;
|
||||
|
||||
/* argh. we have do do this carefully because of OOM */
|
||||
failed_reply:
|
||||
_dbus_string_free (&parser->service_helper);
|
||||
failed_helper:
|
||||
_dbus_string_free (&parser->bus_type);
|
||||
failed_type:
|
||||
|
|
@ -123,6 +128,7 @@ bus_config_parser_unref (BusConfigParser *parser)
|
|||
{
|
||||
_dbus_string_free (&parser->user);
|
||||
_dbus_string_free (&parser->service_helper);
|
||||
_dbus_string_free (&parser->replycheck);
|
||||
_dbus_string_free (&parser->bus_type);
|
||||
_dbus_list_clear_full (&parser->service_dirs, dbus_free);
|
||||
dbus_free (parser);
|
||||
|
|
@ -144,6 +150,7 @@ bus_config_parser_start_element (BusConfigParser *parser,
|
|||
case ELEMENT_SERVICEHELPER:
|
||||
case ELEMENT_USER:
|
||||
case ELEMENT_CONFIGTYPE:
|
||||
case ELEMENT_REPLYCHECK:
|
||||
/* content about to be handled */
|
||||
break;
|
||||
|
||||
|
|
@ -286,6 +293,28 @@ bus_config_parser_content (BusConfigParser *parser,
|
|||
}
|
||||
break;
|
||||
|
||||
case ELEMENT_REPLYCHECK:
|
||||
{
|
||||
const char* content_string;
|
||||
if (!_dbus_string_copy (&content_sane, 0, &parser->replycheck, 0))
|
||||
{
|
||||
BUS_SET_OOM (error);
|
||||
goto out_content;
|
||||
}
|
||||
|
||||
content_string = _dbus_string_get_const_data (&content_sane);
|
||||
if (strcmp(content_string, "none") != 0 &&
|
||||
strcmp(content_string, "send") != 0 &&
|
||||
strcmp(content_string, "reply_with_fallback") != 0 &&
|
||||
strcmp(content_string, "reply") != 0)
|
||||
{
|
||||
dbus_set_error (error, DBUS_ERROR_FAILED,
|
||||
"Element <replycheck> has invalid content %s", content_string);
|
||||
goto out_content;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ELEMENT_NONE:
|
||||
case ELEMENT_BUSCONFIG:
|
||||
case ELEMENT_INCLUDE:
|
||||
|
|
|
|||
|
|
@ -117,6 +117,8 @@ struct BusConfigParser
|
|||
|
||||
DBusHashTable *service_context_table; /**< Map service names to SELinux contexts */
|
||||
|
||||
char *replycheck; /**< What permission verb to use on message replies */
|
||||
|
||||
unsigned int fork : 1; /**< TRUE to fork into daemon mode */
|
||||
|
||||
unsigned int syslog : 1; /**< TRUE to enable syslog */
|
||||
|
|
@ -404,6 +406,13 @@ merge_included (BusConfigParser *parser,
|
|||
included->servicehelper = NULL;
|
||||
}
|
||||
|
||||
if (included->replycheck != NULL)
|
||||
{
|
||||
dbus_free (parser->replycheck);
|
||||
parser->replycheck = included->replycheck;
|
||||
included->replycheck = NULL;
|
||||
}
|
||||
|
||||
while ((link = _dbus_list_pop_first_link (&included->listen_on)))
|
||||
_dbus_list_append_link (&parser->listen_on, link);
|
||||
|
||||
|
|
@ -587,6 +596,7 @@ bus_config_parser_unref (BusConfigParser *parser)
|
|||
dbus_free (parser->servicehelper);
|
||||
dbus_free (parser->bus_type);
|
||||
dbus_free (parser->pidfile);
|
||||
dbus_free (parser->replycheck);
|
||||
|
||||
_dbus_list_clear_full (&parser->listen_on, dbus_free);
|
||||
_dbus_list_clear_full (&parser->service_dirs,
|
||||
|
|
@ -1997,6 +2007,19 @@ start_selinux_child (BusConfigParser *parser,
|
|||
own_copy, context_copy))
|
||||
goto oom;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (strcmp (element_name, "replycheck") == 0)
|
||||
{
|
||||
if (!check_no_attributes (parser, "replycheck", attribute_names, attribute_values, error))
|
||||
return FALSE;
|
||||
|
||||
if (push_element (parser, ELEMENT_REPLYCHECK) == NULL)
|
||||
{
|
||||
BUS_SET_OOM (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
|
|
@ -2297,6 +2320,7 @@ bus_config_parser_end_element (BusConfigParser *parser,
|
|||
case ELEMENT_SERVICEHELPER:
|
||||
case ELEMENT_INCLUDEDIR:
|
||||
case ELEMENT_LIMIT:
|
||||
case ELEMENT_REPLYCHECK:
|
||||
if (!e->had_content)
|
||||
{
|
||||
dbus_set_error (error, DBUS_ERROR_FAILED,
|
||||
|
|
@ -2890,6 +2914,20 @@ bus_config_parser_content (BusConfigParser *parser,
|
|||
e->d.limit.name);
|
||||
}
|
||||
break;
|
||||
|
||||
case ELEMENT_REPLYCHECK:
|
||||
{
|
||||
char *s;
|
||||
|
||||
e->had_content = TRUE;
|
||||
|
||||
if (!_dbus_string_copy_data (content, &s))
|
||||
goto nomem;
|
||||
|
||||
dbus_free (parser->replycheck);
|
||||
parser->replycheck = s;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
|
||||
|
|
@ -2997,6 +3035,12 @@ bus_config_parser_get_servicehelper (BusConfigParser *parser)
|
|||
return parser->servicehelper;
|
||||
}
|
||||
|
||||
const char *
|
||||
bus_config_parser_get_replycheck (BusConfigParser *parser)
|
||||
{
|
||||
return parser->replycheck;
|
||||
}
|
||||
|
||||
BusPolicy*
|
||||
bus_config_parser_steal_policy (BusConfigParser *parser)
|
||||
{
|
||||
|
|
@ -3390,6 +3434,7 @@ elements_equal (const Element *a,
|
|||
case ELEMENT_CONFIGTYPE:
|
||||
case ELEMENT_SELINUX:
|
||||
case ELEMENT_ASSOCIATE:
|
||||
case ELEMENT_REPLYCHECK:
|
||||
case ELEMENT_STANDARD_SESSION_SERVICEDIRS:
|
||||
case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS:
|
||||
case ELEMENT_KEEP_UMASK:
|
||||
|
|
@ -3520,7 +3565,7 @@ config_parsers_equal (const BusConfigParser *a,
|
|||
|
||||
if (!lists_of_service_dirs_equal (a->service_dirs, b->service_dirs))
|
||||
return FALSE;
|
||||
|
||||
|
||||
/* FIXME: compare policy */
|
||||
|
||||
/* FIXME: compare service selinux ID table */
|
||||
|
|
@ -3531,6 +3576,9 @@ config_parsers_equal (const BusConfigParser *a,
|
|||
if (!strings_equal_or_both_null (a->pidfile, b->pidfile))
|
||||
return FALSE;
|
||||
|
||||
if (!strings_equal_or_both_null (a->replycheck, b->replycheck))
|
||||
return FALSE;
|
||||
|
||||
if (! bools_equal (a->fork, b->fork))
|
||||
return FALSE;
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ dbus_bool_t bus_config_parser_get_syslog (BusConfigParser *parser);
|
|||
dbus_bool_t bus_config_parser_get_keep_umask (BusConfigParser *parser);
|
||||
const char* bus_config_parser_get_pidfile (BusConfigParser *parser);
|
||||
const char* bus_config_parser_get_servicehelper (BusConfigParser *parser);
|
||||
const char* bus_config_parser_get_replycheck (BusConfigParser *parser);
|
||||
DBusList** bus_config_parser_get_service_dirs (BusConfigParser *parser);
|
||||
DBusList** bus_config_parser_get_conf_dirs (BusConfigParser *parser);
|
||||
BusPolicy* bus_config_parser_steal_policy (BusConfigParser *parser);
|
||||
|
|
|
|||
|
|
@ -379,6 +379,7 @@ error:
|
|||
* granted from the connection to the message bus or to another
|
||||
* optionally supplied security identifier (e.g. for a service
|
||||
* context). Currently these permissions are either send_msg or
|
||||
* reply_msg (depending in the replycheck configuration) or
|
||||
* acquire_svc in the dbus class.
|
||||
*
|
||||
* @param sender_sid source security context
|
||||
|
|
@ -532,6 +533,8 @@ bus_selinux_allows_acquire_service (DBusConnection *connection,
|
|||
dbus_bool_t
|
||||
bus_selinux_allows_send (DBusConnection *sender,
|
||||
DBusConnection *proposed_recipient,
|
||||
dbus_bool_t requested_reply,
|
||||
const char *replycheck_verb,
|
||||
const char *msgtype,
|
||||
const char *interface,
|
||||
const char *member,
|
||||
|
|
@ -555,6 +558,10 @@ bus_selinux_allows_send (DBusConnection *sender,
|
|||
if (activation_entry)
|
||||
return TRUE;
|
||||
|
||||
/* Skip check on reply messages. */
|
||||
if (requested_reply && !replycheck_verb)
|
||||
return TRUE;
|
||||
|
||||
if (!sender || !dbus_connection_get_unix_process_id (sender, &spid))
|
||||
spid = 0;
|
||||
if (!proposed_recipient || !dbus_connection_get_unix_process_id (proposed_recipient, &tpid))
|
||||
|
|
@ -623,10 +630,10 @@ bus_selinux_allows_send (DBusConnection *sender,
|
|||
else
|
||||
recipient_sid = BUS_SID_FROM_SELINUX (bus_sid);
|
||||
|
||||
ret = bus_selinux_check (sender_sid,
|
||||
ret = bus_selinux_check (sender_sid,
|
||||
recipient_sid,
|
||||
"dbus",
|
||||
"send_msg",
|
||||
requested_reply ? replycheck_verb : "send_msg",
|
||||
&auxdata);
|
||||
|
||||
_dbus_string_free (&auxdata);
|
||||
|
|
@ -995,3 +1002,31 @@ bus_selinux_shutdown (void)
|
|||
}
|
||||
#endif /* HAVE_SELINUX */
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the replycheck configuraion string into the SELinux permission verb.
|
||||
*/
|
||||
const char*
|
||||
bus_selinux_convert_replycheck_option(const char *replycheck_option)
|
||||
{
|
||||
#ifdef HAVE_SELINUX
|
||||
security_class_t security_class;
|
||||
|
||||
if (replycheck_option && strcmp (replycheck_option, "none") == 0)
|
||||
return NULL;
|
||||
|
||||
if (replycheck_option && strcmp (replycheck_option, "send") == 0)
|
||||
return "send_msg";
|
||||
|
||||
if (replycheck_option && strcmp (replycheck_option, "reply") == 0)
|
||||
return "reply_msg";
|
||||
|
||||
security_class = string_to_security_class ("dbus");
|
||||
if (security_class != 0 && string_to_av_perm (security_class, "reply_msg") != 0)
|
||||
return "reply_msg";
|
||||
|
||||
return "send_msg";
|
||||
#else
|
||||
return NULL;
|
||||
#endif /* HAVE_SELINUX */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ dbus_bool_t bus_selinux_allows_acquire_service (DBusConnection *connection,
|
|||
|
||||
dbus_bool_t bus_selinux_allows_send (DBusConnection *sender,
|
||||
DBusConnection *proposed_recipient,
|
||||
dbus_bool_t requested_reply,
|
||||
const char *replycheck_verb,
|
||||
const char *msgtype, /* Supplementary audit data */
|
||||
const char *interface,
|
||||
const char *member,
|
||||
|
|
@ -68,4 +70,5 @@ dbus_bool_t bus_selinux_allows_send (DBusConnection *sender,
|
|||
BusSELinuxID* bus_selinux_init_connection_id (DBusConnection *connection,
|
||||
DBusError *error);
|
||||
|
||||
const char* bus_selinux_convert_replycheck_option(const char *replycheck_option);
|
||||
#endif /* BUS_SELINUX_H */
|
||||
|
|
|
|||
|
|
@ -59,11 +59,13 @@
|
|||
<!ELEMENT limit (#PCDATA)>
|
||||
<!ATTLIST limit name CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT selinux (associate)*>
|
||||
<!ELEMENT selinux (associate|
|
||||
replycheck)*>
|
||||
<!ELEMENT associate EMPTY>
|
||||
<!ATTLIST associate
|
||||
own CDATA #REQUIRED
|
||||
context CDATA #REQUIRED>
|
||||
<!ELEMENT replycheck (#PCDATA)>
|
||||
|
||||
<!ELEMENT apparmor EMPTY>
|
||||
<!ATTLIST apparmor
|
||||
|
|
|
|||
|
|
@ -1186,6 +1186,7 @@ More details below.</para>
|
|||
<itemizedlist remap='TP'>
|
||||
|
||||
<listitem><para><emphasis remap='I'><associate></emphasis></para></listitem>
|
||||
<listitem><para><emphasis remap='I'><replycheck></emphasis></para></listitem>
|
||||
|
||||
|
||||
</itemizedlist>
|
||||
|
|
@ -1219,6 +1220,23 @@ Right now the default will be the security context of the bus itself.</para>
|
|||
<para>If two <associate> elements specify the same name, the element
|
||||
appearing later in the configuration file will be used.</para>
|
||||
|
||||
|
||||
<para>The <replycheck> element controls how reply messages are checked.
|
||||
There are four options:</para>
|
||||
<literallayout remap='.nf'>
|
||||
"send" : the same SELinux permission as for request
|
||||
messages is used (the previous default)
|
||||
"none" : reply messages are not checked
|
||||
"reply" : reply messages are checked with a distinct
|
||||
SELinux permission
|
||||
"reply_with_fallback" : reply messages are checked with a distinct
|
||||
SELinux permission, if this permission is
|
||||
defined in the loaded SELinux policy.
|
||||
Otherwise the same permission as for request
|
||||
messages is used
|
||||
</literallayout> <!-- .fi -->
|
||||
|
||||
|
||||
<itemizedlist remap='TP'>
|
||||
|
||||
<listitem><para><emphasis remap='I'><apparmor></emphasis></para></listitem>
|
||||
|
|
@ -1457,7 +1475,8 @@ that class.</para>
|
|||
<para>First, any time a message is routed from one connection to another
|
||||
connection, the bus daemon will check permissions with the security context of
|
||||
the first connection as source, security context of the second connection
|
||||
as target, object class "dbus" and requested permission "send_msg".</para>
|
||||
as target, object class "dbus" and requested permission "send_msg" or "reply_msg",
|
||||
depending on the message type and the <replycheck> setting.</para>
|
||||
|
||||
|
||||
<para>If a security context is not available for a connection
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
context="my_selinux_context_t"/>
|
||||
<associate own="org.freedesktop.BlahBlahBlah"
|
||||
context="foo_t"/>
|
||||
<replycheck>reply_with_fallback</replycheck>
|
||||
</selinux>
|
||||
|
||||
</busconfig>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue