[systemd-devel] [PATCH] [RFC] [WIP] [kdbus] Attempt to recursively pass fd
Alban Crequy
alban.crequy at collabora.co.uk
Thu Aug 14 04:21:21 PDT 2014
Before Linux commit 25888e (from 2.6.37-rc4, Nov 2010), fd-passing on Unix
sockets could recursively be stacked, allowing a process to exhaust the open
files limit (/proc/sys/fs/file-max) on the system without restriction from
ulimit -n.
This DoS on Unix sockets was fixed by commit:
> commit 25888e30319f8896fc656fc68643e6a078263060
> Author: Eric Dumazet <eric.dumazet at gmail.com>
> Date: Thu Nov 25 04:11:39 2010 +0000
>
> af_unix: limit recursion level
But that commit introduced a bug in dbus:
https://bugs.freedesktop.org/show_bug.cgi?id=80163
kdbus does not use fd-passing on Unix sockets so it is not affected by this.
However, it allows fd-passing similarly. This patch shows it is possible to
recursively pass file descriptors in kdbus and stack them without keeping them
attached to the initial process. I could stack passed fds 256 times, probably
because of the limit KDBUS_USER_MAX_CONN:
defaults.h:#define KDBUS_USER_MAX_CONN 256
But this limit could probably be overrided by using fds from different
endpoints.
I am also afraid that fds from Unix sockets and fds from kdbus could be stacked
together, defeating the limit implemented in unix_attach_fds() by commit 25888e
because the check uses unix_get_socket(), making the assumption that only Unix
sockets could carry file descriptors:
http://lxr.free-electrons.com/source/net/unix/af_unix.c#L1380
http://lxr.free-electrons.com/source/net/unix/garbage.c#L99
---
test/test-kdbus.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 72 insertions(+)
diff --git a/test/test-kdbus.c b/test/test-kdbus.c
index f0bf705..3c79877 100644
--- a/test/test-kdbus.c
+++ b/test/test-kdbus.c
@@ -12,6 +12,8 @@
#include <limits.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
#include <getopt.h>
#include <stdbool.h>
@@ -1004,6 +1006,75 @@ static int check_msg_basic(struct kdbus_check_env *env)
return CHECK_OK;
}
+static int send_fds(struct conn *conn, uint64_t dst_id, int fds[2])
+{
+ struct kdbus_msg *msg;
+ struct kdbus_item *item;
+ uint64_t size;
+ int ret;
+
+ size = sizeof(struct kdbus_msg);
+ size += KDBUS_ITEM_SIZE(sizeof(int[2]));
+
+ msg = malloc(size);
+ ASSERT_RETURN (msg != NULL);
+
+ memset(msg, 0, size);
+ msg->size = size;
+ msg->src_id = conn->id;
+ msg->dst_id = dst_id;
+ msg->payload_type = KDBUS_PAYLOAD_DBUS;
+
+ item = msg->items;
+
+ item->type = KDBUS_ITEM_FDS;
+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(int[2]);
+ item->fds[0] = fds[0];
+ item->fds[1] = fds[1];
+ item = KDBUS_ITEM_NEXT(item);
+
+ ret = ioctl(conn->fd, KDBUS_CMD_MSG_SEND, msg);
+ if (ret) {
+ fprintf(stderr, "error sending message: %d err %d (%m)\n", ret, errno);
+ return EXIT_FAILURE;
+ }
+
+ free(msg);
+
+ return 0;
+}
+
+static int check_fds_passing(struct kdbus_check_env *env)
+{
+ struct conn *conn_src, *conn_dst;
+ int fds[2];
+ int ret;
+ int i;
+
+ /* create two connections */
+ conn_src = kdbus_hello(env->buspath, 0, NULL, 0);
+ ASSERT_RETURN(conn_src != NULL);
+
+ for (i = 0; i >= 0; i++) {
+ conn_dst = kdbus_hello(env->buspath, 0, NULL, 0);
+ ASSERT_RETURN(conn_dst != NULL);
+
+ fds[0] = conn_src->fd;
+ fds[1] = conn_dst->fd;
+
+ ret = send_fds (conn_src, conn_dst->id, fds);
+ printf("check_fds_passing: iter: %d fds %d-%d ret %d err %d (%m)\n", i, fds[0], fds[1], ret, errno);
+ ASSERT_RETURN(ret == 0);
+
+ close(conn_src->fd);
+ free(conn_src);
+
+ conn_src = conn_dst;
+ }
+
+ return CHECK_OK;
+}
+
static int check_msg_free(struct kdbus_check_env *env)
{
int ret;
@@ -1111,6 +1182,7 @@ static const struct kdbus_check checks[] = {
{ "name queue", check_name_queue, CHECK_CREATE_BUS | CHECK_CREATE_CONN },
{ "message basic", check_msg_basic, CHECK_CREATE_BUS | CHECK_CREATE_CONN },
{ "message free", check_msg_free, CHECK_CREATE_BUS | CHECK_CREATE_CONN },
+ { "fds passing", check_fds_passing, CHECK_CREATE_BUS },
{ "connection info", check_conn_info, CHECK_CREATE_BUS | CHECK_CREATE_CONN },
{ "match id add", check_match_id_add, CHECK_CREATE_BUS | CHECK_CREATE_CONN },
{ "match id remove", check_match_id_remove, CHECK_CREATE_BUS | CHECK_CREATE_CONN },
--
1.8.5.3
More information about the systemd-devel
mailing list