From d4c39ffb96567b7182e8f4df1aea35320285bc72 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Sat, 6 Dec 2014 00:43:15 -0500 Subject: [PATCH] hook gvariant vectors up to kdbus --- gio/gdbusmessage.c | 2 + gio/gdbusprivate.c | 2 - gio/gkdbus.c | 203 +++++++++++++++++++++++++++++++++++++++++++---------- gio/gkdbus.h | 4 +- 4 files changed, 169 insertions(+), 42 deletions(-) diff --git a/gio/gdbusmessage.c b/gio/gdbusmessage.c index bfe91e6..4d4cb69 100644 --- a/gio/gdbusmessage.c +++ b/gio/gdbusmessage.c @@ -3012,6 +3012,7 @@ g_dbus_message_to_blob (GDBusMessage *message, if (!append_body_to_blob (message->body, &mbuf, error)) goto out; } +#if 0 /* body - GVariant marshalling */ else if (message->major_protocol_version == 2) { @@ -3020,6 +3021,7 @@ g_dbus_message_to_blob (GDBusMessage *message, g_memory_buffer_write (&mbuf, message_body_data, message_body_size); } +#endif } else { diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c index e3f1cda..27d63bc 100644 --- a/gio/gdbusprivate.c +++ b/gio/gdbusprivate.c @@ -1210,8 +1210,6 @@ write_message_continue_writing (MessageToWriteData *data) data->total_written = _g_kdbus_send (data->worker, data->worker->kdbus, data->message, - data->blob, - data->blob_size, fd_list, data->worker->cancellable, &error); diff --git a/gio/gkdbus.c b/gio/gkdbus.c index 622011f..f249b2f 100644 --- a/gio/gkdbus.c +++ b/gio/gkdbus.c @@ -45,6 +45,7 @@ #endif #include +#include #include #include @@ -1590,6 +1591,23 @@ g_kdbus_append_payload_vec (struct kdbus_item **item, *item = KDBUS_ITEM_NEXT(*item); } +/** + * g_kdbus_append_payload_memfd: + * + */ +static void +g_kdbus_append_payload_memfd (struct kdbus_item **item, + gint fd, + gssize size) +{ + *item = KDBUS_ALIGN8_PTR(*item); + (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, memfd) + sizeof(struct kdbus_memfd); + (*item)->type = KDBUS_ITEM_PAYLOAD_MEMFD; + (*item)->memfd.fd = fd; + (*item)->memfd.size = size; + *item = KDBUS_ITEM_NEXT(*item); +} + /** * g_kdbus_append_payload_destiantion: @@ -1917,16 +1935,22 @@ g_kdbus_decode_kernel_msg (GKdbus *kdbus) * g_kdbus_decode_dbus_msg: * */ -static gssize -g_kdbus_decode_dbus_msg (GKdbus *kdbus) +static GDBusMessage * +g_kdbus_decode_dbus_msg (GKdbus *kdbus, + struct kdbus_cmd_recv *recv) { struct kdbus_item *item; - gchar *msg_ptr; - gssize ret_size = 0; gssize data_size = 0; const gchar *destination = NULL; + GArray *body_vectors; + gsize body_size; + GVariant *body; + guint i; - KDBUS_ITEM_FOREACH(item, kdbus->priv->kmsg, items) + body_vectors = g_array_new (FALSE, FALSE, sizeof (GVariantVector)); + body_size = 0; + + KDBUS_ITEM_FOREACH(item, (struct kdbus_msg *)((guint8 *)kdbus->priv->kdbus_buffer + recv->offset), items) { if (item->size <= KDBUS_ITEM_HEADER_SIZE) g_error("[KDBUS] %llu bytes - invalid data record\n", item->size); @@ -1935,7 +1959,6 @@ g_kdbus_decode_dbus_msg (GKdbus *kdbus) switch (item->type) { - /* KDBUS_ITEM_DST_NAME */ case KDBUS_ITEM_DST_NAME: destination = item->str; @@ -1943,27 +1966,61 @@ g_kdbus_decode_dbus_msg (GKdbus *kdbus) /* KDBUS_ITEM_PALOAD_OFF */ case KDBUS_ITEM_PAYLOAD_OFF: - - msg_ptr = (gchar*) kdbus->priv->kmsg + item->vec.offset; - g_kdbus_add_msg_part (kdbus, msg_ptr, item->vec.size); - ret_size += item->vec.size; - + { + GVariantVector vector; + gsize flavour; + + /* We want to make sure the bytes are aligned the same as + * they would be if they appeared in a contiguously + * allocated chunk of aligned memory. + * + * We decide what the alignment 'should' be by consulting + * body_size, which has been tracking the total size of the + * message up to this point. + * + * We then play around with the pointer by removing as many + * bytes as required to get it to the proper alignment (and + * copy extra bytes accordingly). This means that we will + * grab some extra data in the 'bytes', but it won't be + * shared with GVariant (which means there is no chance of + * it being accidentally retransmitted). + * + * The kernel does the same thing, so make sure we get the + * expected result. Because of the kernel doing the same, + * the result is that we will always be rounding-down to a + * multiple of 8 for the pointer, which means that the + * pointer will always be valid, assuming the original + * address was. + * + * We could fix this with a new GBytes constructor that took + * 'flavour' as a parameter, but it's not worth it... + */ + flavour = body_size & 7; + //g_assert ((item->vec.offset & 7) == flavour); FIXME: kdbus bug doesn't count memfd in flavouring + + vector.gbytes = g_bytes_new (((guchar *) kdbus->priv->kmsg) + item->vec.offset - flavour, + item->vec.size + flavour); + vector.data.pointer = g_bytes_get_data (vector.gbytes, NULL); + vector.data.pointer += flavour; + vector.size = item->vec.size; + + g_array_append_val (body_vectors, vector); + body_size += vector.size; + } break; /* KDBUS_ITEM_PAYLOAD_MEMFD */ case KDBUS_ITEM_PAYLOAD_MEMFD: + { + GVariantVector vector; - msg_ptr = mmap(NULL, item->memfd.size, PROT_READ, MAP_SHARED, item->memfd.fd, 0); - - if (msg_ptr == MAP_FAILED) - { - g_print ("mmap() fd=%i failed:%m", item->memfd.fd); - break; - } - - g_kdbus_add_msg_part (kdbus, msg_ptr, item->memfd.size); - ret_size += item->memfd.size; + vector.gbytes = g_bytes_new_take_zero_copy_fd (item->memfd.fd); + vector.data.pointer = g_bytes_get_data (vector.gbytes, &vector.size); + g_print ("GB was %p/%d\n", vector.data.pointer, (guint) vector.size); + g_array_append_val (body_vectors, vector); + body_size += vector.size; + } break; /* KDBUS_ITEM_FDS */ @@ -1978,8 +2035,27 @@ g_kdbus_decode_dbus_msg (GKdbus *kdbus) /* All of the following items, like CMDLINE, CGROUP, etc. need some GDBUS API extensions and should be implemented in the future */ - case KDBUS_ITEM_CREDS: case KDBUS_ITEM_TIMESTAMP: + { + g_print ("time: seq %llu mon %llu real %llu\n", + item->timestamp.seqnum, item->timestamp.monotonic_ns, item->timestamp.realtime_ns); + //g_dbus_message_set_timestamp (message, item->timestamp.monotonic_ns / 1000); + //g_dbus_message_set_serial (message, item->timestamp.seqnum); + break; + } + + case KDBUS_ITEM_CREDS: + { + g_print ("creds: u%u eu %u su%u fsu%u g%u eg%u sg%u fsg%u\n", + item->creds.uid, item->creds.euid, item->creds.suid, item->creds.fsuid, + item->creds.gid, item->creds.egid, item->creds.sgid, item->creds.fsgid); + break; + } + + case KDBUS_ITEM_PIDS: + { + } + case KDBUS_ITEM_PID_COMM: case KDBUS_ITEM_TID_COMM: case KDBUS_ITEM_EXE: @@ -1992,7 +2068,7 @@ g_kdbus_decode_dbus_msg (GKdbus *kdbus) case KDBUS_ITEM_AUXGROUPS: case KDBUS_ITEM_OWNED_NAME: case KDBUS_ITEM_NAME: - case KDBUS_ITEM_PIDS: + g_print ("unhandled %04x\n", (int) item->type); break; default: @@ -2001,6 +2077,18 @@ g_kdbus_decode_dbus_msg (GKdbus *kdbus) } } + body = GLIB_PRIVATE_CALL(g_variant_from_vectors) (G_VARIANT_TYPE ("(ssa{sv})"), + (GVariantVector *) body_vectors->data, + body_vectors->len, body_size, FALSE); + g_assert (body); + + for (i = 0; i < body_vectors->len; i++) + g_bytes_unref (g_array_index (body_vectors, GVariantVector, i).gbytes); + + g_array_free (body_vectors, TRUE); + + g_print ("body is %s\n", g_variant_print (body, TRUE)); + /* Override information from the user header with data from the kernel */ if (kdbus->priv->kmsg->src_id == KDBUS_SRC_ID_KERNEL) @@ -2018,7 +2106,7 @@ g_kdbus_decode_dbus_msg (GKdbus *kdbus) else g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->dst_id); - return ret_size; + return NULL; } @@ -2032,7 +2120,6 @@ _g_kdbus_receive (GKdbus *kdbus, GError **error) { struct kdbus_cmd_recv recv = {}; - gssize size = 0; if (g_cancellable_set_error_if_cancelled (cancellable, error)) return -1; @@ -2053,9 +2140,9 @@ again: kdbus->priv->kmsg = (struct kdbus_msg *)((guint8 *)kdbus->priv->kdbus_buffer + recv.offset); if (kdbus->priv->kmsg->payload_type == KDBUS_PAYLOAD_DBUS) - size = g_kdbus_decode_dbus_msg (kdbus); + g_kdbus_decode_dbus_msg (kdbus, &recv); else if (kdbus->priv->kmsg->payload_type == KDBUS_PAYLOAD_KERNEL) - size = g_kdbus_decode_kernel_msg (kdbus); + g_kdbus_decode_kernel_msg (kdbus); else { g_set_error (error, @@ -2065,34 +2152,45 @@ again: return -1; } - return size; + return 0; } - /** * _g_kdbus_send: * Returns: size of data sent or -1 when error */ -gsize +gboolean _g_kdbus_send (GDBusWorker *worker, GKdbus *kdbus, GDBusMessage *dbus_msg, - gchar *blob, - gsize blob_size, GUnixFDList *fd_list, GCancellable *cancellable, GError **error) { + GVariantVectors body_vectors; + GVariant *body; struct kdbus_msg* kmsg; struct kdbus_item *item; guint64 kmsg_size = 0; const gchar *name; guint64 dst_id = KDBUS_DST_ID_BROADCAST; + guint i; g_return_val_if_fail (G_IS_KDBUS (kdbus), -1); if (g_cancellable_set_error_if_cancelled (cancellable, error)) - return -1; + return FALSE; + + body = g_dbus_message_get_body (dbus_msg); + if (body == NULL) + { + g_warning ("no body!"); + body = g_variant_new ("()"); + g_variant_ref_sink (body); + } + else + g_variant_ref (body); + GLIB_PRIVATE_CALL(g_variant_to_vectors) (body, &body_vectors); /* * check destination @@ -2111,7 +2209,9 @@ _g_kdbus_send (GDBusWorker *worker, * check and set message size */ kmsg_size = sizeof(struct kdbus_msg); - kmsg_size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); /* header + body */ + + { G_STATIC_ASSERT (sizeof (struct kdbus_vec) == sizeof (struct kdbus_memfd)); } + kmsg_size += KDBUS_ITEM_SIZE(sizeof (struct kdbus_vec)) * body_vectors.vectors->len; if (fd_list != NULL && g_unix_fd_list_get_length (fd_list) > 0) kmsg_size += KDBUS_ALIGN8(G_STRUCT_OFFSET(struct kdbus_item, fds) + sizeof(int) * g_unix_fd_list_get_length(fd_list)); @@ -2156,9 +2256,36 @@ _g_kdbus_send (GDBusWorker *worker, * append payload */ item = kmsg->items; + for (i = 0; i < body_vectors.vectors->len; i++) + { + GVariantVector vector = g_array_index (body_vectors.vectors, GVariantVector, i); + + if (vector.gbytes) + { + gint fd; + + fd = g_bytes_get_zero_copy_fd (vector.gbytes); + + if (fd >= 0) + { + gconstpointer bytes_data; + gsize bytes_size; + + bytes_data = g_bytes_get_data (vector.gbytes, &bytes_size); + + if (bytes_data == vector.data.pointer && bytes_size == vector.size) + g_kdbus_append_payload_memfd (&item, fd, vector.size); + else + g_kdbus_append_payload_vec (&item, vector.data.pointer, vector.size); + } + else + g_kdbus_append_payload_vec (&item, vector.data.pointer, vector.size); + } + else + g_kdbus_append_payload_vec (&item, body_vectors.extra_bytes->data + vector.data.offset, vector.size); + } /* if we don't use memfd, send whole message as a PAYLOAD_VEC item */ - g_kdbus_append_payload_vec (&item, blob, blob_size); /* @@ -2233,10 +2360,12 @@ _g_kdbus_send (GDBusWorker *worker, g_print ("[KDBUS] ioctl error sending kdbus message:%d (%m)\n",errno); g_set_error (error, G_IO_ERROR, g_io_error_from_errno(errno), _("Error sending message - KDBUS_CMD_MSG_SEND error")); */ + perror("ioctl send"); g_error ("IOCTL SEND: %d\n",errno); - return -1; + return FALSE; } free(kmsg); - return blob_size; + + return TRUE; } diff --git a/gio/gkdbus.h b/gio/gkdbus.h index 7ba6f35..d8c8df1 100644 --- a/gio/gkdbus.h +++ b/gio/gkdbus.h @@ -121,11 +121,9 @@ void _g_kdbus_unsubscribe_name_acquired (GDB void _g_kdbus_unsubscribe_name_lost (GDBusConnection *connection); -gsize _g_kdbus_send (GDBusWorker *worker, +gboolean _g_kdbus_send (GDBusWorker *worker, GKdbus *kdbus, GDBusMessage *dbus_msg, - gchar *blob, - gsize blob_size, GUnixFDList *fd_list, GCancellable *cancellable, GError **error); -- 2.7.4