mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-05-07 15:38:01 +02:00
Merge branch 'containers' into 'main'
Draft: Bring back the Containers interface Closes #477 and #186 See merge request dbus/dbus!449
This commit is contained in:
commit
fac71f6e8a
27 changed files with 1695 additions and 456 deletions
|
|
@ -125,6 +125,7 @@ endif()
|
|||
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)
|
||||
option(ENABLE_TRADITIONAL_ACTIVATION "Enable traditional activation (without using systemd)" ON)
|
||||
|
||||
find_package(PkgConfig)
|
||||
|
|
|
|||
|
|
@ -152,6 +152,9 @@ ENABLE_QT_HELP:STRING=AUTO
|
|||
// enable bus daemon usage statistics
|
||||
DBUS_ENABLE_STATS:BOOL=OFF
|
||||
|
||||
// enable restricted servers for app containers
|
||||
DBUS_ENABLE_CONTAINERS:BOOL=OFF
|
||||
|
||||
// build with systemd at_console support
|
||||
ENABLE_SYSTEMD:STRING=AUTO
|
||||
|
||||
|
|
|
|||
|
|
@ -595,7 +595,8 @@ cache_peer_loginfo_string (BusConnectionData *d,
|
|||
dbus_bool_t prev_added;
|
||||
const char *container = NULL;
|
||||
const char *container_type = NULL;
|
||||
const char *container_name = NULL;
|
||||
const char *app_id = NULL;
|
||||
const char *instance_id = NULL;
|
||||
DBusCredentials *credentials;
|
||||
|
||||
if (!_dbus_string_init (&loginfo_buf))
|
||||
|
|
@ -679,7 +680,8 @@ cache_peer_loginfo_string (BusConnectionData *d,
|
|||
/* This does have to come from the connection, not the credentials */
|
||||
if (bus_containers_connection_is_contained (connection, &container,
|
||||
&container_type,
|
||||
&container_name))
|
||||
&app_id,
|
||||
&instance_id))
|
||||
{
|
||||
dbus_bool_t did_append;
|
||||
|
||||
|
|
@ -690,10 +692,11 @@ cache_peer_loginfo_string (BusConnectionData *d,
|
|||
}
|
||||
|
||||
did_append = _dbus_string_append_printf (&loginfo_buf,
|
||||
"container=%s %s=\"%s\")",
|
||||
"container=%s %s=\"%s\" inst=\"%s\")",
|
||||
container,
|
||||
container_type,
|
||||
container_name);
|
||||
app_id,
|
||||
instance_id);
|
||||
if (!did_append)
|
||||
goto oom;
|
||||
else
|
||||
|
|
@ -2478,17 +2481,17 @@ bus_transaction_send (BusTransaction *transaction,
|
|||
* until we know we have enough memory for the entire transaction,
|
||||
* and that doesn't happen until we know all the recipients.
|
||||
* So this is about the last possible time we could edit the header. */
|
||||
if ((d->want_headers & BUS_EXTRA_HEADERS_CONTAINER_INSTANCE) &&
|
||||
dbus_message_get_container_instance (message) == NULL)
|
||||
if ((d->want_headers & BUS_EXTRA_HEADERS_CONTAINER_PATH) &&
|
||||
dbus_message_get_container_path (message) == NULL)
|
||||
{
|
||||
const char *path;
|
||||
|
||||
if (sender == NULL ||
|
||||
!bus_containers_connection_is_contained (sender, &path,
|
||||
NULL, NULL))
|
||||
NULL, NULL, NULL))
|
||||
path = "/";
|
||||
|
||||
if (!dbus_message_set_container_instance (message, path))
|
||||
if (!dbus_message_set_container_path (message, path))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
typedef enum
|
||||
{
|
||||
BUS_EXTRA_HEADERS_CONTAINER_INSTANCE = (1 << 0),
|
||||
BUS_EXTRA_HEADERS_CONTAINER_PATH = (1 << 0),
|
||||
BUS_EXTRA_HEADERS_NONE = 0
|
||||
} BusExtraHeaders;
|
||||
|
||||
|
|
|
|||
629
bus/containers.c
629
bus/containers.c
File diff suppressed because it is too large
Load diff
|
|
@ -38,7 +38,7 @@ dbus_bool_t bus_containers_handle_add_server (DBusConnection *connecti
|
|||
BusTransaction *transaction,
|
||||
DBusMessage *message,
|
||||
DBusError *error);
|
||||
dbus_bool_t bus_containers_handle_stop_instance (DBusConnection *connection,
|
||||
dbus_bool_t bus_containers_handle_stop_server (DBusConnection *connection,
|
||||
BusTransaction *transaction,
|
||||
DBusMessage *message,
|
||||
DBusError *error);
|
||||
|
|
@ -46,14 +46,14 @@ dbus_bool_t bus_containers_handle_stop_listening (DBusConnection *connecti
|
|||
BusTransaction *transaction,
|
||||
DBusMessage *message,
|
||||
DBusError *error);
|
||||
dbus_bool_t bus_containers_handle_get_instance_info (DBusConnection *connection,
|
||||
dbus_bool_t bus_containers_handle_get_server_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_handle_get_connection_info (DBusConnection *connection,
|
||||
BusTransaction *transaction,
|
||||
DBusMessage *message,
|
||||
DBusError *error);
|
||||
dbus_bool_t bus_containers_handle_request_header (DBusConnection *connection,
|
||||
BusTransaction *transaction,
|
||||
DBusMessage *message,
|
||||
|
|
@ -66,7 +66,8 @@ void bus_containers_remove_connection (BusContainers *self,
|
|||
dbus_bool_t bus_containers_connection_is_contained (DBusConnection *connection,
|
||||
const char **path,
|
||||
const char **type,
|
||||
const char **name);
|
||||
const char **app_id,
|
||||
const char **instance_id);
|
||||
|
||||
static inline void
|
||||
bus_clear_containers (BusContainers **containers_p)
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ bus_dispatch (DBusConnection *connection,
|
|||
* don't understand (or validate), so that we can add header fields
|
||||
* in future and clients can assume that we have checked them. */
|
||||
if (!_dbus_message_remove_unknown_fields (message) ||
|
||||
!dbus_message_set_container_instance (message, NULL))
|
||||
!dbus_message_set_container_path (message, NULL))
|
||||
{
|
||||
BUS_SET_OOM (&error);
|
||||
goto out;
|
||||
|
|
|
|||
24
bus/driver.c
24
bus/driver.c
|
|
@ -118,7 +118,7 @@ bus_driver_check_caller_is_not_container (DBusConnection *connection,
|
|||
DBusMessage *message,
|
||||
DBusError *error)
|
||||
{
|
||||
if (bus_containers_connection_is_contained (connection, NULL, NULL, NULL))
|
||||
if (bus_containers_connection_is_contained (connection, NULL, NULL, NULL, NULL))
|
||||
{
|
||||
const char *method = dbus_message_get_member (message);
|
||||
|
||||
|
|
@ -1970,9 +1970,7 @@ bus_driver_fill_connection_credentials (DBusCredentials *credentials,
|
|||
dbus_pid_t pid = DBUS_PID_UNSET;
|
||||
const char *windows_sid = NULL;
|
||||
const char *linux_security_label = NULL;
|
||||
#ifdef DBUS_ENABLE_CONTAINERS
|
||||
const char *path;
|
||||
#endif
|
||||
#ifdef HAVE_UNIX_FD_PASSING
|
||||
int pid_fd = -1; /* owned by credentials */
|
||||
#endif
|
||||
|
|
@ -2033,17 +2031,15 @@ bus_driver_fill_connection_credentials (DBusCredentials *credentials,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef DBUS_ENABLE_CONTAINERS
|
||||
/* This has to come from the connection, not the credentials */
|
||||
if (peer_conn != NULL &&
|
||||
bus_containers_connection_is_contained (peer_conn, &path, NULL, NULL))
|
||||
bus_containers_connection_is_contained (peer_conn, &path, NULL, NULL, NULL))
|
||||
{
|
||||
if (!_dbus_asv_add_object_path (asv_iter,
|
||||
DBUS_INTERFACE_CONTAINERS1 ".Instance",
|
||||
DBUS_INTERFACE_CONTAINERS1 ".Path",
|
||||
path))
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNIX_FD_PASSING
|
||||
if (caller_conn != NULL && pid_fd >= 0 &&
|
||||
|
|
@ -2500,7 +2496,7 @@ typedef enum
|
|||
* containers are never privileged. */
|
||||
METHOD_FLAG_PRIVILEGED = (1 << 1),
|
||||
|
||||
/* If set, callers must not be associated with a container instance. */
|
||||
/* If set, callers must not be associated with a container. */
|
||||
METHOD_FLAG_NO_CONTAINERS = (1 << 2),
|
||||
|
||||
METHOD_FLAG_NONE = 0
|
||||
|
|
@ -2651,16 +2647,16 @@ static const MessageHandler introspectable_message_handlers[] = {
|
|||
|
||||
#ifdef DBUS_ENABLE_CONTAINERS
|
||||
static const MessageHandler containers_message_handlers[] = {
|
||||
{ "AddServer", "ssa{sv}a{sv}", "oays", bus_containers_handle_add_server,
|
||||
{ "AddServer", "sssa{sv}a{sv}", "oa{sv}", bus_containers_handle_add_server,
|
||||
METHOD_FLAG_NO_CONTAINERS },
|
||||
{ "StopInstance", "o", "", bus_containers_handle_stop_instance,
|
||||
{ "StopServer", "o", "", bus_containers_handle_stop_server,
|
||||
METHOD_FLAG_NO_CONTAINERS },
|
||||
{ "StopListening", "o", "", bus_containers_handle_stop_listening,
|
||||
METHOD_FLAG_NO_CONTAINERS },
|
||||
{ "GetConnectionInstance", "s", "oa{sv}ssa{sv}",
|
||||
bus_containers_handle_get_connection_instance,
|
||||
{ "GetConnectionInfo", "s", "oa{sv}sssa{sv}",
|
||||
bus_containers_handle_get_connection_info,
|
||||
METHOD_FLAG_NONE },
|
||||
{ "GetInstanceInfo", "o", "a{sv}ssa{sv}", bus_containers_handle_get_instance_info,
|
||||
{ "GetServerInfo", "o", "a{sv}sssa{sv}", bus_containers_handle_get_server_info,
|
||||
METHOD_FLAG_NONE },
|
||||
{ "RequestHeader", "", "", bus_containers_handle_request_header,
|
||||
METHOD_FLAG_NONE },
|
||||
|
|
@ -2780,7 +2776,7 @@ static InterfaceHandler interface_handlers[] = {
|
|||
#endif
|
||||
#ifdef DBUS_ENABLE_CONTAINERS
|
||||
{ DBUS_INTERFACE_CONTAINERS1, containers_message_handlers,
|
||||
" <signal name=\"InstanceRemoved\">\n"
|
||||
" <signal name=\"ServerRemoved\">\n"
|
||||
" <arg type=\"o\" name=\"path\"/>\n"
|
||||
" </signal>\n",
|
||||
INTERFACE_FLAG_NONE, containers_property_handlers },
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -126,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. -->
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#cmakedefine DBUS_RUNSTATEDIR "@DBUS_RUNSTATEDIR@"
|
||||
|
||||
#cmakedefine DBUS_ENABLE_STATS
|
||||
#cmakedefine DBUS_ENABLE_CONTAINERS
|
||||
#cmakedefine ENABLE_TRADITIONAL_ACTIVATION
|
||||
|
||||
#define TEST_LISTEN "@TEST_LISTEN@"
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ _dbus_header_field_types[DBUS_HEADER_FIELD_LAST+1] = {
|
|||
{ DBUS_HEADER_FIELD_SENDER, DBUS_TYPE_STRING },
|
||||
{ DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE },
|
||||
{ DBUS_HEADER_FIELD_UNIX_FDS, DBUS_TYPE_UINT32 },
|
||||
{ DBUS_HEADER_FIELD_CONTAINER_INSTANCE, DBUS_TYPE_OBJECT_PATH }
|
||||
{ DBUS_HEADER_FIELD_CONTAINER_PATH, DBUS_TYPE_OBJECT_PATH }
|
||||
};
|
||||
|
||||
/** Macro to look up the correct type for a field */
|
||||
|
|
@ -922,7 +922,7 @@ load_and_validate_field (DBusHeader *header,
|
|||
string_validation_func = NULL;
|
||||
break;
|
||||
|
||||
case DBUS_HEADER_FIELD_CONTAINER_INSTANCE:
|
||||
case DBUS_HEADER_FIELD_CONTAINER_PATH:
|
||||
/* OBJECT_PATH was validated generically due to its type */
|
||||
string_validation_func = NULL;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -4097,7 +4097,7 @@ dbus_message_contains_unix_fds(DBusMessage *message)
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the container instance this message was sent from.
|
||||
* Sets the container context this message was sent from.
|
||||
*
|
||||
* The path must contain only valid characters for an object path
|
||||
* as defined in the D-Bus specification.
|
||||
|
|
@ -4107,8 +4107,8 @@ dbus_message_contains_unix_fds(DBusMessage *message)
|
|||
* @returns #FALSE if not enough memory
|
||||
*/
|
||||
dbus_bool_t
|
||||
dbus_message_set_container_instance (DBusMessage *message,
|
||||
const char *object_path)
|
||||
dbus_message_set_container_path (DBusMessage *message,
|
||||
const char *object_path)
|
||||
{
|
||||
_dbus_return_val_if_fail (message != NULL, FALSE);
|
||||
_dbus_return_val_if_fail (!message->locked, FALSE);
|
||||
|
|
@ -4117,13 +4117,27 @@ dbus_message_set_container_instance (DBusMessage *message,
|
|||
FALSE);
|
||||
|
||||
return set_or_delete_string_field (message,
|
||||
DBUS_HEADER_FIELD_CONTAINER_INSTANCE,
|
||||
DBUS_HEADER_FIELD_CONTAINER_PATH,
|
||||
DBUS_TYPE_OBJECT_PATH,
|
||||
object_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the container instance this message was sent from, or #NULL
|
||||
* Deprecated alias for dbus_message_set_container_path().
|
||||
*
|
||||
* @param message the message
|
||||
* @param object_path the path or #NULL to unset
|
||||
* @returns #FALSE if not enough memory
|
||||
*/
|
||||
dbus_bool_t
|
||||
dbus_message_set_container_instance (DBusMessage *message,
|
||||
const char *object_path)
|
||||
{
|
||||
return dbus_message_set_container_path (message, object_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the container context this message was sent from, or #NULL
|
||||
* if none.
|
||||
*
|
||||
* The returned string becomes invalid if the message is
|
||||
|
|
@ -4133,7 +4147,7 @@ dbus_message_set_container_instance (DBusMessage *message,
|
|||
* @returns the path (should not be freed) or #NULL
|
||||
*/
|
||||
const char *
|
||||
dbus_message_get_container_instance (DBusMessage *message)
|
||||
dbus_message_get_container_path (DBusMessage *message)
|
||||
{
|
||||
const char *v;
|
||||
|
||||
|
|
@ -4141,12 +4155,24 @@ dbus_message_get_container_instance (DBusMessage *message)
|
|||
|
||||
v = NULL; /* in case field doesn't exist */
|
||||
_dbus_header_get_field_basic (&message->header,
|
||||
DBUS_HEADER_FIELD_CONTAINER_INSTANCE,
|
||||
DBUS_HEADER_FIELD_CONTAINER_PATH,
|
||||
DBUS_TYPE_OBJECT_PATH,
|
||||
(void *) &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated alias for dbus_message_set_container_instance().
|
||||
*
|
||||
* @param message the message
|
||||
* @returns the path (should not be freed) or #NULL
|
||||
*/
|
||||
const char *
|
||||
dbus_message_get_container_instance (DBusMessage *message)
|
||||
{
|
||||
return dbus_message_get_container_path (message);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -236,10 +236,17 @@ dbus_bool_t dbus_message_get_path_decomposed (DBusMessage *message,
|
|||
char ***path);
|
||||
|
||||
DBUS_EXPORT
|
||||
const char *dbus_message_get_container_instance (DBusMessage *message);
|
||||
const char *dbus_message_get_container_path (DBusMessage *message);
|
||||
DBUS_EXPORT
|
||||
dbus_bool_t dbus_message_set_container_path (DBusMessage *message,
|
||||
const char *object_path);
|
||||
#ifndef DBUS_DISABLE_DEPRECATED
|
||||
DBUS_EXPORT DBUS_DEPRECATED
|
||||
const char *dbus_message_get_container_instance (DBusMessage *message);
|
||||
DBUS_EXPORT DBUS_DEPRECATED
|
||||
dbus_bool_t dbus_message_set_container_instance (DBusMessage *message,
|
||||
const char *object_path);
|
||||
#endif
|
||||
|
||||
DBUS_EXPORT
|
||||
dbus_bool_t dbus_message_append_args (DBusMessage *message,
|
||||
|
|
|
|||
|
|
@ -303,9 +303,15 @@ extern "C" {
|
|||
*/
|
||||
#define DBUS_HEADER_FIELD_UNIX_FDS 9
|
||||
/**
|
||||
* Header field code for the container instance that sent this message.
|
||||
* Header field code for the container context that sent this message.
|
||||
*/
|
||||
#define DBUS_HEADER_FIELD_CONTAINER_PATH 10
|
||||
/**
|
||||
* Deprecated alias for #DBUS_HEADER_FIELD_CONTAINER_PATH
|
||||
*/
|
||||
#ifndef DBUS_DISABLE_DEPRECATED
|
||||
#define DBUS_HEADER_FIELD_CONTAINER_INSTANCE 10
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -314,7 +320,7 @@ extern "C" {
|
|||
* that unknown codes must be ignored, so check for that before
|
||||
* indexing the array.
|
||||
*/
|
||||
#define DBUS_HEADER_FIELD_LAST DBUS_HEADER_FIELD_CONTAINER_INSTANCE
|
||||
#define DBUS_HEADER_FIELD_LAST DBUS_HEADER_FIELD_CONTAINER_PATH
|
||||
|
||||
/** Header format is defined as a signature:
|
||||
* byte byte order
|
||||
|
|
|
|||
|
|
@ -88,6 +88,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"
|
||||
|
||||
|
|
|
|||
|
|
@ -922,48 +922,6 @@ close_and_invalidate (int *fd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static dbus_bool_t
|
||||
make_pipe (int p[2],
|
||||
DBusError *error)
|
||||
{
|
||||
int retval;
|
||||
|
||||
#ifdef HAVE_PIPE2
|
||||
dbus_bool_t cloexec_done;
|
||||
|
||||
retval = pipe2 (p, O_CLOEXEC);
|
||||
cloexec_done = retval >= 0;
|
||||
|
||||
/* Check if kernel seems to be too old to know pipe2(). We assume
|
||||
that if pipe2 is available, O_CLOEXEC is too. */
|
||||
if (retval < 0 && errno == ENOSYS)
|
||||
#endif
|
||||
{
|
||||
retval = pipe(p);
|
||||
}
|
||||
|
||||
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
|
||||
|
||||
if (retval < 0)
|
||||
{
|
||||
dbus_set_error (error,
|
||||
DBUS_ERROR_SPAWN_FAILED,
|
||||
"Failed to create pipe for communicating with child process (%s)",
|
||||
_dbus_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PIPE2
|
||||
if (!cloexec_done)
|
||||
#endif
|
||||
{
|
||||
_dbus_fd_set_close_on_exec (p[0]);
|
||||
_dbus_fd_set_close_on_exec (p[1]);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
do_write (int fd, const void *buf, size_t count)
|
||||
{
|
||||
|
|
@ -1323,7 +1281,7 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
|
|||
goto cleanup_and_fail;
|
||||
}
|
||||
|
||||
if (!make_pipe (child_err_report_pipe, error))
|
||||
if (!_dbus_unix_make_pipe (child_err_report_pipe, error))
|
||||
goto cleanup_and_fail;
|
||||
|
||||
if (!_dbus_socketpair (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error))
|
||||
|
|
|
|||
|
|
@ -5290,4 +5290,46 @@ _dbus_get_low_level_socket_errno (void)
|
|||
return errno;
|
||||
}
|
||||
|
||||
dbus_bool_t
|
||||
_dbus_unix_make_pipe (int p[2],
|
||||
DBusError *error)
|
||||
{
|
||||
int retval;
|
||||
|
||||
#ifdef HAVE_PIPE2
|
||||
dbus_bool_t cloexec_done;
|
||||
|
||||
retval = pipe2 (p, O_CLOEXEC);
|
||||
cloexec_done = retval >= 0;
|
||||
|
||||
/* Check if kernel seems to be too old to know pipe2(). We assume
|
||||
that if pipe2 is available, O_CLOEXEC is too. */
|
||||
if (retval < 0 && errno == ENOSYS)
|
||||
#endif
|
||||
{
|
||||
retval = pipe(p);
|
||||
}
|
||||
|
||||
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
|
||||
|
||||
if (retval < 0)
|
||||
{
|
||||
dbus_set_error (error,
|
||||
_dbus_error_from_errno (errno),
|
||||
"Failed to create pipe (%s)",
|
||||
_dbus_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PIPE2
|
||||
if (!cloexec_done)
|
||||
#endif
|
||||
{
|
||||
_dbus_fd_set_close_on_exec (p[0]);
|
||||
_dbus_fd_set_close_on_exec (p[1]);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* tests in dbus-sysdeps-util.c */
|
||||
|
|
|
|||
|
|
@ -162,6 +162,10 @@ void _dbus_set_signal_handler (int sig,
|
|||
|
||||
dbus_bool_t _dbus_reset_oom_score_adj (const char **error_str_p);
|
||||
|
||||
DBUS_PRIVATE_EXPORT
|
||||
dbus_bool_t _dbus_unix_make_pipe (int p[2],
|
||||
DBusError *error);
|
||||
|
||||
/** @} */
|
||||
|
||||
DBUS_END_DECLS
|
||||
|
|
|
|||
|
|
@ -856,6 +856,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 -->
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7044,6 +7044,19 @@
|
|||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>org.freedesktop.DBus.Containers1.Path</entry>
|
||||
<entry>OBJECT_PATH</entry>
|
||||
<entry>
|
||||
The object path of the container-specific server through
|
||||
which this connection is connected, as returned by the
|
||||
<link linkend="bus-messages-containers1-add-server"
|
||||
>AddServer</link> method. Omitted from the
|
||||
dictionary if this connection is not via a container's
|
||||
server.
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
|
|
@ -7452,6 +7465,764 @@
|
|||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="message-bus-containers-interface">
|
||||
<title>Containers Interface v1: <literal>org.freedesktop.DBus.Containers1</literal></title>
|
||||
<para>
|
||||
The special message bus name <literal>org.freedesktop.DBus</literal>
|
||||
may optionally implement the
|
||||
<literal>org.freedesktop.DBus.Containers1</literal> interface on
|
||||
the object path <literal>/org/freedesktop/DBus</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This interface allows container managers and similar sandboxing
|
||||
mechanisms to ask the message bus to create a special socket
|
||||
for each sandboxed application,
|
||||
which uniquely identifies the application to other message bus
|
||||
clients without introducing race conditions.
|
||||
For this mechanism to be useful, the sandboxed application must be
|
||||
prevented from connecting to the message bus's usual socket.
|
||||
This interface is a D-Bus equivalent of the
|
||||
<ulink url="https://gitlab.freedesktop.org/wayland/wayland-protocols/-/tree/main/staging/security-context">Wayland security-context extension</ulink>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
As currently implemented, this interface does not apply any
|
||||
special filtering to the D-Bus messages sent and received by a
|
||||
sandboxed application.
|
||||
To limit what a sandboxed application can do on D-Bus, it is
|
||||
likely to be necessary to impose restrictions,
|
||||
perhaps by using a Linux security module such as AppArmor or a
|
||||
filtering proxy such as
|
||||
<ulink url="https://github.com/flatpak/xdg-dbus-proxy/">xdg-dbus-proxy</ulink>.
|
||||
A future version of this specification might add a mechanism for
|
||||
the creator of a confined socket to specify filtering rules.
|
||||
</para>
|
||||
|
||||
<sect3 id="bus-messages-containers1-add-server">
|
||||
<title>Method: <literal>org.freedesktop.DBus.Containers1.AddServer</literal></title>
|
||||
<para>
|
||||
As a method:
|
||||
<programlisting>
|
||||
AddServer (in STRING container_type,
|
||||
in STRING app_id,
|
||||
in STRING instance_id,
|
||||
in DICT<STRING,VARIANT> metadata,
|
||||
in DICT<STRING,VARIANT> named_arguments,
|
||||
out OBJECT_PATH server_path,
|
||||
out DICT<STRING,VARIANT> results)
|
||||
</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>.
|
||||
Container managers should use the same identifier here
|
||||
that they use for the
|
||||
<literal>set_sandbox_engine</literal> request in the
|
||||
<ulink url="https://gitlab.freedesktop.org/wayland/wayland-protocols/-/tree/main/staging/security-context">Wayland security-context extension</ulink>.
|
||||
</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.
|
||||
Container managers should use the same identifier here
|
||||
that they use for the
|
||||
<literal>set_app_id</literal> request in the
|
||||
<ulink url="https://gitlab.freedesktop.org/wayland/wayland-protocols/-/tree/main/staging/security-context">Wayland security-context extension</ulink>.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>2</entry>
|
||||
<entry>STRING</entry>
|
||||
<entry>
|
||||
Some unique identifier for a particular instance of 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 instances by a string,
|
||||
using the empty string here is suggested.
|
||||
Container managers should use the same identifier here
|
||||
that they use for the
|
||||
<literal>set_instance_id</literal> request in the
|
||||
<ulink url="https://gitlab.freedesktop.org/wayland/wayland-protocols/-/tree/main/staging/security-context">Wayland security-context extension</ulink>.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>3</entry>
|
||||
<entry>DICT<STRING,VARIANT></entry>
|
||||
<entry>
|
||||
Metadata describing the application or container.
|
||||
All keys and values are reserved for future standardization,
|
||||
either in this specification or in a separate
|
||||
freedesktop.org specification referenced by this one.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>4</entry>
|
||||
<entry>DICT<STRING,VARIANT></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>5</entry>
|
||||
<entry>OBJECT_PATH</entry>
|
||||
<entry>
|
||||
An opaque object path identifying the new container
|
||||
context.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>6</entry>
|
||||
<entry>DICT<STRING,VARIANT></entry>
|
||||
<entry>
|
||||
Details of the container-specific server that was
|
||||
created (see below).
|
||||
</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 server</firstterm>, identified by an object
|
||||
path. Even if the specified container type, app ID and instance ID
|
||||
are the same as for a pre-existing container server, each call
|
||||
creates a new server with a new unique object path, because
|
||||
the new container server might represent a different
|
||||
version of the confined application with different
|
||||
characteristics and restrictions (although in practice it is
|
||||
expected that container managers are most likely to create one
|
||||
server per instance ID). 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.
|
||||
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>)
|
||||
can be used 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>
|
||||
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.
|
||||
The possible keys currently defined for the named arguments are:
|
||||
<informaltable>
|
||||
<tgroup cols="4">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Key</entry>
|
||||
<entry>Value type</entry>
|
||||
<entry>Default value</entry>
|
||||
<entry>Meaning</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>StopOnDisconnect</literal></entry>
|
||||
<entry>BOOLEAN</entry>
|
||||
<entry>true</entry>
|
||||
<entry>
|
||||
If true or omitted, 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.
|
||||
If false, the server socket continues to listen after
|
||||
the caller disconnects, until there is some other reason
|
||||
for it to stop.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>StopOnNotify</literal></entry>
|
||||
<entry>UNIX_FD</entry>
|
||||
<entry>(none)</entry>
|
||||
<entry>
|
||||
A file descriptor which will become readable (either
|
||||
data available or end-of-file) when it is time to stop
|
||||
listening for new connections. In practice, this is
|
||||
expected to be the read end of a Unix pipe, for which
|
||||
the corresponding write end will be closed (either
|
||||
explicitly or when its owning process exits) when the
|
||||
container manager detects that the application has
|
||||
stopped running. This will often be combined with
|
||||
<literal>{ "StopOnDisconnect": false }</literal>.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Keys in the returned result dictionary not containing "." are defined
|
||||
by this specification. Bus daemon implementors wishing to emit
|
||||
information not mentioned in this document should use keys
|
||||
containing "." and starting with a reversed domain name.
|
||||
Additional keys may be added to the result at any time, and
|
||||
callers must accept and ignore unknown keys in this dictionary.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The defined keys for the result dictionary are:
|
||||
<informaltable>
|
||||
<tgroup cols="3">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Key</entry>
|
||||
<entry>Value type</entry>
|
||||
<entry>Value</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>Address</literal></entry>
|
||||
<entry>STRING</entry>
|
||||
<entry>
|
||||
A connectable D-Bus address, for example
|
||||
<literal>unix:path=/run/user/1000/dbus-12345vwxyz</literal>.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>SocketPath</literal></entry>
|
||||
<entry>ARRAY of BYTE</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>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</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.
|
||||
When operating in this way, each successful call will return a
|
||||
result dictionary containing both <literal>Address</literal> and
|
||||
<literal>SocketPath</literal>.
|
||||
Callers may use whichever of those members is more convenient.
|
||||
If a future version of this specification adds a mechanism to
|
||||
request that the server listens in some way that makes these two
|
||||
members inapplicable, for example receiving a socket from the
|
||||
caller in the named arguments dictionary via file descriptor passing
|
||||
and arranging for it to listen for connections, then those members
|
||||
will be omitted from the result 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>
|
||||
The container server 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 server 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-server">
|
||||
<title>Method: <literal>org.freedesktop.DBus.Containers1.StopServer</literal></title>
|
||||
<para>
|
||||
As a method:
|
||||
<programlisting>
|
||||
StopServer (in OBJECT_PATH server_path)
|
||||
</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
|
||||
per-container server.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Terminate the container server. 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 context will cease to exist.
|
||||
</para>
|
||||
<para>
|
||||
If the given object path does not represent a valid container
|
||||
context (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 server exists but the caller of this
|
||||
method is not allowed to stop it (for example because the
|
||||
caller is in a container server or because its user ID does
|
||||
not match the user ID of the creator of the container
|
||||
context),
|
||||
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>Method: <literal>org.freedesktop.DBus.Containers1.StopListening</literal></title>
|
||||
<para>
|
||||
As a method:
|
||||
<programlisting>
|
||||
StopListening (in OBJECT_PATH server_path)
|
||||
</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 server.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Stop listening for new connections to the given per-container
|
||||
server, but do not disconnect any existing connections.
|
||||
</para>
|
||||
<para>
|
||||
If this method is called more than once, while the container
|
||||
context 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
|
||||
context (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
|
||||
per-container server already stopped listening, and all
|
||||
connections to it (if any) were already closed.
|
||||
</para>
|
||||
<para>
|
||||
If the given per-container server exists but the caller of this
|
||||
method is not allowed to stop it (for example because the
|
||||
caller is itself in a container, or because its user ID does
|
||||
not match the user ID of the creator of the container server),
|
||||
the <literal>org.freedesktop.DBus.Error.AccessDenied</literal>
|
||||
error is returned and nothing is stopped.
|
||||
</para>
|
||||
</sect3>
|
||||
|
||||
<sect3 id="bus-messages-containers1-get-connection-info">
|
||||
<title>Method: <literal>org.freedesktop.DBus.Containers1.GetConnectionInfo</literal></title>
|
||||
<para>
|
||||
As a method:
|
||||
<programlisting>
|
||||
GetConnectionInfo (in STRING bus_name,
|
||||
out OBJECT_PATH server_path,
|
||||
out DICT<STRING,VARIANT> creator,
|
||||
out STRING container_type,
|
||||
out STRING app_id,
|
||||
out STRING instance_id,
|
||||
out DICT<STRING,VARIANT> 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
|
||||
<link linkend="bus-messages-containers1-add-server"
|
||||
>AddServer</link> method, identifying a
|
||||
per-container server.
|
||||
This output parameter is produced by the message bus.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>2</entry>
|
||||
<entry>DICT<STRING,VARIANT></entry>
|
||||
<entry>
|
||||
Credentials of the connection that created this
|
||||
per-container server.
|
||||
The keys and values are the same as those that are
|
||||
documented for
|
||||
<link linkend="bus-messages-get-connection-credentials"
|
||||
>GetConnectionCredentials</link>.
|
||||
This output parameter is produced by the message bus
|
||||
and is appropriate to use in trust decisions.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>3</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>.
|
||||
This output parameter is controlled by the creator
|
||||
of the per-container server.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>4</entry>
|
||||
<entry>STRING</entry>
|
||||
<entry>
|
||||
A unique identifier for an application or container,
|
||||
whose meaning is defined by the maintainers of the
|
||||
container type.
|
||||
For example, Flatpak would use a freedesktop.org app ID
|
||||
such as <literal>org.mozilla.firefox</literal>, but
|
||||
Snap might use a Snap app ID such as
|
||||
<literal>firefox</literal>.
|
||||
This output parameter is controlled by the creator
|
||||
of the per-container server.
|
||||
Depending on the container type, it might be possible
|
||||
to look up further metadata for the application in a
|
||||
container-type-specific way.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>5</entry>
|
||||
<entry>STRING</entry>
|
||||
<entry>
|
||||
A unique identifier for a particular instance of an
|
||||
application or container, whose meaning is defined by
|
||||
the maintainers of the container type.
|
||||
For example, Flatpak would use the same numeric
|
||||
instance ID that is shown by <literal>flatpak ps</literal>.
|
||||
This output parameter is controlled by the creator
|
||||
of the per-container server.
|
||||
Depending on the container type, it might be possible
|
||||
to look up further metadata for the instance in a
|
||||
container-type-specific way, for example by reading
|
||||
<filename>$XDG_RUNTIME_DIR/.flatpak/$INSTANCE/info</filename>
|
||||
for a Flatpak app.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>6</entry>
|
||||
<entry>DICT<STRING,VARIANT></entry>
|
||||
<entry>
|
||||
Metadata describing the application or container.
|
||||
All keys and values are reserved for future standardization,
|
||||
either in this specification or in a separate
|
||||
freedesktop.org specification referenced by this one.
|
||||
This output parameter is controlled by the creator
|
||||
of the per-container server.
|
||||
</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 per-container server.
|
||||
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>
|
||||
<para>
|
||||
Several of the output parameters are controlled by the creator of
|
||||
the per-container server.
|
||||
On a bus that accepts connections from multiple clients at
|
||||
different privilege levels, it is not appropriate to trust those
|
||||
output parameters or use them in trust decisions unless the
|
||||
process identified by the <literal>creator</literal> parameter
|
||||
is trusted.
|
||||
</para>
|
||||
</sect3>
|
||||
|
||||
<sect3 id="bus-messages-containers1-get-server-info">
|
||||
<title>Method: <literal>org.freedesktop.DBus.Containers1.GetServerInfo</literal></title>
|
||||
<para>
|
||||
As a method:
|
||||
<programlisting>
|
||||
GetServerInfo (in OBJECT_PATH server_path,
|
||||
out DICT<STRING,VARIANT> creator,
|
||||
out STRING container_type,
|
||||
out STRING app_id,
|
||||
out STRING instance_id,
|
||||
out DICT<STRING,VARIANT> 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
|
||||
per-container server.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>1</entry>
|
||||
<entry>DICT<STRING,VARIANT></entry>
|
||||
<entry>
|
||||
Credentials of the connection that created this
|
||||
per-container server.
|
||||
The keys and values are the same as those that are
|
||||
documented for
|
||||
<link linkend="bus-messages-get-connection-credentials"
|
||||
>GetConnectionCredentials</link>.
|
||||
This output parameter is produced by the message bus
|
||||
and is appropriate to use in trust decisions.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>2</entry>
|
||||
<entry>STRING</entry>
|
||||
<entry>
|
||||
Reversed domain name identifying a container
|
||||
manager or container technology,
|
||||
the same as the corresponding parameter in
|
||||
<link linkend="bus-messages-containers1-get-connection-info"
|
||||
>GetConnectionInfo</link>.
|
||||
This output parameter is controlled by the creator
|
||||
of the per-container server.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>3</entry>
|
||||
<entry>STRING</entry>
|
||||
<entry>
|
||||
Some unique identifier for an application or container,
|
||||
the same as the corresponding parameter in
|
||||
<link linkend="bus-messages-containers1-get-connection-info"
|
||||
>GetConnectionInfo</link>.
|
||||
This output parameter is controlled by the creator
|
||||
of the per-container server.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>4</entry>
|
||||
<entry>STRING</entry>
|
||||
<entry>
|
||||
Some unique identifier for a particular instance of an
|
||||
application or container,
|
||||
the same as the corresponding parameter in
|
||||
<link linkend="bus-messages-containers1-get-connection-info"
|
||||
>GetConnectionInfo</link>.
|
||||
This output parameter is controlled by the creator
|
||||
of the per-container server.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>5</entry>
|
||||
<entry>DICT<STRING,VARIANT></entry>
|
||||
<entry>
|
||||
Metadata describing the application or container,
|
||||
the same as the corresponding parameter in
|
||||
<link linkend="bus-messages-containers1-get-connection-info"
|
||||
>GetConnectionInfo</link>.
|
||||
This output parameter is controlled by the creator
|
||||
of the per-container server.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If the given object path represents a valid per-container server
|
||||
(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>
|
||||
<para>
|
||||
Several of the output parameters are controlled by the creator of
|
||||
the per-container server.
|
||||
See <xref linkend="bus-messages-containers1-get-connection-info"/>
|
||||
for more details.
|
||||
</para>
|
||||
</sect3>
|
||||
|
||||
<sect3 id="bus-messages-containers1-server-removed">
|
||||
<title>Signal: <literal>org.freedesktop.DBus.Containers1.ServerRemoved</literal></title>
|
||||
<para>
|
||||
As a signal emitted by the message bus:
|
||||
<programlisting>
|
||||
ServerRemoved (OBJECT_PATH server_path)
|
||||
</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
|
||||
per-container server.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Emitted when a per-container server ceases to exist. A per-container
|
||||
server continues to exist as long as it is listening for
|
||||
new connections, or as long as connections to the server
|
||||
are open, whichever is longer.
|
||||
</para>
|
||||
</sect3>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="message-bus-monitoring-interface">
|
||||
<title>Monitoring Interface: <literal>org.freedesktop.DBus.Monitoring</literal></title>
|
||||
<para>
|
||||
|
|
@ -7502,7 +8273,12 @@
|
|||
monitor connections<footnote>
|
||||
<para>
|
||||
In the reference implementation,
|
||||
the default configuration is that each user (identified by
|
||||
the default configuration is that connections to a
|
||||
container server managed by
|
||||
<link linkend="message-bus-containers-interface">the
|
||||
Containers1 interface</link>
|
||||
are not privileged and cannot become a monitor;
|
||||
otherwise, each user (identified by
|
||||
numeric user ID) may monitor their own session bus,
|
||||
and the root user (user ID zero) may monitor the
|
||||
system bus.
|
||||
|
|
|
|||
|
|
@ -47,8 +47,6 @@
|
|||
|
||||
#include "test-utils-glib.h"
|
||||
|
||||
#define DBUS_INTERFACE_CONTAINERS1 "org.freedesktop.DBus.Containers1"
|
||||
|
||||
typedef struct {
|
||||
TestMainContext *ctx;
|
||||
gboolean skip;
|
||||
|
|
@ -58,7 +56,7 @@ typedef struct {
|
|||
|
||||
GDBusProxy *proxy;
|
||||
|
||||
gchar *instance_path;
|
||||
gchar *server_path;
|
||||
gchar *socket_path;
|
||||
gchar *socket_dbus_address;
|
||||
GDBusConnection *unconfined_conn;
|
||||
|
|
@ -67,10 +65,11 @@ typedef struct {
|
|||
|
||||
GDBusConnection *observer_conn;
|
||||
GDBusProxy *observer_proxy;
|
||||
GHashTable *containers_removed;
|
||||
GHashTable *servers_removed;
|
||||
guint removed_sub;
|
||||
DBusConnection *libdbus_observer;
|
||||
DBusMessage *latest_shout;
|
||||
int stop_on_notify_pipe_write_end;
|
||||
} Fixture;
|
||||
|
||||
typedef struct
|
||||
|
|
@ -82,6 +81,8 @@ typedef struct
|
|||
STOP_SERVER_DISCONNECT_FIRST,
|
||||
STOP_SERVER_NEVER_CONNECTED,
|
||||
STOP_SERVER_FORCE,
|
||||
STOP_SERVER_VIA_NOTIFY,
|
||||
STOP_SERVER_VIA_NOTIFY_NOT_MANAGER,
|
||||
STOP_SERVER_WITH_MANAGER
|
||||
}
|
||||
stop_server;
|
||||
|
|
@ -138,13 +139,13 @@ observe_shouting_cb (DBusConnection *observer,
|
|||
}
|
||||
|
||||
static void
|
||||
instance_removed_cb (GDBusConnection *observer,
|
||||
const gchar *sender,
|
||||
const gchar *path,
|
||||
const gchar *iface,
|
||||
const gchar *member,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
server_removed_cb (GDBusConnection *observer,
|
||||
const gchar *sender,
|
||||
const gchar *path,
|
||||
const gchar *iface,
|
||||
const gchar *member,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
Fixture *f = user_data;
|
||||
const gchar *container;
|
||||
|
|
@ -152,11 +153,11 @@ instance_removed_cb (GDBusConnection *observer,
|
|||
g_assert_cmpstr (sender, ==, DBUS_SERVICE_DBUS);
|
||||
g_assert_cmpstr (path, ==, DBUS_PATH_DBUS);
|
||||
g_assert_cmpstr (iface, ==, DBUS_INTERFACE_CONTAINERS1);
|
||||
g_assert_cmpstr (member, ==, "InstanceRemoved");
|
||||
g_assert_cmpstr (member, ==, "ServerRemoved");
|
||||
g_assert_cmpstr (g_variant_get_type_string (parameters), ==, "(o)");
|
||||
g_variant_get (parameters, "(&o)", &container);
|
||||
g_assert (!g_hash_table_contains (f->containers_removed, container));
|
||||
g_hash_table_add (f->containers_removed, g_strdup (container));
|
||||
g_assert (!g_hash_table_contains (f->servers_removed, container));
|
||||
g_hash_table_add (f->servers_removed, g_strdup (container));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -177,6 +178,33 @@ fixture_disconnect_unconfined (Fixture *f)
|
|||
g_clear_object (&f->unconfined_conn);
|
||||
}
|
||||
|
||||
#ifdef DBUS_ENABLE_CONTAINERS
|
||||
static void
|
||||
fixture_disconnect_unconfined_and_wait (Fixture *f)
|
||||
{
|
||||
guint name_watch;
|
||||
gboolean gone = FALSE;
|
||||
|
||||
/* Close the unconfined connection (the container manager) and wait
|
||||
* for it to go away */
|
||||
g_test_message ("Closing container manager...");
|
||||
name_watch = g_bus_watch_name_on_connection (f->confined_conn,
|
||||
f->unconfined_unique_name,
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
NULL,
|
||||
name_gone_set_boolean_cb,
|
||||
&gone, NULL);
|
||||
fixture_disconnect_unconfined (f);
|
||||
|
||||
g_test_message ("Waiting for container manager bus name to disappear...");
|
||||
|
||||
while (!gone)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
g_bus_unwatch_name (name_watch);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
fixture_disconnect_observer (Fixture *f)
|
||||
{
|
||||
|
|
@ -233,15 +261,15 @@ setup (Fixture *f,
|
|||
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT),
|
||||
NULL, NULL, &f->error);
|
||||
g_assert_no_error (f->error);
|
||||
f->containers_removed = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, NULL);
|
||||
f->servers_removed = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, NULL);
|
||||
f->removed_sub = g_dbus_connection_signal_subscribe (f->observer_conn,
|
||||
DBUS_SERVICE_DBUS,
|
||||
DBUS_INTERFACE_CONTAINERS1,
|
||||
"InstanceRemoved",
|
||||
"ServerRemoved",
|
||||
DBUS_PATH_DBUS, NULL,
|
||||
G_DBUS_SIGNAL_FLAGS_NONE,
|
||||
instance_removed_cb,
|
||||
server_removed_cb,
|
||||
f, NULL);
|
||||
|
||||
/* We have to use libdbus for new header fields, because GDBus doesn't
|
||||
|
|
@ -253,6 +281,8 @@ setup (Fixture *f,
|
|||
if (!dbus_connection_add_filter (f->libdbus_observer, observe_shouting_cb, f,
|
||||
NULL))
|
||||
g_error ("OOM");
|
||||
|
||||
f->stop_on_notify_pipe_write_end = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -265,6 +295,7 @@ test_get_supported_arguments (Fixture *f,
|
|||
GVariant *v;
|
||||
#ifdef DBUS_ENABLE_CONTAINERS
|
||||
const gchar **args;
|
||||
gsize i;
|
||||
gsize len;
|
||||
#endif
|
||||
|
||||
|
|
@ -286,8 +317,11 @@ test_get_supported_arguments (Fixture *f,
|
|||
g_assert_cmpstr (g_variant_get_type_string (v), ==, "as");
|
||||
args = g_variant_get_strv (v, &len);
|
||||
|
||||
/* No arguments are defined yet */
|
||||
g_assert_cmpuint (len, ==, 0);
|
||||
g_assert_cmpuint (len, ==, 2);
|
||||
i = 0;
|
||||
g_assert_cmpstr (args[i++], ==, "StopOnDisconnect");
|
||||
g_assert_cmpstr (args[i++], ==, "StopOnNotify");
|
||||
g_assert_cmpstr (args[i++], ==, NULL);
|
||||
|
||||
g_free (args);
|
||||
g_variant_unref (v);
|
||||
|
|
@ -308,10 +342,15 @@ test_get_supported_arguments (Fixture *f,
|
|||
*/
|
||||
static gboolean
|
||||
add_container_server (Fixture *f,
|
||||
GVariant *parameters)
|
||||
GVariant *parameters,
|
||||
GUnixFDList *fds,
|
||||
GUnixFDList **fds_out)
|
||||
{
|
||||
GVariant *tuple;
|
||||
GVariant *named_results;
|
||||
GStatBuf stat_buf;
|
||||
gboolean found;
|
||||
gchar *stringified_args;
|
||||
|
||||
f->proxy = g_dbus_proxy_new_sync (f->unconfined_conn,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
|
||||
|
|
@ -320,9 +359,33 @@ add_container_server (Fixture *f,
|
|||
NULL, &f->error);
|
||||
g_assert_no_error (f->error);
|
||||
|
||||
g_test_message ("Calling AddServer...");
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "AddServer", parameters,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error);
|
||||
stringified_args = g_variant_print (parameters, TRUE);
|
||||
g_test_message ("Calling AddServer%s...", stringified_args);
|
||||
g_free (stringified_args);
|
||||
|
||||
if (fds != NULL || fds_out != NULL)
|
||||
{
|
||||
if (fds != NULL)
|
||||
g_test_message ("Sending %d fds", g_unix_fd_list_get_length (fds));
|
||||
|
||||
if (fds_out != NULL)
|
||||
g_test_message ("Expecting to receive fds in result");
|
||||
|
||||
tuple = g_dbus_proxy_call_with_unix_fd_list_sync (f->proxy,
|
||||
"AddServer",
|
||||
parameters,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
fds,
|
||||
fds_out,
|
||||
NULL,
|
||||
&f->error);
|
||||
}
|
||||
else
|
||||
{
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "AddServer", parameters,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error);
|
||||
}
|
||||
|
||||
/* For root, the sockets go in /run/dbus/containers, which we rely on
|
||||
* system infrastructure to create; so it's OK for AddServer to fail
|
||||
|
|
@ -341,22 +404,34 @@ add_container_server (Fixture *f,
|
|||
g_assert_no_error (f->error);
|
||||
g_assert_nonnull (tuple);
|
||||
|
||||
g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(oays)");
|
||||
g_variant_get (tuple, "(o^ays)", &f->instance_path, &f->socket_path,
|
||||
&f->socket_dbus_address);
|
||||
stringified_args = g_variant_print (tuple, TRUE);
|
||||
g_test_message ("-> %s", stringified_args);
|
||||
g_free (stringified_args);
|
||||
|
||||
g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(oa{sv})");
|
||||
g_variant_get (tuple, "(o@a{sv})", &f->server_path, &named_results);
|
||||
g_assert_nonnull (f->server_path);
|
||||
g_assert_true (g_variant_is_object_path (f->server_path));
|
||||
|
||||
found = g_variant_lookup (named_results, "Address",
|
||||
"s", &f->socket_dbus_address);
|
||||
g_assert_true (found);
|
||||
g_assert_nonnull (f->socket_dbus_address);
|
||||
g_assert_true (g_str_has_prefix (f->socket_dbus_address, "unix:"));
|
||||
g_assert_null (strchr (f->socket_dbus_address, ';'));
|
||||
g_assert_null (strchr (f->socket_dbus_address + strlen ("unix:"), ':'));
|
||||
g_clear_pointer (&tuple, g_variant_unref);
|
||||
|
||||
g_assert_nonnull (f->instance_path);
|
||||
g_assert_true (g_variant_is_object_path (f->instance_path));
|
||||
found = g_variant_lookup (named_results, "SocketPath",
|
||||
"^ay", &f->socket_path);
|
||||
g_assert_true (found);
|
||||
g_assert_nonnull (f->socket_path);
|
||||
g_assert_true (g_path_is_absolute (f->socket_path));
|
||||
g_assert_nonnull (f->socket_dbus_address);
|
||||
g_assert_cmpstr (g_stat (f->socket_path, &stat_buf) == 0 ? NULL :
|
||||
g_strerror (errno), ==, NULL);
|
||||
g_assert_cmpuint ((stat_buf.st_mode & S_IFMT), ==, S_IFSOCK);
|
||||
|
||||
g_clear_pointer (&named_results, g_variant_unref);
|
||||
g_clear_pointer (&tuple, g_variant_unref);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -380,7 +455,8 @@ test_basic (Fixture *f,
|
|||
GVariantDict dict;
|
||||
const gchar *confined_unique_name;
|
||||
const gchar *path_from_query;
|
||||
const gchar *name;
|
||||
const gchar *app_id;
|
||||
const gchar *instance_id;
|
||||
const gchar *name_owner;
|
||||
const gchar *type;
|
||||
guint32 uid;
|
||||
|
|
@ -389,16 +465,18 @@ test_basic (Fixture *f,
|
|||
DBusMessage *libdbus_message = NULL;
|
||||
DBusMessage *libdbus_reply = NULL;
|
||||
DBusError libdbus_error = DBUS_ERROR_INIT;
|
||||
gchar *stringified_result;
|
||||
|
||||
if (f->skip)
|
||||
return;
|
||||
|
||||
parameters = g_variant_new ("(ssa{sv}a{sv})",
|
||||
parameters = g_variant_new ("(sssa{sv}a{sv})",
|
||||
"com.example.NotFlatpak",
|
||||
"sample-app",
|
||||
"sample-instance",
|
||||
NULL, /* no metadata */
|
||||
NULL); /* no named arguments */
|
||||
if (!add_container_server (f, g_steal_pointer (¶meters)))
|
||||
if (!add_container_server (f, g_steal_pointer (¶meters), NULL, NULL))
|
||||
return;
|
||||
|
||||
g_test_message ("Connecting to %s...", f->socket_dbus_address);
|
||||
|
|
@ -445,7 +523,7 @@ test_basic (Fixture *f,
|
|||
while (f->latest_shout == NULL)
|
||||
iterate_both_main_loops (f->ctx);
|
||||
|
||||
g_assert_cmpstr (dbus_message_get_container_instance (f->latest_shout), ==,
|
||||
g_assert_cmpstr (dbus_message_get_container_path (f->latest_shout), ==,
|
||||
NULL);
|
||||
dbus_clear_message (&f->latest_shout);
|
||||
|
||||
|
|
@ -456,7 +534,7 @@ test_basic (Fixture *f,
|
|||
while (f->latest_shout == NULL)
|
||||
iterate_both_main_loops (f->ctx);
|
||||
|
||||
g_assert_cmpstr (dbus_message_get_container_instance (f->latest_shout), ==,
|
||||
g_assert_cmpstr (dbus_message_get_container_path (f->latest_shout), ==,
|
||||
NULL);
|
||||
dbus_clear_message (&f->latest_shout);
|
||||
|
||||
|
|
@ -484,8 +562,8 @@ test_basic (Fixture *f,
|
|||
while (f->latest_shout == NULL)
|
||||
iterate_both_main_loops (f->ctx);
|
||||
|
||||
g_assert_cmpstr (dbus_message_get_container_instance (f->latest_shout), ==,
|
||||
f->instance_path);
|
||||
g_assert_cmpstr (dbus_message_get_container_path (f->latest_shout), ==,
|
||||
f->server_path);
|
||||
dbus_clear_message (&f->latest_shout);
|
||||
|
||||
g_dbus_connection_emit_signal (f->unconfined_conn, NULL, "/",
|
||||
|
|
@ -495,7 +573,7 @@ test_basic (Fixture *f,
|
|||
while (f->latest_shout == NULL)
|
||||
iterate_both_main_loops (f->ctx);
|
||||
|
||||
g_assert_cmpstr (dbus_message_get_container_instance (f->latest_shout), ==,
|
||||
g_assert_cmpstr (dbus_message_get_container_path (f->latest_shout), ==,
|
||||
"/");
|
||||
dbus_clear_message (&f->latest_shout);
|
||||
|
||||
|
|
@ -514,41 +592,50 @@ test_basic (Fixture *f,
|
|||
|
||||
g_test_message ("Inspecting connection container info");
|
||||
confined_unique_name = g_dbus_connection_get_unique_name (f->confined_conn);
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInstance",
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInfo",
|
||||
g_variant_new ("(s)", confined_unique_name),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error);
|
||||
g_assert_no_error (f->error);
|
||||
g_assert_nonnull (tuple);
|
||||
g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(oa{sv}ssa{sv})");
|
||||
g_variant_get (tuple, "(&o@a{sv}&s&s@a{sv})",
|
||||
&path_from_query, &creator, &type, &name, &asv);
|
||||
g_assert_cmpstr (path_from_query, ==, f->instance_path);
|
||||
stringified_result = g_variant_print (tuple, TRUE);
|
||||
g_test_message ("GetConnectionInfo() -> %s", stringified_result);
|
||||
g_free (stringified_result);
|
||||
g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(oa{sv}sssa{sv})");
|
||||
g_variant_get (tuple, "(&o@a{sv}&s&s&s@a{sv})",
|
||||
&path_from_query, &creator, &type, &app_id, &instance_id, &asv);
|
||||
g_assert_cmpstr (path_from_query, ==, f->server_path);
|
||||
g_variant_dict_init (&dict, creator);
|
||||
g_assert_true (g_variant_dict_lookup (&dict, "UnixUserID", "u", &uid));
|
||||
g_assert_cmpuint (uid, ==, _dbus_getuid ());
|
||||
g_variant_dict_clear (&dict);
|
||||
g_assert_cmpstr (type, ==, "com.example.NotFlatpak");
|
||||
g_assert_cmpstr (name, ==, "sample-app");
|
||||
g_assert_cmpstr (app_id, ==, "sample-app");
|
||||
g_assert_cmpstr (instance_id, ==, "sample-instance");
|
||||
/* Trivial case: the metadata a{sv} is empty */
|
||||
g_assert_cmpuint (g_variant_n_children (asv), ==, 0);
|
||||
g_clear_pointer (&asv, g_variant_unref);
|
||||
g_clear_pointer (&creator, g_variant_unref);
|
||||
g_clear_pointer (&tuple, g_variant_unref);
|
||||
|
||||
g_test_message ("Inspecting container instance info");
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetInstanceInfo",
|
||||
g_variant_new ("(o)", f->instance_path),
|
||||
g_test_message ("Inspecting container server info");
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetServerInfo",
|
||||
g_variant_new ("(o)", f->server_path),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error);
|
||||
g_assert_no_error (f->error);
|
||||
g_assert_nonnull (tuple);
|
||||
g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(a{sv}ssa{sv})");
|
||||
g_variant_get (tuple, "(@a{sv}&s&s@a{sv})", &creator, &type, &name, &asv);
|
||||
stringified_result = g_variant_print (tuple, TRUE);
|
||||
g_test_message ("GetServerInfo() -> %s", stringified_result);
|
||||
g_free (stringified_result);
|
||||
g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(a{sv}sssa{sv})");
|
||||
g_variant_get (tuple, "(@a{sv}&s&s&s@a{sv})",
|
||||
&creator, &type, &app_id, &instance_id, &asv);
|
||||
g_variant_dict_init (&dict, creator);
|
||||
g_assert_true (g_variant_dict_lookup (&dict, "UnixUserID", "u", &uid));
|
||||
g_assert_cmpuint (uid, ==, _dbus_getuid ());
|
||||
g_variant_dict_clear (&dict);
|
||||
g_assert_cmpstr (type, ==, "com.example.NotFlatpak");
|
||||
g_assert_cmpstr (name, ==, "sample-app");
|
||||
g_assert_cmpstr (app_id, ==, "sample-app");
|
||||
g_assert_cmpstr (instance_id, ==, "sample-instance");
|
||||
/* Trivial case: the metadata a{sv} is empty */
|
||||
g_assert_cmpuint (g_variant_n_children (asv), ==, 0);
|
||||
g_clear_pointer (&asv, g_variant_unref);
|
||||
|
|
@ -584,12 +671,13 @@ test_wrong_uid (Fixture *f,
|
|||
if (f->skip)
|
||||
return;
|
||||
|
||||
parameters = g_variant_new ("(ssa{sv}a{sv})",
|
||||
parameters = g_variant_new ("(sssa{sv}a{sv})",
|
||||
"com.example.NotFlatpak",
|
||||
"sample-app",
|
||||
"instance1",
|
||||
NULL, /* no metadata */
|
||||
NULL); /* no named arguments */
|
||||
if (!add_container_server (f, g_steal_pointer (¶meters)))
|
||||
if (!add_container_server (f, g_steal_pointer (¶meters), NULL, NULL))
|
||||
return;
|
||||
|
||||
g_test_message ("Connecting to %s...", f->socket_dbus_address);
|
||||
|
|
@ -615,7 +703,8 @@ test_wrong_uid (Fixture *f,
|
|||
|
||||
/*
|
||||
* Test for non-trivial metadata: assert that the metadata a{sv} is
|
||||
* carried through correctly, and that the app name is allowed to be empty.
|
||||
* carried through correctly, and that the app/instance IDs are
|
||||
* allowed to be empty.
|
||||
*/
|
||||
static void
|
||||
test_metadata (Fixture *f,
|
||||
|
|
@ -629,7 +718,8 @@ test_metadata (Fixture *f,
|
|||
GVariantDict dict;
|
||||
const gchar *confined_unique_name;
|
||||
const gchar *path_from_query;
|
||||
const gchar *name;
|
||||
const gchar *app_id;
|
||||
const gchar *instance_id;
|
||||
const gchar *type;
|
||||
guint32 uid;
|
||||
guint u;
|
||||
|
|
@ -644,13 +734,15 @@ test_metadata (Fixture *f,
|
|||
g_variant_dict_insert (&dict, "IsCrepuscular", "b", TRUE);
|
||||
g_variant_dict_insert (&dict, "NChildren", "u", 2);
|
||||
|
||||
parameters = g_variant_new ("(ss@a{sv}a{sv})",
|
||||
parameters = g_variant_new ("(sss@a{sv}a{sv})",
|
||||
"org.example.Springwatch",
|
||||
/* Verify that empty app names are OK */
|
||||
/* Verify that empty app IDs are OK */
|
||||
"",
|
||||
/* Verify that empty instance IDs are OK */
|
||||
"",
|
||||
g_variant_dict_end (&dict),
|
||||
NULL); /* no named arguments */
|
||||
if (!add_container_server (f, g_steal_pointer (¶meters)))
|
||||
if (!add_container_server (f, g_steal_pointer (¶meters), NULL, NULL))
|
||||
return;
|
||||
|
||||
g_test_message ("Connecting to %s...", f->socket_dbus_address);
|
||||
|
|
@ -677,29 +769,30 @@ test_metadata (Fixture *f,
|
|||
asv = g_variant_get_child_value (tuple, 0);
|
||||
g_variant_dict_init (&dict, asv);
|
||||
g_assert_true (g_variant_dict_lookup (&dict,
|
||||
DBUS_INTERFACE_CONTAINERS1 ".Instance",
|
||||
DBUS_INTERFACE_CONTAINERS1 ".Path",
|
||||
"&o", &path_from_query));
|
||||
g_assert_cmpstr (path_from_query, ==, f->instance_path);
|
||||
g_assert_cmpstr (path_from_query, ==, f->server_path);
|
||||
g_variant_dict_clear (&dict);
|
||||
g_clear_pointer (&asv, g_variant_unref);
|
||||
g_clear_pointer (&tuple, g_variant_unref);
|
||||
|
||||
g_test_message ("Inspecting connection container info");
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInstance",
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInfo",
|
||||
g_variant_new ("(s)", confined_unique_name),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error);
|
||||
g_assert_no_error (f->error);
|
||||
g_assert_nonnull (tuple);
|
||||
g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(oa{sv}ssa{sv})");
|
||||
g_variant_get (tuple, "(&o@a{sv}&s&s@a{sv})",
|
||||
&path_from_query, &creator, &type, &name, &asv);
|
||||
g_assert_cmpstr (path_from_query, ==, f->instance_path);
|
||||
g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(oa{sv}sssa{sv})");
|
||||
g_variant_get (tuple, "(&o@a{sv}&s&s&s@a{sv})",
|
||||
&path_from_query, &creator, &type, &app_id, &instance_id, &asv);
|
||||
g_assert_cmpstr (path_from_query, ==, f->server_path);
|
||||
g_variant_dict_init (&dict, creator);
|
||||
g_assert_true (g_variant_dict_lookup (&dict, "UnixUserID", "u", &uid));
|
||||
g_assert_cmpuint (uid, ==, _dbus_getuid ());
|
||||
g_variant_dict_clear (&dict);
|
||||
g_assert_cmpstr (type, ==, "org.example.Springwatch");
|
||||
g_assert_cmpstr (name, ==, "");
|
||||
g_assert_cmpstr (app_id, ==, "");
|
||||
g_assert_cmpstr (instance_id, ==, "");
|
||||
g_variant_dict_init (&dict, asv);
|
||||
g_assert_true (g_variant_dict_lookup (&dict, "NChildren", "u", &u));
|
||||
g_assert_cmpuint (u, ==, 2);
|
||||
|
|
@ -713,20 +806,22 @@ test_metadata (Fixture *f,
|
|||
g_clear_pointer (&creator, g_variant_unref);
|
||||
g_clear_pointer (&tuple, g_variant_unref);
|
||||
|
||||
g_test_message ("Inspecting container instance info");
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetInstanceInfo",
|
||||
g_variant_new ("(o)", f->instance_path),
|
||||
g_test_message ("Inspecting container server info");
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetServerInfo",
|
||||
g_variant_new ("(o)", f->server_path),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error);
|
||||
g_assert_no_error (f->error);
|
||||
g_assert_nonnull (tuple);
|
||||
g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(a{sv}ssa{sv})");
|
||||
g_variant_get (tuple, "(@a{sv}&s&s@a{sv})", &creator, &type, &name, &asv);
|
||||
g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(a{sv}sssa{sv})");
|
||||
g_variant_get (tuple, "(@a{sv}&s&s&s@a{sv})",
|
||||
&creator, &type, &app_id, &instance_id, &asv);
|
||||
g_variant_dict_init (&dict, creator);
|
||||
g_assert_true (g_variant_dict_lookup (&dict, "UnixUserID", "u", &uid));
|
||||
g_assert_cmpuint (uid, ==, _dbus_getuid ());
|
||||
g_variant_dict_clear (&dict);
|
||||
g_assert_cmpstr (type, ==, "org.example.Springwatch");
|
||||
g_assert_cmpstr (name, ==, "");
|
||||
g_assert_cmpstr (app_id, ==, "");
|
||||
g_assert_cmpstr (instance_id, ==, "");
|
||||
g_variant_dict_init (&dict, asv);
|
||||
g_assert_true (g_variant_dict_lookup (&dict, "NChildren", "u", &u));
|
||||
g_assert_cmpuint (u, ==, 2);
|
||||
|
|
@ -755,7 +850,7 @@ test_metadata (Fixture *f,
|
|||
* Test StopListening(), which just closes the listening socket.
|
||||
*
|
||||
* With config->stop_server == STOP_SERVER_FORCE:
|
||||
* Test StopInstance(), which closes the listening socket and
|
||||
* Test StopServer(), which closes the listening socket and
|
||||
* disconnects all its clients.
|
||||
*/
|
||||
static void
|
||||
|
|
@ -769,14 +864,22 @@ test_stop_server (Fixture *f,
|
|||
GDBusProxy *attacker_proxy;
|
||||
GSocket *client_socket;
|
||||
GSocketAddress *socket_address;
|
||||
GUnixFDList *fds = NULL;
|
||||
GVariant *tuple;
|
||||
GVariant *creator;
|
||||
GVariant *parameters;
|
||||
GVariant *asv;
|
||||
GVariantDict dict;
|
||||
GVariantDict named_argument_builder;
|
||||
gchar *error_name;
|
||||
gchar *stringified_result;
|
||||
const gchar *confined_unique_name;
|
||||
const gchar *name_owner;
|
||||
gboolean gone = FALSE;
|
||||
guint name_watch;
|
||||
const char *type;
|
||||
const char *app_id;
|
||||
const char *instance_id;
|
||||
guint i;
|
||||
guint32 uid;
|
||||
|
||||
g_assert_nonnull (config);
|
||||
|
||||
|
|
@ -791,12 +894,43 @@ test_stop_server (Fixture *f,
|
|||
&f->error);
|
||||
g_assert_no_error (f->error);
|
||||
|
||||
parameters = g_variant_new ("(ssa{sv}a{sv})",
|
||||
g_variant_dict_init (&named_argument_builder, NULL);
|
||||
fds = g_unix_fd_list_new ();
|
||||
|
||||
if (config->stop_server == STOP_SERVER_VIA_NOTIFY_NOT_MANAGER)
|
||||
g_variant_dict_insert (&named_argument_builder, "StopOnDisconnect",
|
||||
"b", FALSE);
|
||||
|
||||
if (config->stop_server == STOP_SERVER_VIA_NOTIFY ||
|
||||
config->stop_server == STOP_SERVER_VIA_NOTIFY_NOT_MANAGER)
|
||||
{
|
||||
DBusError error = DBUS_ERROR_INIT;
|
||||
int notify_pipe[2];
|
||||
int fd_index;
|
||||
|
||||
_dbus_unix_make_pipe (notify_pipe, &error);
|
||||
test_assert_no_error (&error);
|
||||
|
||||
/* transfer ownership */
|
||||
f->stop_on_notify_pipe_write_end = notify_pipe[1];
|
||||
|
||||
/* duplicate into the fd list and close the original */
|
||||
fd_index = g_unix_fd_list_append (fds, notify_pipe[0], &f->error);
|
||||
g_assert_no_error (f->error);
|
||||
g_assert_cmpint (fd_index, >=, 0);
|
||||
close (notify_pipe[0]);
|
||||
|
||||
g_variant_dict_insert (&named_argument_builder, "StopOnNotify",
|
||||
"h", fd_index);
|
||||
}
|
||||
|
||||
parameters = g_variant_new ("(sssa{sv}@a{sv})",
|
||||
"com.example.NotFlatpak",
|
||||
"sample-app",
|
||||
"",
|
||||
NULL, /* no metadata */
|
||||
NULL); /* no named arguments */
|
||||
if (!add_container_server (f, g_steal_pointer (¶meters)))
|
||||
g_variant_dict_end (&named_argument_builder));
|
||||
if (!add_container_server (f, g_steal_pointer (¶meters), fds, NULL))
|
||||
return;
|
||||
|
||||
socket_address = g_unix_socket_address_new (f->socket_path);
|
||||
|
|
@ -813,6 +947,9 @@ test_stop_server (Fixture *f,
|
|||
|
||||
if (config->stop_server == STOP_SERVER_DISCONNECT_FIRST)
|
||||
{
|
||||
guint name_watch;
|
||||
gboolean gone = FALSE;
|
||||
|
||||
g_test_message ("Disconnecting confined connection...");
|
||||
gone = FALSE;
|
||||
confined_unique_name = g_dbus_connection_get_unique_name (
|
||||
|
|
@ -836,7 +973,7 @@ test_stop_server (Fixture *f,
|
|||
}
|
||||
|
||||
/* If we are able to switch uid (i.e. we are root), check that a local
|
||||
* attacker with a different uid cannot close our container instances. */
|
||||
* attacker with a different uid cannot close our container servers. */
|
||||
attacker = test_try_connect_gdbus_as_user (f->bus_address, TEST_USER_OTHER,
|
||||
&f->error);
|
||||
|
||||
|
|
@ -851,15 +988,15 @@ test_stop_server (Fixture *f,
|
|||
g_assert_no_error (f->error);
|
||||
|
||||
tuple = g_dbus_proxy_call_sync (attacker_proxy, "StopListening",
|
||||
g_variant_new ("(o)", f->instance_path),
|
||||
g_variant_new ("(o)", f->server_path),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL,
|
||||
&f->error);
|
||||
g_assert_error (f->error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED);
|
||||
g_assert_null (tuple);
|
||||
g_clear_error (&f->error);
|
||||
|
||||
tuple = g_dbus_proxy_call_sync (attacker_proxy, "StopInstance",
|
||||
g_variant_new ("(o)", f->instance_path),
|
||||
tuple = g_dbus_proxy_call_sync (attacker_proxy, "StopServer",
|
||||
g_variant_new ("(o)", f->server_path),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL,
|
||||
&f->error);
|
||||
g_assert_error (f->error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED);
|
||||
|
|
@ -880,46 +1017,32 @@ test_stop_server (Fixture *f,
|
|||
g_clear_error (&f->error);
|
||||
}
|
||||
|
||||
g_assert_false (g_hash_table_contains (f->containers_removed,
|
||||
f->instance_path));
|
||||
g_assert_false (g_hash_table_contains (f->servers_removed,
|
||||
f->server_path));
|
||||
|
||||
switch (config->stop_server)
|
||||
{
|
||||
case STOP_SERVER_WITH_MANAGER:
|
||||
/* Close the unconfined connection (the container manager) and wait
|
||||
* for it to go away */
|
||||
g_test_message ("Closing container manager...");
|
||||
name_watch = g_bus_watch_name_on_connection (f->confined_conn,
|
||||
f->unconfined_unique_name,
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
NULL,
|
||||
name_gone_set_boolean_cb,
|
||||
&gone, NULL);
|
||||
fixture_disconnect_unconfined (f);
|
||||
|
||||
g_test_message ("Waiting for container manager bus name to disappear...");
|
||||
|
||||
while (!gone)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
g_bus_unwatch_name (name_watch);
|
||||
g_test_message ("Stopping server (but not confined connection) by "
|
||||
"disconnecting container manager from bus");
|
||||
fixture_disconnect_unconfined_and_wait (f);
|
||||
break;
|
||||
|
||||
case STOP_SERVER_EXPLICITLY:
|
||||
g_test_message ("Stopping server (but not confined connection)...");
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "StopListening",
|
||||
g_variant_new ("(o)", f->instance_path),
|
||||
g_variant_new ("(o)", f->server_path),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL,
|
||||
&f->error);
|
||||
g_assert_no_error (f->error);
|
||||
g_variant_unref (tuple);
|
||||
|
||||
/* The container instance remains open, because the connection has
|
||||
/* The container server remains open, because the connection has
|
||||
* not gone away yet. Do another method call: if we were going to
|
||||
* get the signal, it would arrive before the reply to this second
|
||||
* method call. Any method will do here, even one that doesn't
|
||||
* exist. */
|
||||
g_test_message ("Checking we do not get InstanceRemoved...");
|
||||
g_test_message ("Checking we do not get ServerRemoved...");
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "NoSuchMethod", NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL,
|
||||
&f->error);
|
||||
|
|
@ -928,33 +1051,49 @@ test_stop_server (Fixture *f,
|
|||
g_clear_error (&f->error);
|
||||
break;
|
||||
|
||||
case STOP_SERVER_VIA_NOTIFY_NOT_MANAGER:
|
||||
fixture_disconnect_unconfined_and_wait (f);
|
||||
|
||||
/* Assert that the server is still functional at this point,
|
||||
* because we configured it with StopOnDisconnect=FALSE */
|
||||
g_assert_true (g_file_test (f->socket_path, G_FILE_TEST_EXISTS));
|
||||
/* fall through */
|
||||
|
||||
case STOP_SERVER_VIA_NOTIFY:
|
||||
g_test_message ("Stopping server (but not confined connection) by "
|
||||
"closing pipe fd");
|
||||
g_close (f->stop_on_notify_pipe_write_end, &f->error);
|
||||
g_assert_no_error (f->error);
|
||||
f->stop_on_notify_pipe_write_end = -1;
|
||||
break;
|
||||
|
||||
case STOP_SERVER_DISCONNECT_FIRST:
|
||||
case STOP_SERVER_NEVER_CONNECTED:
|
||||
g_test_message ("Stopping server (with no confined connections)...");
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "StopListening",
|
||||
g_variant_new ("(o)", f->instance_path),
|
||||
g_variant_new ("(o)", f->server_path),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL,
|
||||
&f->error);
|
||||
g_assert_no_error (f->error);
|
||||
g_variant_unref (tuple);
|
||||
|
||||
g_test_message ("Waiting for InstanceRemoved...");
|
||||
while (!g_hash_table_contains (f->containers_removed, f->instance_path))
|
||||
g_test_message ("Waiting for ServerRemoved...");
|
||||
while (!g_hash_table_contains (f->servers_removed, f->server_path))
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
break;
|
||||
|
||||
case STOP_SERVER_FORCE:
|
||||
g_test_message ("Stopping server and all confined connections...");
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "StopInstance",
|
||||
g_variant_new ("(o)", f->instance_path),
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "StopServer",
|
||||
g_variant_new ("(o)", f->server_path),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL,
|
||||
&f->error);
|
||||
g_assert_no_error (f->error);
|
||||
g_variant_unref (tuple);
|
||||
|
||||
g_test_message ("Waiting for InstanceRemoved...");
|
||||
while (!g_hash_table_contains (f->containers_removed, f->instance_path))
|
||||
g_test_message ("Waiting for ServerRemoved...");
|
||||
while (!g_hash_table_contains (f->servers_removed, f->server_path))
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
break;
|
||||
|
|
@ -1034,6 +1173,8 @@ test_stop_server (Fixture *f,
|
|||
break;
|
||||
|
||||
case STOP_SERVER_EXPLICITLY:
|
||||
case STOP_SERVER_VIA_NOTIFY:
|
||||
case STOP_SERVER_VIA_NOTIFY_NOT_MANAGER:
|
||||
case STOP_SERVER_WITH_MANAGER:
|
||||
g_test_message ("Checking that the confined app still works...");
|
||||
tuple = g_dbus_connection_call_sync (f->confined_conn,
|
||||
|
|
@ -1053,18 +1194,34 @@ test_stop_server (Fixture *f,
|
|||
g_assert_cmpstr (name_owner, ==, DBUS_SERVICE_DBUS);
|
||||
g_clear_pointer (&tuple, g_variant_unref);
|
||||
|
||||
/* The container instance will not disappear from the bus
|
||||
/* The container server will not disappear from the bus
|
||||
* until the confined connection goes away */
|
||||
tuple = g_dbus_proxy_call_sync (f->observer_proxy, "GetInstanceInfo",
|
||||
g_variant_new ("(o)", f->instance_path),
|
||||
tuple = g_dbus_proxy_call_sync (f->observer_proxy, "GetServerInfo",
|
||||
g_variant_new ("(o)", f->server_path),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL,
|
||||
&f->error);
|
||||
g_assert_no_error (f->error);
|
||||
g_assert_nonnull (tuple);
|
||||
stringified_result = g_variant_print (tuple, TRUE);
|
||||
g_test_message ("GetServerInfo() -> %s", stringified_result);
|
||||
g_free (stringified_result);
|
||||
g_assert_cmpstr (g_variant_get_type_string (tuple), ==, "(a{sv}sssa{sv})");
|
||||
g_variant_get (tuple, "(@a{sv}&s&s&s@a{sv})",
|
||||
&creator, &type, &app_id, &instance_id, &asv);
|
||||
g_variant_dict_init (&dict, creator);
|
||||
g_assert_true (g_variant_dict_lookup (&dict, "UnixUserID", "u", &uid));
|
||||
g_assert_cmpuint (uid, ==, _dbus_getuid ());
|
||||
g_variant_dict_clear (&dict);
|
||||
g_assert_cmpstr (type, ==, "com.example.NotFlatpak");
|
||||
g_assert_cmpstr (app_id, ==, "sample-app");
|
||||
g_assert_cmpstr (instance_id, ==, "");
|
||||
g_assert_cmpuint (g_variant_n_children (asv), ==, 0);
|
||||
g_clear_pointer (&asv, g_variant_unref);
|
||||
g_clear_pointer (&creator, g_variant_unref);
|
||||
g_clear_pointer (&tuple, g_variant_unref);
|
||||
|
||||
/* Now disconnect the last confined connection, which will make the
|
||||
* container instance go away */
|
||||
* container server go away */
|
||||
g_test_message ("Closing confined connection...");
|
||||
g_dbus_connection_close_sync (f->confined_conn, NULL, &f->error);
|
||||
g_assert_no_error (f->error);
|
||||
|
|
@ -1076,12 +1233,12 @@ test_stop_server (Fixture *f,
|
|||
|
||||
/* Whatever happened above, by now it has gone away */
|
||||
|
||||
g_test_message ("Waiting for InstanceRemoved...");
|
||||
while (!g_hash_table_contains (f->containers_removed, f->instance_path))
|
||||
g_test_message ("Waiting for ServerRemoved...");
|
||||
while (!g_hash_table_contains (f->servers_removed, f->server_path))
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
tuple = g_dbus_proxy_call_sync (f->observer_proxy, "GetInstanceInfo",
|
||||
g_variant_new ("(o)", f->instance_path),
|
||||
tuple = g_dbus_proxy_call_sync (f->observer_proxy, "GetServerInfo",
|
||||
g_variant_new ("(o)", f->server_path),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL,
|
||||
&f->error);
|
||||
g_assert_nonnull (f->error);
|
||||
|
|
@ -1099,7 +1256,7 @@ test_stop_server (Fixture *f,
|
|||
|
||||
/*
|
||||
* Assert that we cannot get the container metadata for a path that
|
||||
* isn't a container instance, or a bus name that isn't in a container
|
||||
* isn't a container server, or a bus name that isn't in a container
|
||||
* or doesn't exist at all.
|
||||
*/
|
||||
static void
|
||||
|
|
@ -1119,7 +1276,7 @@ test_invalid_metadata_getters (Fixture *f,
|
|||
|
||||
g_test_message ("Inspecting unconfined connection");
|
||||
unique_name = g_dbus_connection_get_unique_name (f->unconfined_conn);
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInstance",
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInfo",
|
||||
g_variant_new ("(s)", unique_name),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error);
|
||||
g_assert_nonnull (f->error);
|
||||
|
|
@ -1135,7 +1292,7 @@ test_invalid_metadata_getters (Fixture *f,
|
|||
g_clear_error (&f->error);
|
||||
|
||||
g_test_message ("Inspecting dbus-daemon");
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInstance",
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInfo",
|
||||
g_variant_new ("(s)", DBUS_SERVICE_DBUS),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error);
|
||||
g_assert_nonnull (f->error);
|
||||
|
|
@ -1152,7 +1309,7 @@ test_invalid_metadata_getters (Fixture *f,
|
|||
|
||||
g_test_message ("Inspecting a non-connection");
|
||||
unique_name = g_dbus_connection_get_unique_name (f->unconfined_conn);
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInstance",
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetConnectionInfo",
|
||||
g_variant_new ("(s)", "com.example.Nope"),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error);
|
||||
g_assert_nonnull (f->error);
|
||||
|
|
@ -1168,8 +1325,8 @@ test_invalid_metadata_getters (Fixture *f,
|
|||
g_clear_error (&f->error);
|
||||
|
||||
|
||||
g_test_message ("Inspecting container instance info");
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetInstanceInfo",
|
||||
g_test_message ("Inspecting container server info");
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "GetServerInfo",
|
||||
g_variant_new ("(o)", "/nope"),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, NULL, &f->error);
|
||||
g_assert_nonnull (f->error);
|
||||
|
|
@ -1213,9 +1370,10 @@ test_unsupported_parameter (Fixture *f,
|
|||
"ThisArgumentIsntImplemented",
|
||||
"b", FALSE);
|
||||
|
||||
parameters = g_variant_new ("(ssa{sv}@a{sv})",
|
||||
parameters = g_variant_new ("(sssa{sv}@a{sv})",
|
||||
"com.example.NotFlatpak",
|
||||
"sample-app",
|
||||
"",
|
||||
NULL, /* no metadata */
|
||||
g_variant_dict_end (&named_argument_builder));
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "AddServer",
|
||||
|
|
@ -1253,9 +1411,10 @@ test_invalid_type_name (Fixture *f,
|
|||
NULL, &f->error);
|
||||
g_assert_no_error (f->error);
|
||||
|
||||
parameters = g_variant_new ("(ssa{sv}a{sv})",
|
||||
parameters = g_variant_new ("(sssa{sv}a{sv})",
|
||||
"this is not a valid container type name",
|
||||
"sample-app",
|
||||
"",
|
||||
NULL, /* no metadata */
|
||||
NULL); /* no named arguments */
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "AddServer",
|
||||
|
|
@ -1288,12 +1447,13 @@ test_invalid_nesting (Fixture *f,
|
|||
if (f->skip)
|
||||
return;
|
||||
|
||||
parameters = g_variant_new ("(ssa{sv}a{sv})",
|
||||
parameters = g_variant_new ("(sssa{sv}a{sv})",
|
||||
"com.example.NotFlatpak",
|
||||
"sample-app",
|
||||
"instance0",
|
||||
NULL, /* no metadata */
|
||||
NULL); /* no named arguments */
|
||||
if (!add_container_server (f, g_steal_pointer (¶meters)))
|
||||
if (!add_container_server (f, g_steal_pointer (¶meters), NULL, NULL))
|
||||
return;
|
||||
|
||||
g_test_message ("Connecting to %s...", f->socket_dbus_address);
|
||||
|
|
@ -1312,9 +1472,10 @@ test_invalid_nesting (Fixture *f,
|
|||
&f->error);
|
||||
g_assert_no_error (f->error);
|
||||
|
||||
parameters = g_variant_new ("(ssa{sv}a{sv})",
|
||||
parameters = g_variant_new ("(sssa{sv}a{sv})",
|
||||
"com.example.NotFlatpak",
|
||||
"inner-app",
|
||||
"instance1",
|
||||
NULL, /* no metadata */
|
||||
NULL); /* no named arguments */
|
||||
tuple = g_dbus_proxy_call_sync (nested_proxy, "AddServer",
|
||||
|
|
@ -1361,9 +1522,10 @@ test_max_containers (Fixture *f,
|
|||
NULL, &f->error);
|
||||
g_assert_no_error (f->error);
|
||||
|
||||
parameters = g_variant_new ("(ssa{sv}a{sv})",
|
||||
parameters = g_variant_new ("(sssa{sv}a{sv})",
|
||||
"com.example.NotFlatpak",
|
||||
"sample-app",
|
||||
"instance1",
|
||||
NULL, /* no metadata */
|
||||
NULL); /* no named arguments */
|
||||
/* We will reuse this variant several times, so don't use floating refs */
|
||||
|
|
@ -1377,7 +1539,7 @@ test_max_containers (Fixture *f,
|
|||
NULL, &f->error);
|
||||
g_assert_no_error (f->error);
|
||||
g_assert_nonnull (tuple);
|
||||
g_variant_get (tuple, "(o^ays)", &placeholders[i], NULL, NULL);
|
||||
g_variant_get (tuple, "(o@a{sv})", &placeholders[i], NULL);
|
||||
g_variant_unref (tuple);
|
||||
g_test_message ("Placeholder server at %s", placeholders[i]);
|
||||
}
|
||||
|
|
@ -1458,7 +1620,6 @@ test_max_connections_per_container (Fixture *f,
|
|||
* limit-containers.conf */
|
||||
GSocket *placeholders[G_N_ELEMENTS (socket_paths) * 3] = { NULL };
|
||||
GVariant *parameters;
|
||||
GVariant *tuple;
|
||||
guint i;
|
||||
|
||||
if (f->skip)
|
||||
|
|
@ -1471,9 +1632,10 @@ test_max_connections_per_container (Fixture *f,
|
|||
NULL, &f->error);
|
||||
g_assert_no_error (f->error);
|
||||
|
||||
parameters = g_variant_new ("(ssa{sv}a{sv})",
|
||||
parameters = g_variant_new ("(sssa{sv}a{sv})",
|
||||
"com.example.NotFlatpak",
|
||||
"sample-app",
|
||||
"",
|
||||
NULL, /* no metadata */
|
||||
NULL); /* no named arguments */
|
||||
/* We will reuse this variant several times, so don't use floating refs */
|
||||
|
|
@ -1481,13 +1643,25 @@ test_max_connections_per_container (Fixture *f,
|
|||
|
||||
for (i = 0; i < G_N_ELEMENTS (socket_paths); i++)
|
||||
{
|
||||
GVariant *tuple;
|
||||
GVariant *named_results;
|
||||
gboolean found;
|
||||
|
||||
tuple = g_dbus_proxy_call_sync (f->proxy, "AddServer",
|
||||
parameters, G_DBUS_CALL_FLAGS_NONE, -1,
|
||||
NULL, &f->error);
|
||||
g_assert_no_error (f->error);
|
||||
g_assert_nonnull (tuple);
|
||||
g_variant_get (tuple, "(o^ays)", NULL, &socket_paths[i],
|
||||
&dbus_addresses[i]);
|
||||
g_variant_get (tuple, "(o@a{sv})", NULL, &named_results);
|
||||
|
||||
found = g_variant_lookup (named_results, "Address",
|
||||
"s", &dbus_addresses[i]);
|
||||
g_assert_true (found);
|
||||
found = g_variant_lookup (named_results, "SocketPath",
|
||||
"^ay", &socket_paths[i]);
|
||||
g_assert_true (found);
|
||||
|
||||
g_variant_unref (named_results);
|
||||
g_variant_unref (tuple);
|
||||
socket_addresses[i] = g_unix_socket_address_new (socket_paths[i]);
|
||||
g_test_message ("Server #%u at %s", i, socket_paths[i]);
|
||||
|
|
@ -1621,9 +1795,10 @@ test_max_container_metadata_bytes (Fixture *f,
|
|||
1));
|
||||
|
||||
/* Floating reference, call_..._sync takes ownership */
|
||||
parameters = g_variant_new ("(ss@a{sv}a{sv})",
|
||||
parameters = g_variant_new ("(sss@a{sv}a{sv})",
|
||||
"com.wasteheadquarters",
|
||||
"Packt Like Sardines in a Crushd Tin Box",
|
||||
"",
|
||||
g_variant_dict_end (&dict),
|
||||
NULL); /* no named arguments */
|
||||
|
||||
|
|
@ -1645,7 +1820,7 @@ teardown (Fixture *f,
|
|||
g_clear_object (&f->proxy);
|
||||
|
||||
fixture_disconnect_observer (f);
|
||||
g_clear_pointer (&f->containers_removed, g_hash_table_unref);
|
||||
g_clear_pointer (&f->servers_removed, g_hash_table_unref);
|
||||
|
||||
if (f->libdbus_observer != NULL)
|
||||
{
|
||||
|
|
@ -1680,8 +1855,17 @@ teardown (Fixture *f,
|
|||
f->daemon_pid = 0;
|
||||
}
|
||||
|
||||
if (f->stop_on_notify_pipe_write_end >= 0)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
g_close (f->stop_on_notify_pipe_write_end, &error);
|
||||
g_assert_no_error (error);
|
||||
f->stop_on_notify_pipe_write_end = -1;
|
||||
}
|
||||
|
||||
dbus_clear_message (&f->latest_shout);
|
||||
g_free (f->instance_path);
|
||||
g_free (f->server_path);
|
||||
g_free (f->socket_path);
|
||||
g_free (f->socket_dbus_address);
|
||||
g_free (f->bus_address);
|
||||
|
|
@ -1710,6 +1894,16 @@ static const Config stop_server_force =
|
|||
"valid-config-files/multi-user.conf",
|
||||
STOP_SERVER_FORCE
|
||||
};
|
||||
static const Config stop_server_via_notify =
|
||||
{
|
||||
"valid-config-files/multi-user.conf",
|
||||
STOP_SERVER_VIA_NOTIFY
|
||||
};
|
||||
static const Config stop_server_not_with_manager =
|
||||
{
|
||||
"valid-config-files/multi-user.conf",
|
||||
STOP_SERVER_VIA_NOTIFY_NOT_MANAGER
|
||||
};
|
||||
static const Config stop_server_with_manager =
|
||||
{
|
||||
"valid-config-files/multi-user.conf",
|
||||
|
|
@ -1769,6 +1963,10 @@ main (int argc,
|
|||
&stop_server_never_connected, setup, test_stop_server, teardown);
|
||||
g_test_add ("/containers/stop-server/force", Fixture,
|
||||
&stop_server_force, setup, test_stop_server, teardown);
|
||||
g_test_add ("/containers/stop-server/via-notify", Fixture,
|
||||
&stop_server_via_notify, setup, test_stop_server, teardown);
|
||||
g_test_add ("/containers/stop-server/not-with-manager", Fixture,
|
||||
&stop_server_not_with_manager, setup, test_stop_server, teardown);
|
||||
g_test_add ("/containers/stop-server/with-manager", Fixture,
|
||||
&stop_server_with_manager, setup, test_stop_server, teardown);
|
||||
g_test_add ("/containers/metadata", Fixture, &limit_containers,
|
||||
|
|
|
|||
|
|
@ -13,4 +13,9 @@
|
|||
<!-- 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>
|
||||
|
|
|
|||
|
|
@ -57,4 +57,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>
|
||||
|
|
|
|||
|
|
@ -637,6 +637,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1170,9 +1170,9 @@ _dbus_message_test (const char *test_data_dir _DBUS_GNUC_UNUSED)
|
|||
_dbus_assert (strcmp (dbus_message_get_path (message),
|
||||
"/foo") == 0);
|
||||
|
||||
if (!dbus_message_set_container_instance (message, "/org/freedesktop/DBus/Containers1/c42"))
|
||||
if (!dbus_message_set_container_path (message, "/org/freedesktop/DBus/Containers1/c42"))
|
||||
_dbus_test_fatal ("out of memory");
|
||||
_dbus_assert (strcmp (dbus_message_get_container_instance (message),
|
||||
_dbus_assert (strcmp (dbus_message_get_container_path (message),
|
||||
"/org/freedesktop/DBus/Containers1/c42") == 0);
|
||||
|
||||
if (!dbus_message_set_interface (message, "org.Foo"))
|
||||
|
|
|
|||
|
|
@ -377,6 +377,7 @@ case "$ci_buildsys" in
|
|||
fi
|
||||
|
||||
set -- -Db_pie=true "$@"
|
||||
set -- -Dcontainers=true "$@"
|
||||
set -- -Duser_session=true "$@"
|
||||
;;
|
||||
esac
|
||||
|
|
@ -401,6 +402,7 @@ case "$ci_buildsys" in
|
|||
set "$@" -Dlibaudit=disabled -Dvalgrind=disabled
|
||||
# Disable optional features, some of which are on by
|
||||
# default
|
||||
set "$@" -Dcontainers=false
|
||||
set "$@" -Dstats=false
|
||||
set "$@" -Duser_session=false
|
||||
shift
|
||||
|
|
@ -462,6 +464,12 @@ case "$ci_buildsys" in
|
|||
$meson_setup "$@" "$srcdir"
|
||||
meson compile -v
|
||||
|
||||
if [ "$(id -u)" = 0 ]; then
|
||||
# In production, this would be /run/dbus/containers and would
|
||||
# have been set up by the init script or tmpfiles.d
|
||||
mkdir -p /var/local/run/dbus/containers
|
||||
fi
|
||||
|
||||
# This is too slow and verbose to keep enabled at the moment
|
||||
export DBUS_TEST_MALLOC_FAILURES=0
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue