#include "dbus-marshal-gvariant.h"
#include "dbus-marshal-validate.h"
#include "dbus-asv-util.h"
-#include "kdbus.h"
+#include <linux/kdbus.h>
#include "dbus-watch.h"
#include "dbus-errors.h"
#include "dbus-bus.h"
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
-# if defined(__arm__) || defined(__aarch64__)
+# if defined(__arm__)
# define __NR_memfd_create 385
-# elif defined(__i386__)
+# elif defined(__aarch64__)
# define __NR_memfd_create 279
+# elif defined(__i386__)
+# define __NR_memfd_create 356
+# elif defined(__x86_64__)
+# define __NR_memfd_create 319
# else
# error "Architecture not supported"
# endif
((uint8_t *)(iter) < (uint8_t *)(first) + (_size)) && \
((uint8_t *)(iter) >= (uint8_t *)(first)); \
iter = (void*)(((uint8_t *)iter) + ALIGN8((iter)->size)))
-#define KDBUS_DEFAULT_TIMEOUT_NS 50000000000LLU
+#define KDBUS_INFINITE_TIMEOUT_NS 0x3fffffffffffffffLLU
/**
* @defgroup DBusTransportKdbus DBusTransport implementations for kdbus
if (errMessage == NULL)
return NULL;
- if (sender)
- dbus_message_set_sender (errMessage, sender);
+ if (sender && !dbus_message_set_sender (errMessage, sender))
+ {
+ _dbus_verbose ("oom");
+ dbus_message_unref (errMessage);
+ return NULL;
+ }
return errMessage;
}
{
case ENXIO: /* no such id on the bus */
case ESRCH:
- dbus_set_error (error,
- DBUS_ERROR_NAME_HAS_NO_OWNER,
- "Name \"%s\" does not exist",
- destination);
- break;
-
- case EADDRNOTAVAIL:
- case ECONNRESET:
- /* when well known name is not available on the bus */
if (is_auto_start)
dbus_set_error (error,
DBUS_ERROR_SERVICE_UNKNOWN,
destination);
break;
- case EMLINK:
+ case EADDRNOTAVAIL:
+ dbus_set_error (error,
+ DBUS_ERROR_SERVICE_UNKNOWN,
+ "No support for activation for name: \"%s\"", destination);
+ break;
+
+ case EXFULL:
dbus_set_error (error,
DBUS_ERROR_LIMITS_EXCEEDED,
- "The maximum number of pending replies per connection has been reached");
+ "The memory pool of the receiver is full");
break;
case ENOBUFS:
- case EXFULL:
dbus_set_error (error,
DBUS_ERROR_LIMITS_EXCEEDED,
- "No space in receiver's buffer");
+ "Too many pending messages on the receiver side");
+ break;
+
+ case EMSGSIZE:
+ dbus_set_error (error,
+ DBUS_ERROR_LIMITS_EXCEEDED,
+ "The size of the message is excessive");
+ break;
+
+ case EMLINK:
+ dbus_set_error (error,
+ DBUS_ERROR_LIMITS_EXCEEDED,
+ "The maximum number of pending replies per connection has been reached");
break;
case ETIMEDOUT:
dbus_set_error (error,
DBUS_ERROR_TIMEOUT,
- "Connection does not receive a reply");
+ "Timeout was reached");
+ break;
+
+ case EPERM:
+ dbus_set_error (error,
+ DBUS_ERROR_ACCESS_DENIED,
+ "Permission denied");
break;
default:
* Otherwise - check the policy.
*/
if (0 == reply_serial)
- ret = dbuspolicy1_check_out (transport->policy,
- dbus_message_get_destination (message),
- dbus_message_get_sender (message),
- dbus_message_get_path (message),
- dbus_message_get_interface (message),
- dbus_message_get_member (message),
- dbus_message_get_type (message),
- dbus_message_get_error_name (message),
- reply_serial,
- !dbus_message_get_no_reply (message));
+ {
+ /* If method call or unicast signal, check policy */
+ if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
+ (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL &&
+ dbus_message_get_destination (message) != NULL))
+ ret = dbuspolicy1_check_out (transport->policy,
+ dbus_message_get_destination (message),
+ transport->my_DBus_unique_name,
+ dbus_message_get_path (message),
+ dbus_message_get_interface (message),
+ dbus_message_get_member (message),
+ dbus_message_get_type (message),
+ dbus_message_get_error_name (message),
+ reply_serial,
+ !dbus_message_get_no_reply (message));
+ }
}
return ret;
unsigned fds_count;
const char* header_data;
DBusError error;
+ const char *destination_name = destination;
dbus_uint64_t items_size;
dbus_uint64_t flags = 0;
else /* method calls */
{
long tv_sec, tv_usec;
+ int timeout_ms = _dbus_message_get_timeout_ms(message);
_dbus_get_monotonic_time (&tv_sec, &tv_usec);
/* ms us ns */
- timeout_ns_or_cookie_reply = (dbus_uint64_t)tv_sec * 1000ULL * 1000ULL * 1000ULL
- + tv_usec * 1000ULL
- + KDBUS_DEFAULT_TIMEOUT_NS;
+ timeout_ns_or_cookie_reply = 1U | ( /* ensure nonzero */
+ (dbus_uint64_t)tv_sec * 1000ULL * 1000ULL * 1000ULL
+ + tv_usec * 1000ULL + (
+ timeout_ms == -1 ? _DBUS_DEFAULT_TIMEOUT_VALUE * 1000000LLU :
+ timeout_ms == DBUS_TIMEOUT_INFINITE ? KDBUS_INFINITE_TIMEOUT_NS :
+ (uint64_t)timeout_ms * 1000000U
+ )
+ );
flags |= KDBUS_MSG_EXPECT_REPLY;
}
if (body_size > 0)
{
const char* body_data = _dbus_string_get_const_data (body);
+ size_t body_offsets_size;
+ const char *footer_ptr;
+
+ /* determine body offsets size */
+ if (ret_size <= 0xFF)
+ body_offsets_size = 1;
+ else if (ret_size <= 0xFFFF)
+ body_offsets_size = 2;
+ else if (ret_size <= 0xFFFFFFFF)
+ body_offsets_size = 4;
+ else
+ body_offsets_size = 8;
+
+ /* check footer size */
+ footer_ptr = body_data + body_size - body_offsets_size -1;
+ while (footer_ptr >= body_data && (*footer_ptr) != 0)
+ footer_ptr--;
+
+ if (footer_ptr < body_data)
+ {
+ ret_size = -1;
+ goto out;
+ }
#ifdef DBUS_ENABLE_VERBOSE_MODE
if (-1 != debug)
if (memfd >= 0)
{
-
- size_t body_offsets_size;
- const char *footer_ptr;
-
- /* determine body offsets size */
- if (ret_size <= 0xFF)
- body_offsets_size = 1;
- else if (ret_size <= 0xFFFF)
- body_offsets_size = 2;
- else if (ret_size <= 0xFFFFFFFF)
- body_offsets_size = 4;
- else
- body_offsets_size = 8;
-
- /* check footer size */
- footer_ptr = body_data + body_size - body_offsets_size -1;
- while (footer_ptr >= body_data && (*footer_ptr) != 0)
- footer_ptr--;
-
- if (footer_ptr < body_data)
- {
- ret_size = -1;
- goto out;
- }
-
/* prepare memfd for body */
- if (prepare_mfd (memfd,
+ if (-1 == prepare_mfd (memfd,
body_data,
- (footer_ptr - body_data) * sizeof(char)) == -1)
+ (uint64_t)((footer_ptr - body_data) * sizeof(char))))
{
ret_size = -1;
goto out;
}
- /* body */
+ /* body */
item = _kdbus_item_add_payload_memfd (item,
0,
(footer_ptr - body_data) * sizeof(char),
memfd);
- /* footer */
+ /* footer */
item = _kdbus_item_add_payload_vec (item,
(body_data + body_size - footer_ptr) * sizeof(char),
(uintptr_t)footer_ptr);
{
while (body_size > 0)
{
- dbus_uint64_t part_size = body_size;
+ dbus_uint32_t part_size;
- if (part_size > KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE)
- part_size = KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE;
+ if (body_size < KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE)
+ part_size = body_size;
+ else
+ part_size = KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE;
+
+ /* we need to adjust part size if footer does not fit as a whole */
+ if (body_size - part_size > 0 && footer_ptr < (body_data + part_size))
+ part_size = footer_ptr - body_data;
_dbus_verbose ("attaching body part\n");
item = _kdbus_item_add_payload_vec (item,
break;
case DBUSPOLICY_RESULT_DEST_NOT_AVAILABLE:
- reply = reply_with_error (DBUS_ERROR_SERVICE_UNKNOWN, NULL,
- "Cannot send message - destination not known",
- message);
+ _dbus_assert (destination_name != NULL);
+ if (dbus_message_get_auto_start (message))
+ reply = reply_with_error (DBUS_ERROR_SERVICE_UNKNOWN, NULL,
+ "Cannot send message - destination not known",
+ message);
+ else
+ reply = reply_with_error (DBUS_ERROR_NAME_HAS_NO_OWNER, "Name \"%s\" does not exist",
+ destination_name,
+ message);
break;
case DBUSPOLICY_RESULT_KDBUS_ERROR:
NULL,
error.message,
message);
+ dbus_error_free(&error);
}
if (reply == NULL)
/* alloc palce for fds */
fds = dbus_malloc (sizeof (int) * (n_fds + 1));
+ if (fds == NULL)
+ {
+ ret_size = -1;
+ kdbus_close_message (transport, msg_reply);
+ dbus_free (data);
+ goto out;
+ }
/* decode dbus message */
ret = kdbus_decode_dbus_message (msg_reply, data,
{
ret_size = -1;
kdbus_close_message (transport, msg_reply);
+ dbus_free (fds);
dbus_free (data);
goto out;
}
* and configures transport.
* As a result unique id on he bus is obtained.
*
- * @see KDBUS_HELLO_* flags in kdbus.h
+ * @see KDBUS_HELLO_* flags in <linux/kdbus.h>
*
* @param transport transport structure
* @param registration_flags aditional flags to modify registration process
int ret;
dbus_uint64_t flags;
+#ifdef LIBDBUSPOLICY
+ void *policy = dbuspolicy1_init_shared (_kdbus_get_path(transport->kdbus),
+ _kdbus_get_fd(transport->kdbus));
+ if (NULL == policy)
+ {
+ dbus_set_error (error,
+ DBUS_ERROR_NO_REPLY,
+ "Did not receive a reply. Possible causes include: couldn't load dbus policy for kdbus transport or the message bus security policy blocked the reply.");
+ return FALSE;
+ }
+
+ transport->policy = policy;
+#endif
+
flags = KDBUS_HELLO_ACCEPT_FD;
if (registration_flags & REGISTER_FLAG_MONITOR)
flags |= KDBUS_HELLO_MONITOR;
if (ret != 0)
{
dbus_set_error (error, DBUS_ERROR_FAILED, "Hello failed: %d", -ret);
+#ifdef LIBDBUSPOLICY
+ dbuspolicy1_free (policy);
+#endif
return FALSE;
}
+#ifdef LIBDBUSPOLICY
+ dbuspolicy1_init_set_pool (transport->policy, _kdbus_get_pool(transport->kdbus));
+#endif
+
transport->my_DBus_unique_name = create_unique_name_from_unique_id (_kdbus_get_id (transport->kdbus));
if (NULL == transport->my_DBus_unique_name)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "Hello post failed: %d", -ret);
+#ifdef LIBDBUSPOLICY
+ dbuspolicy1_free (policy);
+#endif
return FALSE;
}
rule_cookie = match_rule_get_cookie (rule);
rule_sender = _match_rule_get_sender (rule);
- if (_match_rule_get_args_len(rule) == 1)
- rule_arg0 = _match_rule_get_args(rule, 0);
-
/*
* First check if it is org.freedesktop.DBus's NameOwnerChanged or any
* org.freedesktop.DBus combination that includes this,
&& !strcmp_existing (_match_rule_get_interface (rule), DBUS_INTERFACE_DBUS)
&& !strcmp_existing (_match_rule_get_path (rule), DBUS_PATH_DBUS))
{
+ if (_match_rule_get_args_len(rule) == 1)
+ {
+ rule_arg0 = _match_rule_get_args(rule, 0);
+ if (rule_arg0)
+ {
+ DBusString str;
+ _dbus_string_init_const (&str, rule_arg0);
+ ret = _dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str));
+ if (!ret)
+ return FALSE;
+ }
+ }
if (!strcmp_existing (_match_rule_get_member (rule), "NameOwnerChanged"))
{
ret = _kdbus_add_match_name_change (transport->kdbus,
dbus_bool_t res = _dbus_asv_add_byte_array (&array_iter,
"LinuxSecurityLabel",
info.sec_label,
- strlen (info.sec_label)+1);
+ info.sec_label_len);
dbus_free (info.sec_label);
return NULL;
}
+static dbus_bool_t
+_mac_smack_use (void)
+{
+ static int cached_use = -1;
+
+ if (cached_use < 0)
+ cached_use = access("/sys/fs/smackfs/", F_OK) >= 0;
+
+ return cached_use;
+}
+
static DBusMessage *
capture_org_freedesktop_DBus_GetConnectionSELinuxSecurityContext (DBusTransportKdbus *transport,
DBusMessage *message,
if (info.sec_label != NULL)
{
- DBusMessage *reply;
+ if (_mac_smack_use())
+ {
+ dbus_set_error (error, DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN,
+ "Could not determine security context");
+ dbus_free (info.sec_label);
+ }
+ else
+ {
+ DBusMessage *reply;
- reply = reply_fixed_array (message, DBUS_TYPE_BYTE,
- info.sec_label,
- strlen (info.sec_label)+1);
+ reply = reply_fixed_array (message, DBUS_TYPE_BYTE,
+ info.sec_label,
+ info.sec_label_len);
- dbus_free (info.sec_label);
- return reply;
+ dbus_free (info.sec_label);
+ return reply;
+ }
}
else
{
{
if (item->type == KDBUS_ITEM_OWNED_NAME)
{
- DBusError local_error;
char *name_ptr = item->name.name;
- dbus_error_init ( &local_error );
- if (!dbus_validate_bus_name (name_ptr, &local_error))
+ if (!dbus_validate_bus_name (name_ptr, NULL))
continue;
if (flags & KDBUS_LIST_QUEUED)
if (!dbus_message_iter_append_basic (&array_iter,
DBUS_TYPE_STRING,
&name_ptr))
- goto oom_iterator;
+ {
+ if (flags & KDBUS_LIST_QUEUED)
+ free (name_ptr);
+ goto oom_iterator;
+ }
if (flags & KDBUS_LIST_QUEUED)
free (name_ptr);
dbus_message_lock (sub_message);
- if (kdbus_write_msg_internal (transport, sub_message, name, NULL, FALSE) == -1)
+ ret = kdbus_write_msg_internal (transport, sub_message, name, NULL, FALSE);
+
+ dbus_message_unref (sub_message);
+
+ if (ret == -1)
return NULL;
else
{
int ret = 1;
if (!strcmp (destination, DBUS_SERVICE_DBUS))
{
- if (!strcmp (dbus_message_get_interface (message), DBUS_INTERFACE_DBUS))
+ const char *interface = dbus_message_get_interface (message);
+ if (interface && !strcmp (interface, DBUS_INTERFACE_DBUS))
{
DBusError error;
const char *member = dbus_message_get_member (message);
+ _dbus_assert (member != NULL);
+
dbus_error_init (&error);
if (!strcmp (member, "Hello"))
else
ret = 0;
- } /* id DBUS_INTERFACE_DBUS */
+ } /* if DBUS_INTERFACE_DBUS */
} /* if DBUS_SERVICE_DBUS */
return ret;
_dbus_verbose ("%s\n", const_ptr);
}
- dbus_message_set_sender (message, DBUS_SERVICE_DBUS);
+ if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
+ goto error;
dbus_message_set_serial (message, get_next_client_serial (transport));
if (!add_message_to_received (message, transport->base.connection))
result = FALSE;
- _dbus_string_init (&names);
+ if (!_dbus_string_init (&names))
+ {
+ _dbus_verbose ("oom:_dbus_string_init");
+ return FALSE;
+ }
KDBUS_ITEM_FOREACH(item, msg, items)
switch (item->type)
if (_dbus_validate_bus_name (&name, 0, _dbus_string_get_length (&name)))
{
if (_dbus_string_get_length (&names) != 0)
- _dbus_string_append_byte (&names, ' ');
-
- _dbus_string_copy (&name,
+ {
+ if (!_dbus_string_append_byte (&names, ' '))
+ {
+ _dbus_string_free (&names);
+ return FALSE;
+ }
+ }
+
+ if (!_dbus_string_copy (&name,
0,
&names,
- _dbus_string_get_length (&names));
+ _dbus_string_get_length (&names)))
+ {
+ _dbus_string_free (&names);
+ return FALSE;
+ }
}
}
break;
if (load_dbus_header (transport, &header, message_data, message_len))
got_header = TRUE;
}
-
- if (got_header && _dbus_header_get_message_type (&header) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+ if (got_header &&
+ _dbus_header_get_message_type (&header) != DBUS_MESSAGE_TYPE_METHOD_CALL &&
+ _dbus_header_get_message_type (&header) != DBUS_MESSAGE_TYPE_SIGNAL)
{
result = TRUE;
}
DBUS_HEADER_FIELD_DESTINATION,
DBUS_TYPE_STRING,
&destination);
+ if (!destination)
+ destination = transport->my_DBus_unique_name;
_dbus_header_get_field_basic (&header,
DBUS_HEADER_FIELD_PATH,
{
case KDBUS_ITEM_REPLY_TIMEOUT:
case KDBUS_ITEM_REPLY_DEAD:
- {
- DBusMessage *message = NULL;
- _dbus_verbose (" +%s (%llu bytes) cookie=%llu\n",
- enum_MSG (item->type), item->size, msg->cookie_reply);
-
- message = _dbus_generate_local_error_message (msg->cookie_reply,
- item->type == KDBUS_ITEM_REPLY_TIMEOUT ? DBUS_ERROR_NO_REPLY : DBUS_ERROR_NAME_HAS_NO_OWNER, NULL);
- if (message == NULL)
- {
- ret_size = -1;
- goto out;
- }
-
- dbus_message_set_serial (message, get_next_client_serial (kdbus_transport));
-
- if (!add_message_to_received (message, kdbus_transport->base.connection))
- ret_size = -1;
- }
+ _dbus_verbose (" +%s (%llu bytes) cookie=%llu\n",
+ enum_MSG (item->type), item->size, msg->cookie_reply);
break;
case KDBUS_ITEM_NAME_ADD:
char *data,
DBusTransportKdbus *kdbus_transport,
int *fds,
- int *n_fds,
- DBusError *error)
+ int *n_fds)
{
int ret_size = 0;
int start;
dbus_uint64_t flags = 0;
int ret;
- DBusError error;
-
- dbus_error_init (&error);
start = _dbus_string_get_length (buffer);
}
data = _dbus_string_get_data_len (buffer, start, buf_size);
- ret_size = kdbus_decode_msg (msg, data, kdbus_transport, fds, n_fds, &error);
+ ret_size = kdbus_decode_msg (msg, data, kdbus_transport, fds, n_fds);
if (ret_size == -1) /* error */
_dbus_string_set_length (buffer, start);
return ret_size;
}
+#ifdef ENABLE_KDBUS_SYNC_CALLS
static DBusMessage *
kdbus_send_sync_call (DBusTransportKdbus *transport,
DBusMessage *message)
return reply;
}
+#endif
/**
* Copy-paste from socket transport. Only renames done.
again:
/* See if we've exceeded max messages and need to disable reading */
- if (kdbus_transport->activator == NULL)
- check_read_watch (kdbus_transport);
+ if (kdbus_transport->activator == NULL)
+ check_read_watch (kdbus_transport);
if (total > kdbus_transport->max_bytes_read_per_iteration)
{
oom = TRUE;
goto out;
}
- _dbus_message_loader_get_buffer (transport->loader, &buffer);
+ _dbus_message_loader_get_buffer (transport->loader, &buffer, NULL, NULL);
bytes_read = kdbus_read_message (kdbus_transport, buffer, fds, &n_fds);
* error messages are inserted directly to incoming queue and
* application hangs on dbus_poll.
*
- * This causes a busy loop in _dbus_connection_block_pending_call()
+ * This causes a busy loop in _dbus_connection_block_pending_call()
* There is no case of waiting for the locally-generated error reply
if (_dbus_connection_get_n_incoming (transport->connection) > 0)
return NULL;
}
-static dbus_bool_t
-initialize_policies (DBusTransportKdbus *transport, const char *path)
-{
- dbus_bool_t result = TRUE;
-
-#ifdef LIBDBUSPOLICY
- transport->policy = dbuspolicy1_init (path);
- if (NULL == transport->policy)
- result = FALSE;
-#endif
-
- return result;
-}
-
/**
* Connects to kdbus, creates and sets-up transport.
*
goto failed_0;
}
- kdbus = _kdbus_new ();
+ kdbus = _kdbus_new (path);
if (NULL == kdbus)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed_0;
}
- ret = _kdbus_open (kdbus, path);
+ ret = _kdbus_open (kdbus);
if (ret < 0)
{
dbus_set_error (error,
goto failed_1;
}
- if (!initialize_policies (transport, path))
- {
- dbus_set_error (error,
- DBUS_ERROR_FAILED,
- "Can't load dbus policy for kdbus transport");
- _kdbus_close (kdbus);
- transport_finalize ((DBusTransport*)transport);
- transport = NULL;
- }
-
_dbus_string_free (&address);
return (DBusTransport*)transport;