Merge branch 'containers-minimum-101354'

Add experimental support for creating extra servers at runtime, to
be used by app containers like Flatpak or Snap. This API is still
subject to change and is not compiled in by default.

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=101354
This commit is contained in:
Simon McVittie 2017-12-12 17:41:19 +00:00
commit 065e2249ac
30 changed files with 4013 additions and 32 deletions

8
NEWS
View file

@ -8,6 +8,11 @@ a 1.14.0 stable release at an unspecified point in the future.
Enhancements:
• Add experimental support for creating extra servers at runtime, to
be used by app containers like Flatpak or Snap. This API is still
subject to change and is not compiled in by default.
(fd.o #101354, Simon McVittie)
• Improve automated test logging (fd.o #103601, Simon McVittie)
Fixes:
@ -32,9 +37,6 @@ Fixes:
Internal changes:
• Preparations for future support for restricted sockets used by
app containers like Flatpak (fd.o #101354, Simon McVittie)
• Harden the nonce-tcp: transport against resource leaks and
use-after-free (fd.o #103597, Simon McVittie)

View file

@ -117,6 +117,9 @@ DBUS_ENABLE_DOXYGEN_DOCS:BOOL=OFF
// enable bus daemon usage statistics
DBUS_ENABLE_STATS:BOOL=OFF
// enable restricted servers for app containers
DBUS_ENABLE_CONTAINERS:BOOL=OFF
// support verbose debug mode
DBUS_ENABLE_VERBOSE_MODE:BOOL=ON

View file

@ -29,6 +29,7 @@ AM_CPPFLAGS = \
$(EXPAT_CFLAGS) \
$(APPARMOR_CFLAGS) \
-DDBUS_SYSTEM_CONFIG_FILE=\""$(dbusdatadir)/system.conf"\" \
-DDBUS_RUNSTATEDIR=\""$(runstatedir)"\" \
-DDBUS_COMPILATION \
$(NULL)
@ -97,6 +98,8 @@ BUS_SOURCES= \
config-parser-common.h \
connection.c \
connection.h \
containers.c \
containers.h \
desktop-file.c \
desktop-file.h \
$(DIR_WATCH_SOURCE) \

View file

@ -29,6 +29,7 @@
#include "activation.h"
#include "connection.h"
#include "containers.h"
#include "services.h"
#include "utils.h"
#include "policy.h"
@ -69,6 +70,7 @@ struct BusContext
BusMatchmaker *matchmaker;
BusLimits limits;
DBusRLimit *initial_fd_limit;
BusContainers *containers;
unsigned int fork : 1;
unsigned int syslog : 1;
unsigned int keep_umask : 1;
@ -100,7 +102,8 @@ server_get_context (DBusServer *server)
bd = BUS_SERVER_DATA (server);
/* every DBusServer in the dbus-daemon has gone through setup_server() */
/* every DBusServer in the dbus-daemon's main loop has gone through
* bus_context_setup_server() */
_dbus_assert (bd != NULL);
context = bd->context;
@ -173,8 +176,14 @@ new_connection_callback (DBusServer *server,
DBusConnection *new_connection,
void *data)
{
BusContext *context = data;
/* If this fails it logs a warning, so we don't need to do that */
bus_context_add_incoming_connection (data, new_connection);
}
dbus_bool_t
bus_context_add_incoming_connection (BusContext *context,
DBusConnection *new_connection)
{
/* If this fails it logs a warning, so we don't need to do that */
if (!bus_connections_setup_connection (context->connections, new_connection))
{
@ -184,6 +193,8 @@ new_connection_callback (DBusServer *server,
* in general.
*/
dbus_connection_close (new_connection);
/* on OOM, we won't have ref'd the connection so it will die. */
return FALSE;
}
dbus_connection_set_max_received_size (new_connection,
@ -201,7 +212,7 @@ new_connection_callback (DBusServer *server,
dbus_connection_set_allow_anonymous (new_connection,
context->allow_anonymous);
/* on OOM, we won't have ref'd the connection so it will die. */
return TRUE;
}
static void
@ -217,6 +228,25 @@ setup_server (BusContext *context,
DBusServer *server,
char **auth_mechanisms,
DBusError *error)
{
if (!bus_context_setup_server (context, server, error))
return FALSE;
if (!dbus_server_set_auth_mechanisms (server, (const char**) auth_mechanisms))
{
BUS_SET_OOM (error);
return FALSE;
}
dbus_server_set_new_connection_function (server, new_connection_callback,
context, NULL);
return TRUE;
}
dbus_bool_t
bus_context_setup_server (BusContext *context,
DBusServer *server,
DBusError *error)
{
BusServerData *bd;
@ -232,16 +262,6 @@ setup_server (BusContext *context,
bd->context = context;
if (!dbus_server_set_auth_mechanisms (server, (const char**) auth_mechanisms))
{
BUS_SET_OOM (error);
return FALSE;
}
dbus_server_set_new_connection_function (server,
new_connection_callback,
context, NULL);
if (!dbus_server_set_watch_functions (server,
add_server_watch,
remove_server_watch,
@ -887,6 +907,14 @@ bus_context_new (const DBusString *config_file,
goto failed;
}
context->containers = bus_containers_new ();
if (context->containers == NULL)
{
BUS_SET_OOM (error);
goto failed;
}
/* check user before we fork */
if (context->user != NULL)
{
@ -1102,6 +1130,9 @@ bus_context_shutdown (BusContext *context)
link = _dbus_list_get_next_link (&context->servers, link);
}
if (context->containers != NULL)
bus_containers_stop_listening (context->containers);
}
BusContext *
@ -1172,6 +1203,7 @@ bus_context_unref (BusContext *context)
context->matchmaker = NULL;
}
bus_clear_containers (&context->containers);
dbus_free (context->config_file);
dbus_free (context->log_prefix);
dbus_free (context->type);
@ -1282,6 +1314,12 @@ bus_context_get_policy (BusContext *context)
return context->policy;
}
BusContainers *
bus_context_get_containers (BusContext *context)
{
return context->containers;
}
BusClientPolicy*
bus_context_create_client_policy (BusContext *context,
DBusConnection *connection,
@ -1359,6 +1397,26 @@ bus_context_get_reply_timeout (BusContext *context)
return context->limits.reply_timeout;
}
int bus_context_get_max_containers (BusContext *context)
{
return context->limits.max_containers;
}
int bus_context_get_max_containers_per_user (BusContext *context)
{
return context->limits.max_containers_per_user;
}
int bus_context_get_max_container_metadata_bytes (BusContext *context)
{
return context->limits.max_container_metadata_bytes;
}
int bus_context_get_max_connections_per_container (BusContext *context)
{
return context->limits.max_connections_per_container;
}
DBusRLimit *
bus_context_get_initial_fd_limit (BusContext *context)
{

View file

@ -45,6 +45,7 @@ typedef struct BusTransaction BusTransaction;
typedef struct BusMatchmaker BusMatchmaker;
typedef struct BusMatchRule BusMatchRule;
typedef struct BusActivationEntry BusActivationEntry;
typedef struct BusContainers BusContainers;
typedef struct
{
@ -65,6 +66,10 @@ typedef struct
int max_match_rules_per_connection; /**< Max number of match rules for a single connection */
int max_replies_per_connection; /**< Max number of replies that can be pending for each connection */
int reply_timeout; /**< How long to wait before timing out a reply */
int max_containers; /**< Max number of restricted servers for app-containers */
int max_containers_per_user; /**< Max number of restricted servers for app-containers, per user */
int max_connections_per_container; /**< Max number of connections per restricted server */
int max_container_metadata_bytes; /**< Max number of bytes of metadata per restricted server */
} BusLimits;
typedef enum
@ -106,6 +111,7 @@ dbus_bool_t bus_context_allow_unix_user (BusContext
dbus_bool_t bus_context_allow_windows_user (BusContext *context,
const char *windows_sid);
BusPolicy* bus_context_get_policy (BusContext *context);
BusContainers *bus_context_get_containers (BusContext *context);
BusClientPolicy* bus_context_create_client_policy (BusContext *context,
DBusConnection *connection,
@ -121,6 +127,10 @@ int bus_context_get_max_services_per_connection (BusContext
int bus_context_get_max_match_rules_per_connection (BusContext *context);
int bus_context_get_max_replies_per_connection (BusContext *context);
int bus_context_get_reply_timeout (BusContext *context);
int bus_context_get_max_containers (BusContext *context);
int bus_context_get_max_containers_per_user (BusContext *context);
int bus_context_get_max_container_metadata_bytes (BusContext *context);
int bus_context_get_max_connections_per_container (BusContext *context);
DBusRLimit * bus_context_get_initial_fd_limit (BusContext *context);
dbus_bool_t bus_context_get_using_syslog (BusContext *context);
void bus_context_log (BusContext *context,
@ -145,6 +155,11 @@ dbus_bool_t bus_context_check_security_policy (BusContext
BusActivationEntry *activation_entry,
DBusError *error);
void bus_context_check_all_watches (BusContext *context);
dbus_bool_t bus_context_setup_server (BusContext *context,
DBusServer *server,
DBusError *error);
dbus_bool_t bus_context_add_incoming_connection (BusContext *context,
DBusConnection *new_connection);
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
void bus_context_quiet_log_begin (BusContext *context);

View file

@ -481,7 +481,10 @@ bus_config_parser_new (const DBusString *basedir,
else
{
/* Make up some numbers! woot! */
/* Make up some numbers! woot!
* Please keep these hard-coded values in sync with the comments
* in bus/system.conf.in. */
parser->limits.max_incoming_bytes = _DBUS_ONE_MEGABYTE * 127;
parser->limits.max_outgoing_bytes = _DBUS_ONE_MEGABYTE * 127;
parser->limits.max_message_size = _DBUS_ONE_MEGABYTE * 32;
@ -514,12 +517,21 @@ bus_config_parser_new (const DBusString *basedir,
parser->limits.max_incomplete_connections = 64;
parser->limits.max_connections_per_user = 256;
parser->limits.max_containers_per_user = 16;
/* Note that max_completed_connections / max_connections_per_user
* is the number of users that would have to work together to
* DOS all the other users.
* DOS all the other users. The same applies to containers.
*/
parser->limits.max_completed_connections = 2048;
parser->limits.max_containers = 512;
/* Similarly max_connections_per_user / max_connections_per_container
* is the number of app-containers per user that would have to work
* together to DoS all the other processes of that user */
parser->limits.max_connections_per_container = 8;
/* Someone trying to do a denial of service attack can make us store
* this much data per app-container */
parser->limits.max_container_metadata_bytes = 4096;
parser->limits.max_pending_activations = 512;
parser->limits.max_services_per_connection = 512;
@ -2177,6 +2189,30 @@ set_limit (BusConfigParser *parser,
must_be_int = TRUE;
parser->limits.max_replies_per_connection = value;
}
else if (strcmp (name, "max_containers") == 0)
{
must_be_positive = TRUE;
must_be_int = TRUE;
parser->limits.max_containers = value;
}
else if (strcmp (name, "max_containers_per_user") == 0)
{
must_be_positive = TRUE;
must_be_int = TRUE;
parser->limits.max_containers_per_user = value;
}
else if (strcmp (name, "max_container_metadata_bytes") == 0)
{
must_be_positive = TRUE;
must_be_int = TRUE;
parser->limits.max_container_metadata_bytes = value;
}
else if (strcmp (name, "max_connections_per_container") == 0)
{
must_be_positive = TRUE;
must_be_int = TRUE;
parser->limits.max_connections_per_container = value;
}
else
{
dbus_set_error (error, DBUS_ERROR_FAILED,

View file

@ -23,6 +23,8 @@
#include <config.h>
#include "connection.h"
#include "containers.h"
#include "dispatch.h"
#include "policy.h"
#include "services.h"
@ -306,6 +308,9 @@ bus_connection_disconnected (DBusConnection *connection)
d->link_in_monitors = NULL;
}
bus_containers_remove_connection (bus_context_get_containers (d->connections->context),
connection);
if (d->link_in_connection_list != NULL)
{
if (d->name != NULL)
@ -583,6 +588,9 @@ cache_peer_loginfo_string (BusConnectionData *d,
unsigned long pid;
char *windows_sid = NULL, *security_label = NULL;
dbus_bool_t prev_added;
const char *container = NULL;
const char *container_type = NULL;
const char *container_name = NULL;
if (!_dbus_string_init (&loginfo_buf))
return FALSE;
@ -654,6 +662,29 @@ cache_peer_loginfo_string (BusConnectionData *d,
prev_added = TRUE;
}
if (bus_containers_connection_is_contained (connection, &container,
&container_type,
&container_name))
{
dbus_bool_t did_append;
if (prev_added)
{
if (!_dbus_string_append_byte (&loginfo_buf, ' '))
goto oom;
}
did_append = _dbus_string_append_printf (&loginfo_buf,
"container=%s %s=\"%s\")",
container,
container_type,
container_name);
if (!did_append)
goto oom;
else
prev_added = TRUE;
}
if (!_dbus_string_steal_data (&loginfo_buf, &(d->cached_loginfo_string)))
goto oom;

1392
bus/containers.c Normal file

File diff suppressed because it is too large Load diff

71
bus/containers.h Normal file
View file

@ -0,0 +1,71 @@
/* containers.h - restricted bus servers for containers
*
* Copyright © 2017 Collabora Ltd.
*
* Licensed under the Academic Free License version 2.1
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#ifndef BUS_CONTAINERS_H
#define BUS_CONTAINERS_H
#include "bus.h"
#include <dbus/dbus-macros.h>
BusContainers *bus_containers_new (void);
BusContainers *bus_containers_ref (BusContainers *self);
void bus_containers_unref (BusContainers *self);
void bus_containers_stop_listening (BusContainers *self);
dbus_bool_t bus_containers_handle_add_server (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusError *error);
dbus_bool_t bus_containers_handle_stop_instance (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusError *error);
dbus_bool_t bus_containers_handle_stop_listening (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusError *error);
dbus_bool_t bus_containers_handle_get_instance_info (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusError *error);
dbus_bool_t bus_containers_handle_get_connection_instance (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusError *error);
dbus_bool_t bus_containers_supported_arguments_getter (BusContext *context,
DBusMessageIter *var_iter);
void bus_containers_remove_connection (BusContainers *self,
DBusConnection *connection);
dbus_bool_t bus_containers_connection_is_contained (DBusConnection *connection,
const char **path,
const char **type,
const char **name);
static inline void
bus_clear_containers (BusContainers **containers_p)
{
_dbus_clear_pointer_impl (BusContainers, containers_p, bus_containers_unref);
}
#endif /* multiple-inclusion guard */

View file

@ -26,6 +26,7 @@
#include "activation.h"
#include "apparmor.h"
#include "connection.h"
#include "containers.h"
#include "driver.h"
#include "dispatch.h"
#include "services.h"
@ -109,6 +110,28 @@ bus_driver_get_conn_helper (DBusConnection *connection,
return BUS_DRIVER_FOUND_PEER;
}
static dbus_bool_t
bus_driver_check_caller_is_not_container (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusError *error)
{
if (bus_containers_connection_is_contained (connection, NULL, NULL, NULL))
{
const char *method = dbus_message_get_member (message);
bus_context_log_and_set_error (bus_transaction_get_context (transaction),
DBUS_SYSTEM_LOG_SECURITY, error, DBUS_ERROR_ACCESS_DENIED,
"rejected attempt to call %s by connection %s (%s) in "
"container", method,
nonnull (bus_connection_get_name (connection), "(inactive)"),
bus_connection_get_loginfo (connection));
return FALSE;
}
return TRUE;
}
/*
* Log a security warning and set error unless the uid of the connection
* is either the uid of this process, or on Unix, uid 0 (root).
@ -128,7 +151,16 @@ bus_driver_check_caller_is_privileged (DBusConnection *connection,
{
#ifdef DBUS_UNIX
unsigned long uid;
#elif defined(DBUS_WIN)
char *windows_sid = NULL;
dbus_bool_t ret = FALSE;
#endif
if (!bus_driver_check_caller_is_not_container (connection, transaction,
message, error))
return FALSE;
#ifdef DBUS_UNIX
if (!dbus_connection_get_unix_user (connection, &uid))
{
const char *method = dbus_message_get_member (message);
@ -168,9 +200,6 @@ bus_driver_check_caller_is_privileged (DBusConnection *connection,
return TRUE;
#elif defined(DBUS_WIN)
char *windows_sid = NULL;
dbus_bool_t ret = FALSE;
if (!dbus_connection_get_windows_user (connection, &windows_sid))
{
const char *method = dbus_message_get_member (message);
@ -1886,7 +1915,10 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
DBusMessageIter array_iter;
unsigned long ulong_uid, ulong_pid;
char *s;
const char *name;
const char *path;
const char *service;
const char *type;
BusDriverFound found;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
@ -1974,6 +2006,19 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
dbus_free (s);
}
if (found == BUS_DRIVER_FOUND_PEER &&
bus_containers_connection_is_contained (conn, &path, &type, &name))
{
if (!_dbus_asv_add_object_path (&array_iter,
DBUS_INTERFACE_CONTAINERS1 ".Instance",
path) ||
!_dbus_asv_add_string (&array_iter,
DBUS_INTERFACE_CONTAINERS1 ".Type", type) ||
!_dbus_asv_add_string (&array_iter,
DBUS_INTERFACE_CONTAINERS1 ".Name", name))
goto oom;
}
if (!_dbus_asv_close (&reply_iter, &array_iter))
goto oom;
@ -2368,9 +2413,15 @@ typedef enum
/* If set, callers must be privileged. On Unix, the uid of the connection
* must either be the uid of this process, or 0 (root). On Windows,
* the SID of the connection must be the SID of this process. */
* the SID of the connection must be the SID of this process.
*
* This flag effectively implies METHOD_FLAG_NO_CONTAINERS, because
* containers are never privileged. */
METHOD_FLAG_PRIVILEGED = (1 << 1),
/* If set, callers must not be associated with a container instance. */
METHOD_FLAG_NO_CONTAINERS = (1 << 2),
METHOD_FLAG_NONE = 0
} MethodFlags;
@ -2517,6 +2568,27 @@ static const MessageHandler introspectable_message_handlers[] = {
{ NULL, NULL, NULL, NULL }
};
#ifdef DBUS_ENABLE_CONTAINERS
static const MessageHandler containers_message_handlers[] = {
{ "AddServer", "ssa{sv}a{sv}", "oays", bus_containers_handle_add_server,
METHOD_FLAG_NO_CONTAINERS },
{ "StopInstance", "o", "", bus_containers_handle_stop_instance,
METHOD_FLAG_NO_CONTAINERS },
{ "StopListening", "o", "", bus_containers_handle_stop_listening,
METHOD_FLAG_NO_CONTAINERS },
{ "GetConnectionInstance", "s", "ossa{sv}",
bus_containers_handle_get_connection_instance,
METHOD_FLAG_NONE },
{ "GetInstanceInfo", "o", "ssa{sv}", bus_containers_handle_get_instance_info,
METHOD_FLAG_NONE },
{ NULL, NULL, NULL, NULL }
};
static const PropertyHandler containers_property_handlers[] = {
{ "SupportedArguments", "as", bus_containers_supported_arguments_getter },
{ NULL, NULL, NULL }
};
#endif
static const MessageHandler monitoring_message_handlers[] = {
{ "BecomeMonitor", "asu", "", bus_driver_handle_become_monitor,
METHOD_FLAG_PRIVILEGED },
@ -2526,9 +2598,9 @@ static const MessageHandler monitoring_message_handlers[] = {
#ifdef DBUS_ENABLE_VERBOSE_MODE
static const MessageHandler verbose_message_handlers[] = {
{ "EnableVerbose", "", "", bus_driver_handle_enable_verbose,
METHOD_FLAG_NONE },
METHOD_FLAG_NO_CONTAINERS },
{ "DisableVerbose", "", "", bus_driver_handle_disable_verbose,
METHOD_FLAG_NONE },
METHOD_FLAG_NO_CONTAINERS },
{ NULL, NULL, NULL, NULL }
};
#endif
@ -2536,11 +2608,11 @@ static const MessageHandler verbose_message_handlers[] = {
#ifdef DBUS_ENABLE_STATS
static const MessageHandler stats_message_handlers[] = {
{ "GetStats", "", "a{sv}", bus_stats_handle_get_stats,
METHOD_FLAG_NONE },
METHOD_FLAG_NO_CONTAINERS },
{ "GetConnectionStats", "s", "a{sv}", bus_stats_handle_get_connection_stats,
METHOD_FLAG_NONE },
METHOD_FLAG_NO_CONTAINERS },
{ "GetAllMatchRules", "", "a{sas}", bus_stats_handle_get_all_match_rules,
METHOD_FLAG_NONE },
METHOD_FLAG_NO_CONTAINERS },
{ NULL, NULL, NULL, NULL }
};
#endif
@ -2620,6 +2692,13 @@ static InterfaceHandler interface_handlers[] = {
#ifdef DBUS_ENABLE_STATS
{ BUS_INTERFACE_STATS, stats_message_handlers, NULL,
INTERFACE_FLAG_NONE },
#endif
#ifdef DBUS_ENABLE_CONTAINERS
{ DBUS_INTERFACE_CONTAINERS1, containers_message_handlers,
" <signal name=\"InstanceRemoved\">\n"
" <arg type=\"o\" name=\"path\"/>\n"
" </signal>\n",
INTERFACE_FLAG_NONE, containers_property_handlers },
#endif
{ DBUS_INTERFACE_PEER, peer_message_handlers, NULL,
/* Not in the Interfaces property because it's a pseudo-interface
@ -2913,12 +2992,25 @@ bus_driver_handle_message (DBusConnection *connection,
_dbus_verbose ("Found driver handler for %s\n", name);
if ((mh->flags & METHOD_FLAG_PRIVILEGED) &&
!bus_driver_check_caller_is_privileged (connection, transaction,
message, error))
if (mh->flags & METHOD_FLAG_PRIVILEGED)
{
_DBUS_ASSERT_ERROR_IS_SET (error);
return FALSE;
if (!bus_driver_check_caller_is_privileged (connection,
transaction, message,
error))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
return FALSE;
}
}
else if (mh->flags & METHOD_FLAG_NO_CONTAINERS)
{
if (!bus_driver_check_caller_is_not_container (connection,
transaction,
message, error))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
return FALSE;
}
}
if (!(is_canonical_path || (mh->flags & METHOD_FLAG_ANY_PATH)))

View file

@ -76,5 +76,11 @@
<limit name="max_names_per_connection">50000</limit>
<limit name="max_match_rules_per_connection">50000</limit>
<limit name="max_replies_per_connection">50000</limit>
<limit name="max_containers">10000</limit>
<limit name="max_containers_per_user">10000</limit>
<limit name="max_container_metadata_bytes">1000000000</limit>
<!-- This is relatively low so that app-containers (which we do not fully
trust) do not cause DoS. -->
<limit name="max_connections_per_container">16</limit>
</busconfig>

View file

@ -69,6 +69,8 @@
send_interface="org.freedesktop.DBus.Introspectable"/>
<allow send_destination="org.freedesktop.DBus"
send_interface="org.freedesktop.DBus.Properties"/>
<allow send_destination="org.freedesktop.DBus"
send_interface="org.freedesktop.DBus.Containers1"/>
<!-- But disallow some specific bus services -->
<deny send_destination="org.freedesktop.DBus"
send_interface="org.freedesktop.DBus"
@ -124,6 +126,10 @@
<!-- <limit name="max_names_per_connection">512</limit> -->
<!-- <limit name="max_match_rules_per_connection">512</limit> -->
<!-- <limit name="max_replies_per_connection">128</limit> -->
<!-- <limit name="max_containers">512</limit> -->
<!-- <limit name="max_containers_per_user">16</limit> -->
<!-- <limit name="max_container_metadata_bytes">4096</limit> -->
<!-- <limit name="max_connections_per_container">8</limit> -->
<!-- Config files are placed here that among other things, punch
holes in the above policy for specific services. -->

View file

@ -3,3 +3,7 @@
# Make ${localstatedir}/lib/dbus/machine-id a symlink to /etc/machine-id
# if it does not already exist
L @EXPANDED_LOCALSTATEDIR@/lib/dbus/machine-id - - - - /etc/machine-id
# Create ${runstatedir}/dbus/containers owned by the system bus user.
# org.freedesktop.DBus.Containers1 uses this to create sockets.
d @EXPANDED_RUNSTATEDIR@/dbus/containers 0755 @DBUS_USER@ - - -

View file

@ -128,6 +128,7 @@ endif(NOT WIN32)
option (DBUS_DISABLE_ASSERT "Disable assertion checking" OFF)
option (DBUS_ENABLE_STATS "enable bus daemon usage statistics" OFF)
option (DBUS_ENABLE_CONTAINERS "enable restricted servers for app-containers" OFF)
if(WIN32)
set(FD_SETSIZE "8192" CACHE STRING "The maximum number of connections that can be handled at once")

View file

@ -52,6 +52,8 @@ set (BUS_SOURCES
# ${BUS_DIR}/config-parser-trivial.c
${BUS_DIR}/connection.c
${BUS_DIR}/connection.h
${BUS_DIR}/containers.c
${BUS_DIR}/containers.h
${BUS_DIR}/desktop-file.c
${BUS_DIR}/desktop-file.h
${BUS_DIR}/dir-watch.h

View file

@ -28,6 +28,7 @@
#cmakedefine DBUS_RUNSTATEDIR "@DBUS_RUNSTATEDIR@"
#cmakedefine DBUS_ENABLE_STATS
#cmakedefine DBUS_ENABLE_CONTAINERS
#define TEST_LISTEN "@TEST_LISTEN@"

View file

@ -1762,6 +1762,16 @@ AC_ARG_ENABLE([user-session],
AM_CONDITIONAL([DBUS_ENABLE_USER_SESSION],
[test "x$enable_user_session" = xyes])
AC_ARG_ENABLE([containers],
[AS_HELP_STRING([--enable-containers],
[enable restricted servers for app containers])],
[], [enable_containers=no])
AS_IF([test "x$enable_containers" = xyes && test "x$dbus_unix" != xyes],
[AC_MSG_ERROR([Restricted servers for app containers require Unix])])
AS_IF([test "x$enable_containers" = xyes],
[AC_DEFINE([DBUS_ENABLE_CONTAINERS], [1],
[Define to enable restricted servers for app containers])])
AC_CONFIG_FILES([
Doxyfile
dbus/Version
@ -1842,6 +1852,7 @@ echo "
Building assertions: ${enable_asserts}
Building checks: ${enable_checks}
Building bus stats API: ${enable_stats}
Building container API: ${enable_containers}
Building SELinux support: ${have_selinux}
Building AppArmor support: ${have_apparmor}
Building inotify support: ${have_inotify}

View file

@ -88,6 +88,7 @@ DBUS_PRIVATE_EXPORT
void _dbus_hash_iter_remove_entry (DBusHashIter *iter);
DBUS_PRIVATE_EXPORT
void* _dbus_hash_iter_get_value (DBusHashIter *iter);
DBUS_PRIVATE_EXPORT
void _dbus_hash_iter_set_value (DBusHashIter *iter,
void *value);
DBUS_PRIVATE_EXPORT
@ -96,6 +97,7 @@ DBUS_PRIVATE_EXPORT
const char* _dbus_hash_iter_get_string_key (DBusHashIter *iter);
DBUS_PRIVATE_EXPORT
uintptr_t _dbus_hash_iter_get_uintptr_key (DBusHashIter *iter);
DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_hash_iter_lookup (DBusHashTable *table,
void *key,
dbus_bool_t create_if_not_found,

View file

@ -376,6 +376,7 @@ void _dbus_unlock (DBusGlobalLock lock);
DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_threads_init_debug (void);
DBUS_PRIVATE_EXPORT
dbus_bool_t _dbus_address_append_escaped (DBusString *escaped,
const DBusString *unescaped);

View file

@ -455,6 +455,9 @@ extern "C" {
* but could have succeeded if an interactive authorization step was
* allowed. */
#define DBUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED "org.freedesktop.DBus.Error.InteractiveAuthorizationRequired"
/** The connection is not from a container, or the specified container instance
* does not exist. */
#define DBUS_ERROR_NOT_CONTAINER "org.freedesktop.DBus.Error.NotContainer"
/* XML introspection format */

View file

@ -86,6 +86,8 @@ typedef enum
*/
/** The interface exported by the object with #DBUS_SERVICE_DBUS and #DBUS_PATH_DBUS */
#define DBUS_INTERFACE_DBUS "org.freedesktop.DBus"
/** The restricted container interface exported by the dbus-daemon */
#define DBUS_INTERFACE_CONTAINERS1 "org.freedesktop.DBus.Containers1"
/** The monitoring interface exported by the dbus-daemon */
#define DBUS_INTERFACE_MONITORING "org.freedesktop.DBus.Monitoring"

View file

@ -749,6 +749,14 @@ Available limit names are:</para>
(number of calls-in-progress)
"reply_timeout" : milliseconds (thousandths)
until a method call times out
"max_containers" : max number of restricted servers for use
in app-containers, in total
"max_containers_per_user" : max number of app-containers per Unix uid
"max_container_metadata_bytes": max number of bytes of metadata to store
for each app-container
"max_connections_per_container": max number of (authenticated or
unauthenticated) connections to each
app-container
</literallayout> <!-- .fi -->

View file

@ -6416,6 +6416,44 @@
</entry>
</row>
<row>
<entry>org.freedesktop.DBus.Containers1.Instance</entry>
<entry>OBJECT_PATH</entry>
<entry>
The container instance object path of the server through
which this connection is connected, as returned by
<literal>AddServer</literal>. Omitted from the
dictionary if this connection is not via a container's
server.
</entry>
</row>
<row>
<entry>org.freedesktop.DBus.Containers1.Type</entry>
<entry>STRING</entry>
<entry>
The container technology that created the container
instance, as passed to <literal>AddServer</literal>.
Omitted from the dictionary if this connection is not
via a container's server. For example, a typical value
for a Flatpak application would be
<literal>org.flatpak</literal>.
</entry>
</row>
<row>
<entry>org.freedesktop.DBus.Containers1.Name</entry>
<entry>STRING</entry>
<entry>
The contained app name for the container instance,
as passed to <literal>AddServer</literal>. Omitted
from the dictionary if this connection is not via a
container's server. For example, a typical value for
a Flatpak application would be
<literal>org.gnome.Weather</literal>.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
@ -6647,6 +6685,520 @@
</para>
</sect3>
<sect3 id="bus-messages-containers1-add-server">
<title><literal>org.freedesktop.DBus.Containers1.AddServer</literal></title>
<para>
As a method:
<programlisting>
AddServer (in STRING container_type,
in STRING container_name,
in DICT&lt;STRING,VARIANT&gt; metadata,
in DICT&lt;STRING,VARIANT&gt; named_arguments,
out OBJECT_PATH container_instance,
out ARRAY&lt;BYTE&gt; socket_path,
out STRING connectable_address)
</programlisting>
Message arguments:
<informaltable>
<tgroup cols="3">
<thead>
<row>
<entry>Argument</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>0</entry>
<entry>STRING</entry>
<entry>
Reversed domain name identifying a container manager
or container technology, such as
<literal>org.flatpak</literal> or
<literal>io.snapcraft</literal>. It must follow the
same syntactic rules as a
<link linkend="message-protocol-names-interface">D-Bus
interface name</link>.
</entry>
</row>
<row>
<entry>1</entry>
<entry>STRING</entry>
<entry>
Some unique identifier for an application or
container, whose meaning is defined by the
maintainers of the container type. If the container
type does not have a concept of identifying or
naming its applications or containers by a string,
using the empty string here is suggested.
</entry>
</row>
<row>
<entry>2</entry>
<entry>DICT&lt;STRING,VARIANT&gt;</entry>
<entry>
Metadata describing the application or container, with the
keys and values defined by the maintainers of the container
type.
</entry>
</row>
<row>
<entry>3</entry>
<entry>DICT&lt;STRING,VARIANT&gt;</entry>
<entry>
Additional arguments that extend this method.
The only named arguments that are allowed are the ones
listed in the
<literal>org.freedesktop.DBus.Containers1.SupportedArguments</literal>
property. All other named arguments are an error.
</entry>
</row>
<row>
<entry>4</entry>
<entry>OBJECT_PATH</entry>
<entry>
An opaque object path identifying the new container
instance.
</entry>
</row>
<row>
<entry>5</entry>
<entry>ARRAY&lt;BYTE&gt;</entry>
<entry>
The absolute filesystem path of the resulting
<literal>AF_UNIX</literal> socket, followed by a single
zero (nul) byte, for example
<literal>/run/user/1000/dbus-12345vwxyz\x00</literal>
where \x00 represents the terminating zero byte.
</entry>
</row>
<row>
<entry>6</entry>
<entry>STRING</entry>
<entry>
A connectable D-Bus address, for example
<literal>unix:path=/run/user/1000/dbus-12345vwxyz</literal>.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>
Set up a new server socket for use in an application container.
Clients can connect to that socket, and the result will be as
though they had connected to the message bus, with a few differences.
The intention is that a container manager will call this method
to get a new server socket, bind-mount the server socket
into a location that is accessible by the confined (sandboxed)
application, and ensure that the normal message bus socket is
<emphasis>not</emphasis> accessible by the confined application.
</para>
<para>
Each call to this method creates a new
<firstterm>container instance</firstterm>, identified by an object
path. Even if the specified container type and name are the
same as for a pre-existing container instance, each call
creates a new server with a new unique object path, because
the new container instance might represent a different
version of the confined application with different
characteristics and restrictions. The message bus may provide
an object at the given object path, but is not required to
do so.
</para>
<para>
Metadata from the first three arguments is stored by the message
bus, but not interpreted; software that interacts with the
container manager can use this metadata.
<!-- TODO: Clarify how the trust model works here. See
<https://bugs.freedesktop.org/show_bug.cgi?id=100344#c15>-->
The method call may fail with the error
<literal>org.freedesktop.DBus.Error.LimitsExceeded</literal>
if the caller provides more metadata than the message bus
is willing to store.
</para>
<para>
The last argument (the <firstterm>named arguments</firstterm>)
will be used in future versions of this specification to modify
the behaviour of this method call; all keys in this dictionary not
containing <literal>.</literal> are reserved by this specification
for this purpose. It can also contain implementation-specific
arguments for a particular message bus implementation, which
should start with a reversed domain name in the same way as
interface names. For example, GLib's gdbus-daemon might use
<literal>org.gtk.GDBus.SomeArgument</literal> if it used this
extension point.
</para>
<para>
In the most basic form of a call to this method, the new server
socket is an <literal>AF_UNIX</literal> socket at a path chosen
by the message bus and returned from the method. Future versions
of this specification are likely to provide a way for the
message bus implementation to receive a socket from the caller
and arrange for it to listen for connections, using the named
arguments dictionary.
</para>
<para>
Connections to the new server socket are said to be
<firstterm>confined</firstterm>. The message bus may prevent
confined connections from calling certain security-sensitive methods,
and may apply lower limits to these connections. However, container
managers and services must not rely on confined connections having
any particular filtering applied to them by the message bus.
</para>
<para>
In the most basic form of a call to this method, the server
socket will cease to listen for new connections (in the same
way as if <literal>StopListening</literal> had been called
successfully) when the caller of this method disconnects from
the bus. Any confined connections that are already active are
unaffected. Future versions of this specification are likely
to provide a way for the caller to alter this behaviour by
specifying named arguments.
</para>
<para>
The container instance object path remains valid for as
long as one or more confined connection via the same server
socket remain open, or there is a way for the server socket
to produce new connections in future (in other words,
either it is preparing to listen for new connections, or
it is currently listening for new connections). When the
container instance has ceased to listen for new connections
and no longer has any confined connections, the object path
becomes invalid, and API calls that specify it will fail with
the <literal>org.freedesktop.DBus.Error.NotContainer</literal>
error.
</para>
</sect3>
<sect3 id="bus-messages-containers1-stop-instance">
<title><literal>org.freedesktop.DBus.Containers1.StopInstance</literal></title>
<para>
As a method:
<programlisting>
StopInstance (in OBJECT_PATH container_instance)
</programlisting>
Message arguments:
<informaltable>
<tgroup cols="3">
<thead>
<row>
<entry>Argument</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>0</entry>
<entry>OBJECT_PATH</entry>
<entry>
The opaque object path that was returned from the
<literal>AddServer</literal> method, identifying a
container instance.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>
Terminate the container instance. The server will stop
listening for new connections, and any existing connections to
that server will be disconnected. When all connections have
been disconnected, the instance will cease to exist.
</para>
<para>
If the given object path does not represent a valid container
instance (see
<xref linkend="bus-messages-containers1-add-server"/>), the
<literal>org.freedesktop.DBus.Error.NotContainer</literal>
error is returned. In particular, if this method is called
twice, the second call will fail in this way.
</para>
<para>
If the given container instance exists but the caller of this
method is not allowed to stop it (for example because the
caller is in a container instance or because its user ID does
not match the user ID of the creator of the container
instance),
the <literal>org.freedesktop.DBus.Error.AccessDenied</literal>
error is returned and nothing is stopped.
</para>
</sect3>
<sect3 id="bus-messages-containers1-stop-listening">
<title><literal>org.freedesktop.DBus.Containers1.StopListening</literal></title>
<para>
As a method:
<programlisting>
StopListening (in OBJECT_PATH container_instance)
</programlisting>
Message arguments:
<informaltable>
<tgroup cols="3">
<thead>
<row>
<entry>Argument</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>0</entry>
<entry>OBJECT_PATH</entry>
<entry>
The opaque object path that was returned from the
<literal>AddServer</literal> method, identifying a
container instance.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>
Stop listening for new connections to the server in the given
container instance, but do not disconnect any existing
connections.
</para>
<para>
If this method is called more than once, while the container
instance still exists because connections to it are still
open, the second and subsequent calls will be successful but
will have no practical effect.
</para>
<para>
If the given object path does not represent a valid container
instance (see
<xref linkend="bus-messages-containers1-add-server"/>), the
<literal>org.freedesktop.DBus.Error.NotContainer</literal>
error is returned. In particular, this will happen if the
container instance already stopped listening, and all
connections to it (if any) were already closed.
</para>
<para>
If the given container instance exists but the caller of this
method is not allowed to stop it (for example because the
caller is in a container instance or because its user ID does
not match the user ID of the creator of the container
instance),
the <literal>org.freedesktop.DBus.Error.AccessDenied</literal>
error is returned and nothing is stopped.
</para>
</sect3>
<sect3 id="bus-messages-containers1-get-connection-instance">
<title><literal>org.freedesktop.DBus.Containers1.GetConnectionInstance</literal></title>
<para>
As a method:
<programlisting>
GetConnectionInstance (in STRING bus_name,
out OBJECT_PATH container_instance,
out STRING container_type,
out STRING container_name,
out DICT&lt;STRING,VARIANT&gt; metadata)
</programlisting>
Message arguments:
<informaltable>
<tgroup cols="3">
<thead>
<row>
<entry>Argument</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>0</entry>
<entry>STRING</entry>
<entry>
Unique or well-known bus name of the connection to
query, such as <literal>:12.34</literal> or
<literal>com.example.tea</literal>.
</entry>
</row>
<row>
<entry>1</entry>
<entry>OBJECT_PATH</entry>
<entry>
The opaque object path that was returned from the
<literal>AddServer</literal> method, identifying a
container instance.
</entry>
</row>
<row>
<entry>2</entry>
<entry>STRING</entry>
<entry>
Reversed domain name identifying a container
manager or container technology, as passed to the
<literal>AddServer</literal> method, such as
<literal>org.flatpak</literal> or
<literal>io.snapcraft</literal>.
</entry>
</row>
<row>
<entry>3</entry>
<entry>STRING</entry>
<entry>
Some unique identifier for an application or container,
whose meaning is defined by the maintainers of the
container type.
</entry>
</row>
<row>
<entry>4</entry>
<entry>DICT&lt;STRING,VARIANT&gt;</entry>
<entry>
Metadata describing the application or container, with the
keys and values defined by the maintainers of the container
type.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>
If the given unique or well-known bus name is a connection to a
container server, return information about that container instance.
If the bus name exists but is not confined (in other words, if it
is a direct connection to the main message bus socket), the
<literal>org.freedesktop.DBus.Error.NotContainer</literal> error
is returned instead. If the given bus name has no owner at all, the
<literal>org.freedesktop.DBus.Error.NameHasNoOwner</literal> error
is returned instead.
</para>
</sect3>
<sect3 id="bus-messages-containers1-get-instance-info">
<title><literal>org.freedesktop.DBus.Containers1.GetInstanceInfo</literal></title>
<para>
As a method:
<programlisting>
GetInstanceInfo (in OBJECT_PATH container_instance,
out STRING container_type,
out STRING container_name,
out DICT&lt;STRING,VARIANT&gt; metadata)
</programlisting>
Message arguments:
<informaltable>
<tgroup cols="3">
<thead>
<row>
<entry>Argument</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>0</entry>
<entry>OBJECT_PATH</entry>
<entry>
The opaque object path that was returned from the
<literal>AddServer</literal> method, identifying a
container instance.
</entry>
</row>
<row>
<entry>1</entry>
<entry>STRING</entry>
<entry>
Reversed domain name identifying a container
manager or container technology, as passed to the
<literal>AddServer</literal> method, such as
<literal>org.flatpak</literal> or
<literal>io.snapcraft</literal>.
</entry>
</row>
<row>
<entry>2</entry>
<entry>STRING</entry>
<entry>
Some unique identifier for an application or container,
whose meaning is defined by the maintainers of the
container type.
</entry>
</row>
<row>
<entry>3</entry>
<entry>DICT&lt;STRING,VARIANT&gt;</entry>
<entry>
Metadata describing the application or container, with the
keys and values defined by the maintainers of the container
type.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>
If the given object path represents a valid container instance,
(see <xref linkend="bus-messages-containers1-add-server"/>),
return information about it. Otherwise, the
<literal>org.freedesktop.DBus.Error.NotContainer</literal> error
is returned.
</para>
</sect3>
<sect3 id="bus-messages-containers1-instance-removed">
<title><literal>org.freedesktop.DBus.Containers1.InstanceRemoved</literal></title>
<para>
As a signal emitted by the message bus:
<programlisting>
InstanceRemoved (OBJECT_PATH container_instance)
</programlisting>
Message arguments:
<informaltable>
<tgroup cols="3">
<thead>
<row>
<entry>Argument</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>0</entry>
<entry>OBJECT_PATH</entry>
<entry>
The opaque object path that was returned from the
<literal>AddServer</literal> method, identifying a
container instance.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>
Emitted when a container instance ceases to exist. A container
instance continues to exist as long as it is listening for
new connections, or as long as connections to the instance
are open, whichever is longer.
</para>
</sect3>
<sect3 id="bus-messages-become-monitor">
<title><literal>org.freedesktop.DBus.Monitoring.BecomeMonitor</literal></title>
<para>

View file

@ -181,6 +181,7 @@ installable_helpers += \
$(NULL)
installable_tests += \
test-containers \
test-sd-activation \
$(NULL)
@ -286,6 +287,12 @@ test_apparmor_activation_LDADD = \
$(NULL)
endif
test_containers_SOURCES = containers.c
test_containers_LDADD = \
libdbus-testutils.la \
$(GLIB_LIBS) \
$(NULL)
test_corrupt_SOURCES = corrupt.c
test_corrupt_LDADD = \
libdbus-testutils.la \
@ -422,8 +429,10 @@ in_data = \
data/valid-config-files/finite-timeout.conf.in \
data/valid-config-files/forbidding.conf.in \
data/valid-config-files/incoming-limit.conf.in \
data/valid-config-files/limit-containers.conf.in \
data/valid-config-files/max-completed-connections.conf.in \
data/valid-config-files/max-connections-per-user.conf.in \
data/valid-config-files/max-containers.conf.in \
data/valid-config-files/max-match-rules-per-connection.conf.in \
data/valid-config-files/max-names-per-connection.conf.in \
data/valid-config-files/max-replies-per-connection.conf.in \

1620
test/containers.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,21 @@
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<!-- Our well-known bus type, don't change this -->
<type>session</type>
<listen>@TEST_LISTEN@</listen>
<policy context="default">
<!-- Allow everything to be sent -->
<allow send_destination="*" eavesdrop="true"/>
<!-- Allow everything to be received -->
<allow eavesdrop="true"/>
<!-- Allow anyone to own anything -->
<allow own="*"/>
</policy>
<limit name="max_containers">5</limit>
<limit name="max_containers_per_user">3</limit>
<limit name="max_container_metadata_bytes">4096</limit>
<limit name="max_connections_per_container">3</limit>
</busconfig>

View file

@ -0,0 +1,18 @@
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<!-- Our well-known bus type, don't change this -->
<type>session</type>
<listen>@TEST_LISTEN@</listen>
<policy context="default">
<!-- Allow everything to be sent -->
<allow send_destination="*" eavesdrop="true"/>
<!-- Allow everything to be received -->
<allow eavesdrop="true"/>
<!-- Allow anyone to own anything -->
<allow own="*"/>
</policy>
<limit name="max_containers">3</limit>
</busconfig>

View file

@ -507,6 +507,10 @@ test_creds (Fixture *f,
g_assert_not_reached ();
#endif
}
else if (g_str_has_prefix (name, DBUS_INTERFACE_CONTAINERS1 "."))
{
g_assert_not_reached ();
}
dbus_message_iter_next (&arr_iter);
}

View file

@ -187,6 +187,11 @@ test_monitor (Fixture *f,
dbus_clear_message (&m);
}
/*
* Assert that AddServer() can be called by the owner of the bus
* (TEST_USER_MESSAGEBUS) or by root, but cannot be called by other
* users for now.
*/
static void
teardown (Fixture *f,
gconstpointer context G_GNUC_UNUSED)

View file

@ -127,6 +127,7 @@ case "$ci_buildsys" in
set "$@" --enable-developer --enable-tests
# Enable optional features that are off by default
if [ "$ci_host" != mingw ]; then
set "$@" --enable-containers
set "$@" --enable-user-session
fi
shift
@ -153,6 +154,7 @@ case "$ci_buildsys" in
set "$@" --disable-libaudit --without-valgrind
# Disable optional features, some of which are on by
# default
set "$@" --disable-containers
set "$@" --disable-stats
set "$@" --disable-user-session
shift