Updated kernel tree for ELL development
by Mat Martineau
Hello -
I have a kernel.org repo set up now:
https://git.kernel.org/cgit/linux/kernel/git/martineau/linux.git/
The "ell-key-crypto" branch has the patches to enable Diffie-Hellman and
AF_ALG akcipher operations. I will force-push to this branch as the
various patch sets are updated, so if you use this branch as a basis for
your own development you will have to rebase periodically.
To build for your environment, copy your system's current kernel config in
to your kernel working directory and update the kernel configuration:
$ cp /boot/config-<recent kernel-version> .config
$ make olddefconfig
$ scripts/config --enable CONFIG_KEY_DH_OPERATIONS
$ scripts/config --enable CONFIG_CRYPTO_USER_API_AKCIPHER
$ make olddefconfig
The second "make olddefconfig" gives the Kbuild system a chance to check
dependencies.
$ make -j$(nproc) bzImage
$ make -j$(nproc) modules
$ sudo make modules_install
$ sudo make install
I've used this approach with the 4.5 kernel and Fedora 23. I'd expect
things to work smoothly with configs from kernel 4.2/4.3 or newer, but as
you go older than that we'll have to see how things go.
ELL knows how to use the Diffie-Hellman functionality in the above kernel.
I'm working on keyring patches that include certificate validation, and
updating the ELL cipher functions to use the above kernel.
--
Mat Martineau
Intel OTC
6 years, 2 months
[PATCH] build: Add sanitizer options
by Mat Martineau
Build using Address Sanitizer (asan), Leak Sanitizer (lsan), or
Undefined Behavior Sanitizer (ubsan) by using one of these options for
the configure script:
--enable-asan
--enable-lsan
--enable-ubsan
For each of these to work, the compiler must support the requested
sanitizer and the requisite libraries must be installed (libasan,
liblsan, libubsan).
---
acinclude.m4 | 36 ++++++++++++++++++++++++++++++++++++
configure.ac | 45 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 81 insertions(+)
diff --git a/acinclude.m4 b/acinclude.m4
index 0ba4287..8aab4ee 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -10,6 +10,42 @@ AC_DEFUN([AC_PROG_CC_PIE], [
])
])
+AC_DEFUN([AC_PROG_CC_ASAN], [
+ AC_CACHE_CHECK([whether ${CC-cc} accepts -fsanitize=address], ac_cv_prog_cc_asan, [
+ echo 'void f(){}' > conftest.c
+ if test -z "`${CC-cc} -fsanitize=address -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_asan=yes
+ else
+ ac_cv_prog_cc_asan=no
+ fi
+ rm -rf conftest*
+ ])
+])
+
+AC_DEFUN([AC_PROG_CC_LSAN], [
+ AC_CACHE_CHECK([whether ${CC-cc} accepts -fsanitize=leak], ac_cv_prog_cc_lsan, [
+ echo 'void f(){}' > conftest.c
+ if test -z "`${CC-cc} -fsanitize=leak -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_lsan=yes
+ else
+ ac_cv_prog_cc_lsan=no
+ fi
+ rm -rf conftest*
+ ])
+])
+
+AC_DEFUN([AC_PROG_CC_UBSAN], [
+ AC_CACHE_CHECK([whether ${CC-cc} accepts -fsanitize=undefined], ac_cv_prog_cc_ubsan, [
+ echo 'void f(){}' > conftest.c
+ if test -z "`${CC-cc} -fsanitize=undefined -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_ubsan=yes
+ else
+ ac_cv_prog_cc_ubsan=no
+ fi
+ rm -rf conftest*
+ ])
+])
+
AC_DEFUN([COMPILER_FLAGS], [
if (test "${CFLAGS}" = ""); then
CFLAGS="-Wall -O2 -fsigned-char"
diff --git a/configure.ac b/configure.ac
index 39755fe..e4ca5b2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,6 +20,9 @@ AC_LANG_C
AC_PROG_CC
AC_PROG_CC_PIE
+AC_PROG_CC_ASAN
+AC_PROG_CC_LSAN
+AC_PROG_CC_UBSAN
AC_PROG_INSTALL
AC_C_CHAR_UNSIGNED
@@ -54,6 +57,48 @@ AC_ARG_ENABLE(pie, AC_HELP_STRING([--enable-pie],
fi
])
+save_LIBS=$LIBS
+AC_CHECK_LIB(asan, __sanitizer_cov_init)
+LIBS=$save_LIBS
+
+AC_ARG_ENABLE(asan, AC_HELP_STRING([--enable-asan],
+ [enable linking with address sanitizer]), [
+ if (test "${enableval}" = "yes" &&
+ test "${ac_cv_lib_asan___sanitizer_cov_init}" = "yes" &&
+ test "${ac_cv_prog_cc_asan}" = "yes"); then
+ CFLAGS="$CFLAGS -fsanitize=address";
+ LDFLAGS="$LDFLAGS -fsanitize=address"
+ fi
+])
+
+save_LIBS=$LIBS
+AC_CHECK_LIB(lsan, __sanitizer_cov_init)
+LIBS=$save_LIBS
+
+AC_ARG_ENABLE(lsan, AC_HELP_STRING([--enable-lsan],
+ [enable linking with leak sanitizer]), [
+ if (test "${enableval}" = "yes" &&
+ test "${ac_cv_lib_lsan___sanitizer_cov_init}" = "yes" &&
+ test "${ac_cv_prog_cc_lsan}" = "yes"); then
+ CFLAGS="$CFLAGS -fsanitize=leak";
+ LDFLAGS="$LDFLAGS -fsanitize=leak"
+ fi
+])
+
+save_LIBS=$LIBS
+AC_CHECK_LIB(ubsan, __sanitizer_cov_init)
+LIBS=$save_LIBS
+
+AC_ARG_ENABLE(ubsan, AC_HELP_STRING([--enable-ubsan],
+ [enable linking with undefined behavior sanitizer]), [
+ if (test "${enableval}" = "yes" &&
+ test "${ac_cv_lib_ubsan___sanitizer_cov_init}" = "yes" &&
+ test "${ac_cv_prog_cc_ubsan}" = "yes"); then
+ CFLAGS="$CFLAGS -fsanitize=undefined";
+ LDFLAGS="$LDFLAGS -fsanitize=undefined"
+ fi
+])
+
AC_CHECK_FUNC(signalfd, dummy=yes,
AC_MSG_ERROR(signalfd support is required))
--
2.8.2
6 years, 3 months
[PATCH 1/2] dbus: Add name_cache argument NULL checks
by Andrew Zaborowski
This is so that _dbus_name_cache_free and _dbus_name_cache_notify can be
called with a null pointer similar to l_free, _dbus_filter_free, etc.
---
ell/dbus-name-cache.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/ell/dbus-name-cache.c b/ell/dbus-name-cache.c
index 24ca619..0c2e08e 100644
--- a/ell/dbus-name-cache.c
+++ b/ell/dbus-name-cache.c
@@ -100,6 +100,9 @@ static void name_cache_entry_destroy(void *data)
void _dbus_name_cache_free(struct _dbus_name_cache *cache)
{
+ if (!cache)
+ return;
+
if (cache->watch_remove_work)
l_idle_remove(cache->watch_remove_work);
@@ -172,6 +175,9 @@ void _dbus_name_cache_notify(struct _dbus_name_cache *cache,
struct service_watch *watch;
bool prev_connected, connected;
+ if (!cache)
+ return;
+
if (_dbus_parse_unique_name(name, NULL))
return;
--
2.7.4
6 years, 3 months
[PATCH] dbus: Don't call l_hashmap_remove within l_hashmap_foreach
by Andrew Zaborowski
---
ell/dbus-name-cache.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/ell/dbus-name-cache.c b/ell/dbus-name-cache.c
index 6d723d7..24ca619 100644
--- a/ell/dbus-name-cache.c
+++ b/ell/dbus-name-cache.c
@@ -232,9 +232,8 @@ unsigned int _dbus_name_cache_add_watch(struct _dbus_name_cache *cache,
return watch->id;
}
-static void service_watch_remove(const void *key, void *value, void *user_data)
+static bool service_watch_remove(const void *key, void *value, void *user_data)
{
- struct _dbus_name_cache *cache = user_data;
struct name_cache_entry *entry = value;
struct service_watch **watch, *tmp;
@@ -249,8 +248,15 @@ static void service_watch_remove(const void *key, void *value, void *user_data)
service_watch_destroy(tmp);
- _dbus_name_cache_remove(cache, key);
+ entry->ref_count--;
}
+
+ if (entry->ref_count)
+ return false;
+
+ name_cache_entry_destroy(entry);
+
+ return true;
}
static void service_watch_remove_all(struct l_idle *idle, void *user_data)
@@ -260,7 +266,7 @@ static void service_watch_remove_all(struct l_idle *idle, void *user_data)
l_idle_remove(cache->watch_remove_work);
cache->watch_remove_work = NULL;
- l_hashmap_foreach(cache->names, service_watch_remove, cache);
+ l_hashmap_foreach_remove(cache->names, service_watch_remove, cache);
}
static void service_watch_mark(const void *key, void *value, void *user_data)
--
2.7.4
6 years, 3 months
[PATCH] unit: End to end FD passing test
by Andrew Zaborowski
---
Makefile.am | 3 +
unit/test-dbus-message-fds.c | 384 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 387 insertions(+)
create mode 100644 unit/test-dbus-message-fds.c
diff --git a/Makefile.am b/Makefile.am
index 3e8e3ef..aa99bdd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -140,6 +140,7 @@ dbus_tests = unit/test-kdbus \
unit/test-dbus \
unit/test-dbus-util \
unit/test-dbus-message \
+ unit/test-dbus-message-fds \
unit/test-dbus-service \
unit/test-dbus-watch \
unit/test-dbus-properties \
@@ -186,6 +187,8 @@ unit_test_dbus_LDADD = ell/libell-private.la
unit_test_dbus_message_LDADD = ell/libell-private.la
+unit_test_dbus_message_fds_LDADD = ell/libell-private.la
+
unit_test_dbus_util_LDADD = ell/libell-private.la
unit_test_dbus_service_LDADD = ell/libell-private.la
diff --git a/unit/test-dbus-message-fds.c b/unit/test-dbus-message-fds.c
new file mode 100644
index 0000000..7e710cf
--- /dev/null
+++ b/unit/test-dbus-message-fds.c
@@ -0,0 +1,384 @@
+/*
+ *
+ * Embedded Linux library
+ *
+ * Copyright (C) 2016 Intel Corporation. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <ell/ell.h>
+#include <ell/dbus-private.h>
+
+#define TEST_BUS_ADDRESS "unix:path=/tmp/ell-test-bus"
+
+static pid_t dbus_daemon_pid = -1;
+
+static int kdbus_fd = -1;
+
+static char bus_address[128];
+
+static bool start_dbus_daemon(void)
+{
+ char *prg_argv[6];
+ char *prg_envp[1];
+ pid_t pid;
+
+ prg_argv[0] = "/usr/bin/dbus-daemon";
+ prg_argv[1] = "--session";
+ prg_argv[2] = "--address=" TEST_BUS_ADDRESS;
+ prg_argv[3] = "--nopidfile";
+ prg_argv[4] = "--nofork";
+ prg_argv[5] = NULL;
+
+ prg_envp[0] = NULL;
+
+ l_info("launching dbus-daemon");
+
+ pid = fork();
+ if (pid < 0) {
+ l_error("failed to fork new process");
+ return false;
+ }
+
+ if (pid == 0) {
+ execve(prg_argv[0], prg_argv, prg_envp);
+ exit(EXIT_SUCCESS);
+ }
+
+ l_info("dbus-daemon process %d created", pid);
+
+ dbus_daemon_pid = pid;
+
+ strcpy(bus_address, TEST_BUS_ADDRESS);
+
+ return true;
+}
+
+static bool create_kdbus(void)
+{
+ char bus_name[64];
+
+ snprintf(bus_name, sizeof(bus_name), "%u-ell-test", getuid());
+
+ kdbus_fd = _dbus_kernel_create_bus(bus_name);
+ if (kdbus_fd < 0) {
+ l_warn("kdbus not available");
+ return false;
+ }
+
+ snprintf(bus_address, sizeof(bus_address),
+ "kernel:path=/dev/kdbus/%s/bus", bus_name);
+
+ return true;
+}
+
+static void signal_handler(struct l_signal *signal, uint32_t signo,
+ void *user_data)
+{
+ switch (signo) {
+ case SIGINT:
+ case SIGTERM:
+ l_info("Terminate");
+ l_main_quit();
+ break;
+ case SIGCHLD:
+ while (1) {
+ pid_t pid;
+ int status;
+
+ pid = waitpid(WAIT_ANY, &status, WNOHANG);
+ if (pid < 0 || pid == 0)
+ break;
+
+ l_info("process %d terminated with status=%d\n",
+ pid, status);
+
+ if (pid == dbus_daemon_pid) {
+ dbus_daemon_pid = -1;
+ l_main_quit();
+ }
+ }
+ break;
+ }
+}
+
+static struct l_dbus *dbus;
+
+struct dbus_test {
+ const char *name;
+ void (*start)(struct l_dbus *dbus, void *);
+ void *data;
+};
+
+static bool success;
+static struct l_queue *tests;
+static const struct l_queue_entry *current;
+
+static void test_add(const char *name,
+ void (*start)(struct l_dbus *dbus, void *),
+ void *test_data)
+{
+ struct dbus_test *test = l_new(struct dbus_test, 1);
+
+ test->name = name;
+ test->start = start;
+ test->data = test_data;
+
+ if (!tests)
+ tests = l_queue_new();
+
+ l_queue_push_tail(tests, test);
+}
+
+static void test_next()
+{
+ struct dbus_test *test;
+
+ if (current)
+ current = current->next;
+ else
+ current = l_queue_get_entries(tests);
+
+ if (!current) {
+ success = true;
+ l_main_quit();
+ return;
+ }
+
+ test = current->data;
+
+ l_info("TEST: %s", test->name);
+
+ test->start(dbus, test->data);
+}
+
+#define test_assert(cond) \
+ do { \
+ if (!(cond)) { \
+ l_info("TEST FAILED in %s at %s:%i: %s", \
+ __func__, __FILE__, __LINE__, \
+ L_STRINGIFY(cond)); \
+ l_main_quit(); \
+ return; \
+ } \
+ } while (0)
+
+static void request_name_callback(struct l_dbus *dbus, bool success,
+ bool queued, void *user_data)
+{
+ l_info("request name result=%s",
+ success ? (queued ? "queued" : "success") : "failed");
+
+ test_next();
+}
+
+static void ready_callback(void *user_data)
+{
+ l_info("ready");
+
+ l_dbus_name_acquire(dbus, "org.test", false, false, false,
+ request_name_callback, NULL);
+}
+
+static void disconnect_callback(void *user_data)
+{
+ l_info("Disconnected from DBus");
+ l_main_quit();
+}
+
+static struct l_dbus_message *get_random_callback(struct l_dbus *dbus,
+ struct l_dbus_message *message,
+ void *user_data)
+{
+ struct l_dbus_message *reply;
+ int fd;
+
+ reply = l_dbus_message_new_method_return(message);
+
+ fd = open("/dev/random", O_RDONLY);
+ l_dbus_message_set_arguments(reply, "h", fd);
+ close(fd);
+
+ return reply;
+}
+
+static void setup_test_interface(struct l_dbus_interface *interface)
+{
+ l_dbus_interface_method(interface, "GetRandom", 0, get_random_callback,
+ "h", "", "randomfd");
+}
+
+static int count_fds(void)
+{
+ int fd;
+ int count = 0;
+
+ for (fd = 0; fd < FD_SETSIZE; fd++)
+ if (fcntl(fd, F_GETFL) != -1 || errno != EBADF)
+ count++;
+
+ return count;
+}
+
+static bool compare_failed;
+
+static void compare_files(int a, int b)
+{
+ struct stat sa, sb;
+
+ compare_failed = true;
+
+ test_assert(fstat(a, &sa) == 0);
+ test_assert(fstat(b, &sb) == 0);
+
+ test_assert(sa.st_dev == sb.st_dev);
+ test_assert(sa.st_ino == sb.st_ino);
+ test_assert(sa.st_rdev == sb.st_rdev);
+
+ compare_failed = false;
+}
+
+static int open_fds;
+
+static void get_random_idle_callback(void *user_data)
+{
+ test_assert(count_fds() == open_fds);
+
+ test_next();
+}
+
+static void get_random_return_callback(struct l_dbus_message *message,
+ void *user_data)
+{
+ int fd0, fd1;
+
+ test_assert(!l_dbus_message_get_error(message, NULL, NULL));
+
+ test_assert(l_dbus_message_get_arguments(message, "h", &fd1));
+
+ fd0 = open("/dev/random", O_RDONLY);
+ test_assert(fd0 != -1);
+
+ compare_files(fd0, fd1);
+ if (compare_failed)
+ return;
+
+ close(fd0);
+ close(fd1);
+
+ test_assert(l_idle_oneshot(get_random_idle_callback, NULL, NULL));
+}
+
+static void test_fd_passing_1(struct l_dbus *dbus, void *test_data)
+{
+ open_fds = count_fds();
+
+ l_dbus_method_call(dbus, "org.test", "/test", "org.test", "GetRandom",
+ NULL, get_random_return_callback, NULL, NULL);
+}
+
+static void test_run(void)
+{
+ success = false;
+
+ l_dbus_set_ready_handler(dbus, ready_callback, dbus, NULL);
+ l_dbus_set_disconnect_handler(dbus, disconnect_callback, NULL, NULL);
+
+ if (!l_dbus_register_interface(dbus, "org.test", setup_test_interface,
+ NULL, true)) {
+ l_info("Unable to register interface");
+ return;
+ }
+
+ if (!l_dbus_object_add_interface(dbus, "/test", "org.test", NULL)) {
+ l_info("Unable to instantiate interface");
+ return;
+ }
+
+ l_main_run();
+}
+
+int main(int argc, char *argv[])
+{
+ struct l_signal *signal;
+ sigset_t mask;
+ int i;
+
+ test_add("FD passing 1", test_fd_passing_1, NULL);
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+ sigaddset(&mask, SIGCHLD);
+
+ signal = l_signal_create(&mask, signal_handler, NULL, NULL);
+
+ l_log_set_stderr();
+
+ if (!start_dbus_daemon())
+ return -1;
+
+ for (i = 0; i < 10; i++) {
+ usleep(200 * 1000);
+
+ dbus = l_dbus_new(bus_address);
+ if (dbus)
+ break;
+ }
+
+ test_run();
+
+ l_dbus_destroy(dbus);
+
+ kill(dbus_daemon_pid, SIGKILL);
+
+ if (!success)
+ goto done;
+
+ if (!create_kdbus())
+ goto done;
+
+ dbus = l_dbus_new(bus_address);
+
+ test_run();
+
+ l_dbus_destroy(dbus);
+
+ close(kdbus_fd);
+
+done:
+ l_signal_remove(signal);
+
+ l_queue_destroy(tests, l_free);
+
+ if (!success)
+ abort();
+
+ return 0;
+}
--
2.7.4
6 years, 3 months
[PATCH 1/4] dbus: Close unused file descriptors when creating message
by Andrew Zaborowski
---
ell/dbus-message.c | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/ell/dbus-message.c b/ell/dbus-message.c
index 0fe76de..89aaacc 100644
--- a/ell/dbus-message.c
+++ b/ell/dbus-message.c
@@ -765,7 +765,7 @@ struct l_dbus_message *dbus_message_from_blob(const void *data, size_t size,
'g', &message->signature);
if (num_fds) {
- uint32_t unix_fds;
+ uint32_t unix_fds, orig_fds = num_fds;
if (!get_header_field(message, DBUS_MESSAGE_FIELD_UNIX_FDS,
'u', &unix_fds))
@@ -774,12 +774,11 @@ struct l_dbus_message *dbus_message_from_blob(const void *data, size_t size,
if (num_fds > unix_fds)
num_fds = unix_fds;
- if (num_fds > L_ARRAY_SIZE(message->fds)) {
- for (i = L_ARRAY_SIZE(message->fds); i < num_fds; i++)
- close(fds[i]);
-
+ if (num_fds > L_ARRAY_SIZE(message->fds))
num_fds = L_ARRAY_SIZE(message->fds);
- }
+
+ for (i = num_fds; i < orig_fds; i++)
+ close(fds[i]);
}
message->num_fds = num_fds;
@@ -824,7 +823,7 @@ struct l_dbus_message *dbus_message_build(void *header, size_t header_size,
message->sealed = true;
if (num_fds) {
- uint32_t unix_fds;
+ uint32_t unix_fds, orig_fds = num_fds;
if (!get_header_field(message, DBUS_MESSAGE_FIELD_UNIX_FDS,
'u', &unix_fds)) {
@@ -835,12 +834,11 @@ struct l_dbus_message *dbus_message_build(void *header, size_t header_size,
if (num_fds > unix_fds)
num_fds = unix_fds;
- if (num_fds > L_ARRAY_SIZE(message->fds)) {
- for (i = L_ARRAY_SIZE(message->fds); i < num_fds; i++)
- close(fds[i]);
-
+ if (num_fds > L_ARRAY_SIZE(message->fds))
num_fds = L_ARRAY_SIZE(message->fds);
- }
+
+ for (i = num_fds; i < orig_fds; i++)
+ close(fds[i]);
}
message->num_fds = num_fds;
--
2.7.4
6 years, 3 months
[PATCH 1/2] dbus: Better search for matching rules in the filter tree
by Andrew Zaborowski
When adding new filter rules, perform a more complete search for
existing rules that already cover the rule being added by removing the
requierement that levels in the tree are ordered by the match type.
This may add overhead to adding new rules in some situations but will
reduce the number of server-side rules being used and the number of
requests. This covers a scenario where first a watch is added for:
type=signal, path=/
followed by
type=signal, sender=org.test, path=/
I believe there are some more tricky scenarios which are not covered
specifically when more than one child of an existing node matches some
condition of the rule being added.
---
ell/dbus-filter.c | 67 +++++++++++++++++++++++++++++++++++++++++++-----------
ell/dbus-private.h | 8 +++----
2 files changed, 58 insertions(+), 17 deletions(-)
diff --git a/ell/dbus-filter.c b/ell/dbus-filter.c
index 42755a9..9e3cad5 100644
--- a/ell/dbus-filter.c
+++ b/ell/dbus-filter.c
@@ -234,34 +234,63 @@ static bool remove_recurse(struct _dbus_filter *filter,
}
unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter,
- struct _dbus_filter_condition *rule,
- int rule_len,
- l_dbus_message_func_t signal_func,
- void *user_data)
+ const struct _dbus_filter_condition *rule,
+ int rule_len,
+ l_dbus_message_func_t signal_func,
+ void *user_data)
{
struct filter_node **node_ptr = &filter->root;
struct filter_node *node;
struct filter_node *parent = filter->root;
bool remote_rule = false;
- struct _dbus_filter_condition *condition, *end = rule + rule_len;
-
- qsort(rule, rule_len, sizeof(*rule), condition_compare);
-
- for (condition = rule; condition < end; condition++) {
- /* See if this condition is already a child of the node */
+ struct _dbus_filter_condition sorted[rule_len];
+ struct _dbus_filter_condition *unused, *condition;
+ struct _dbus_filter_condition *end = sorted + rule_len;
+
+ memcpy(sorted, rule, sizeof(sorted));
+ qsort(sorted, rule_len, sizeof(*condition), condition_compare);
+
+ /*
+ * Find or create a path in the tree with a node for each
+ * condition in the rule, loop until all conditions have been
+ * used.
+ */
+ unused = sorted;
+ while (unused < end) {
+ /*
+ * Find a child of the node that matches any unused
+ * condition. Note there could be multiple matches, we're
+ * happy with the first we can find.
+ */
while (*node_ptr) {
node = *node_ptr;
- if (node->type == condition->type &&
- !strcmp(node->match.value,
+ for (condition = unused; condition < end; condition++) {
+ if (condition->type > node->type) {
+ condition = end;
+ break;
+ }
+
+ if (condition->type < node->type ||
+ condition->type ==
+ L_DBUS_MATCH_NONE)
+ continue;
+
+ if (!strcmp(node->match.value,
condition->value))
+ break;
+ }
+
+ if (condition < end)
break;
node_ptr = &node->next;
}
- /* Add one */
+ /* Add a node */
if (!*node_ptr) {
+ condition = unused;
+
node = l_new(struct filter_node, 1);
node->type = condition->type;
node->match.value = l_strdup(condition->value);
@@ -278,6 +307,18 @@ unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter,
}
+ /*
+ * Mark the condition used. We do this by setting
+ * condition->type to an invalid value unless it is the
+ * first condition left in which case we can push the
+ * rule start. Another option is to always push the rule
+ * start and memmove the still unused conditions by one
+ * if necessary.
+ */
+ condition->type = L_DBUS_MATCH_NONE;
+ while (unused < end && unused[0].type == L_DBUS_MATCH_NONE)
+ unused++;
+
node_ptr = &node->match.children;
parent = node;
diff --git a/ell/dbus-private.h b/ell/dbus-private.h
index ab52895..f4209b8 100644
--- a/ell/dbus-private.h
+++ b/ell/dbus-private.h
@@ -320,10 +320,10 @@ struct _dbus_filter *_dbus_filter_new(struct l_dbus *dbus,
void _dbus_filter_free(struct _dbus_filter *filter);
unsigned int _dbus_filter_add_rule(struct _dbus_filter *filter,
- struct _dbus_filter_condition *rule,
- int rule_len,
- l_dbus_message_func_t signal_func,
- void *user_data);
+ const struct _dbus_filter_condition *rule,
+ int rule_len,
+ l_dbus_message_func_t signal_func,
+ void *user_data);
bool _dbus_filter_remove_rule(struct _dbus_filter *filter, unsigned int id);
char *_dbus_filter_rule_to_str(const struct _dbus_filter_condition *rule,
--
2.5.0
6 years, 3 months
[PATCH 1/5] dbus: Handle the 'h' type in append_arguments
by Andrew Zaborowski
FD values can't be handled same as int32 values ('i' and 'u').
---
ell/dbus-message.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/ell/dbus-message.c b/ell/dbus-message.c
index 6089295..038d44d 100644
--- a/ell/dbus-message.c
+++ b/ell/dbus-message.c
@@ -1140,7 +1140,6 @@ static bool append_arguments(struct l_dbus_message *message,
}
case 'i':
case 'u':
- case 'h':
{
uint32_t u = va_arg(args, uint32_t);
@@ -1149,6 +1148,20 @@ static bool append_arguments(struct l_dbus_message *message,
break;
}
+ case 'h':
+ {
+ int fd = va_arg(args, int);
+
+ if (!driver->append_basic(builder, *s,
+ &message->num_fds))
+ goto error;
+
+ if (message->num_fds < L_ARRAY_SIZE(message->fds))
+ message->fds[message->num_fds++] =
+ fcntl(fd, F_DUPFD_CLOEXEC, 3);
+
+ break;
+ }
case 'x':
case 't':
{
--
2.5.0
6 years, 3 months