diff options
author | Kay Sievers <kay@vrfy.org> | 2013-05-22 10:53:02 +0200 |
---|---|---|
committer | Kay Sievers <kay@vrfy.org> | 2013-05-24 03:07:40 +0200 |
commit | 48b24f974d131f2d85b47e128cc08f84cfa8db9c (patch) | |
tree | 6e224bd7d0885b2d947470b93eafc5f720e06fa1 | |
parent | cda746371aced17f995e494f1629cc1e8a2bc863 (diff) | |
download | kdbus-bus-48b24f974d131f2d85b47e128cc08f84cfa8db9c.tar.gz kdbus-bus-48b24f974d131f2d85b47e128cc08f84cfa8db9c.tar.bz2 kdbus-bus-48b24f974d131f2d85b47e128cc08f84cfa8db9c.zip |
make part iteration generic; *really* validate parts, fix now failing test
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | bus.c | 19 | ||||
-rw-r--r-- | connection.c | 26 | ||||
-rw-r--r-- | endpoint.c | 16 | ||||
-rw-r--r-- | internal.h | 29 | ||||
-rw-r--r-- | kdbus.h | 65 | ||||
-rw-r--r-- | match.c | 9 | ||||
-rw-r--r-- | message.c | 26 | ||||
-rw-r--r-- | names.c | 42 | ||||
-rw-r--r-- | namespace.c | 16 | ||||
-rw-r--r-- | policy.c | 19 | ||||
-rw-r--r-- | test/kdbus-util.c | 101 | ||||
-rw-r--r-- | test/kdbus-util.h | 26 | ||||
-rw-r--r-- | test/test-kdbus-daemon.c | 4 | ||||
-rw-r--r-- | test/test-kdbus.c | 8 |
15 files changed, 211 insertions, 197 deletions
@@ -16,6 +16,8 @@ Internal: accounts against its budget, security_vm_enough_memory_mm())? - how to limit memfd memory? - memfd's file pos is shared, which can be confusing, document pread/pwrite + - prefix all functions with kdbus + - signals miss all the process metadata, we attach only creds Kernel Core: - remove our own task_cgroup_path_from_hierarchy() as soon as it's available: @@ -245,9 +245,8 @@ int kdbus_bus_make_user(void __user *buf, struct kdbus_cmd_bus_kmake **kmake) goto exit; } - KDBUS_ITEM_FOREACH_VALIDATE(item, &km->make) { - /* empty items are invalid */ - if (item->size <= KDBUS_ITEM_HEADER_SIZE) { + KDBUS_PART_FOREACH(item, &km->make, items) { + if (!KDBUS_PART_VALID(item, &km->make)) { ret = -EINVAL; goto exit; } @@ -259,18 +258,18 @@ int kdbus_bus_make_user(void __user *buf, struct kdbus_cmd_bus_kmake **kmake) goto exit; } - if (item->size < KDBUS_ITEM_HEADER_SIZE + 2) { + if (item->size < KDBUS_PART_HEADER_SIZE + 2) { ret = -EINVAL; goto exit; } - if (item->size > KDBUS_ITEM_HEADER_SIZE + KDBUS_MAKE_MAX_LEN + 1) { + if (item->size > KDBUS_PART_HEADER_SIZE + KDBUS_MAKE_MAX_LEN + 1) { ret = -ENAMETOOLONG; goto exit; } if (!kdbus_validate_nul(item->str, - item->size - KDBUS_ITEM_HEADER_SIZE)) { + item->size - KDBUS_PART_HEADER_SIZE)) { ret = -EINVAL; goto exit; } @@ -279,6 +278,11 @@ int kdbus_bus_make_user(void __user *buf, struct kdbus_cmd_bus_kmake **kmake) continue; case KDBUS_MAKE_CGROUP: + if (item->size != KDBUS_PART_HEADER_SIZE + sizeof(__u64)) { + ret = -EINVAL; + goto exit; + } + if (km->cgroup_id) { ret = -EEXIST; goto exit; @@ -293,8 +297,7 @@ int kdbus_bus_make_user(void __user *buf, struct kdbus_cmd_bus_kmake **kmake) } } - /* expect correct padding and size values */ - if ((char *)item - ((char *)&km->make + km->make.size) >= 8) + if (!KDBUS_PART_END(item, &km->make)) return -EINVAL; if (!km->name) { diff --git a/connection.c b/connection.c index 094090aec3a..4e133d4475d 100644 --- a/connection.c +++ b/connection.c @@ -191,10 +191,10 @@ static int kdbus_conn_payload_add(struct kdbus_conn_queue *queue, return -ENOMEM; } - KDBUS_ITEM_FOREACH(item, &kmsg->msg) { + KDBUS_PART_FOREACH(item, &kmsg->msg, items) { switch (item->type) { case KDBUS_MSG_PAYLOAD_VEC: { - size_t size = KDBUS_ITEM_HEADER_SIZE + + size_t size = KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_vec); char tmp[size]; struct kdbus_item *it = (struct kdbus_item *)tmp; @@ -225,7 +225,7 @@ static int kdbus_conn_payload_add(struct kdbus_conn_queue *queue, } case KDBUS_MSG_PAYLOAD_MEMFD: { - size_t size = KDBUS_ITEM_HEADER_SIZE + + size_t size = KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_memfd); char tmp[size]; struct kdbus_item *it = (struct kdbus_item *)tmp; @@ -379,7 +379,7 @@ int kdbus_conn_queue_insert(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg, /* add a FDS item; the array content will be updated at RECV time */ if (kmsg->fds_count > 0) { - size_t size = KDBUS_ITEM_HEADER_SIZE; + size_t size = KDBUS_PART_HEADER_SIZE; char tmp[size]; struct kdbus_item *it = (struct kdbus_item *)tmp; @@ -525,6 +525,8 @@ int kdbus_conn_kmsg_send(struct kdbus_ep *ep, kmsg)) continue; + //FIXME: call kdbus_kmsg_append_for_dst()? + kdbus_conn_queue_insert(conn_dst, kmsg, 0); } mutex_unlock(&ep->bus->lock); @@ -564,11 +566,9 @@ int kdbus_conn_kmsg_send(struct kdbus_ep *ep, return ret; } - if (conn_src) { - ret = kdbus_kmsg_append_for_dst(kmsg, conn_src, conn_dst); - if (ret < 0) - return ret; - } + ret = kdbus_kmsg_append_for_dst(kmsg, conn_src, conn_dst); + if (ret < 0) + return ret; /* monitor connections get all messages */ mutex_lock(&ep->bus->lock); @@ -1127,9 +1127,8 @@ static long kdbus_conn_ioctl_ep(struct file *file, unsigned int cmd, break; } - KDBUS_ITEM_FOREACH_VALIDATE(item, hello) { - /* empty items are invalid */ - if (item->size <= KDBUS_ITEM_HEADER_SIZE) { + KDBUS_PART_FOREACH(item, hello, items) { + if (!KDBUS_PART_VALID(item, hello)) { ret = -EINVAL; break; } @@ -1168,6 +1167,9 @@ static long kdbus_conn_ioctl_ep(struct file *file, unsigned int cmd, } } + if (!KDBUS_PART_END(item, hello)) + return -EINVAL; + mutex_init(&conn->lock); mutex_init(&conn->names_lock); mutex_init(&conn->accounting_lock); diff --git a/endpoint.c b/endpoint.c index f1610769e61..834d595c53b 100644 --- a/endpoint.c +++ b/endpoint.c @@ -236,9 +236,8 @@ int kdbus_ep_kmake_user(void __user *buf, struct kdbus_cmd_ep_kmake **kmake) goto exit; } - KDBUS_ITEM_FOREACH_VALIDATE(item, &km->make) { - /* empty items are invalid */ - if (item->size <= KDBUS_ITEM_HEADER_SIZE) { + KDBUS_PART_FOREACH(item, &km->make, items) { + if (!KDBUS_PART_VALID(item, &km->make)) { ret = -EINVAL; goto exit; } @@ -250,18 +249,18 @@ int kdbus_ep_kmake_user(void __user *buf, struct kdbus_cmd_ep_kmake **kmake) goto exit; } - if (item->size < KDBUS_ITEM_HEADER_SIZE + 2) { + if (item->size < KDBUS_PART_HEADER_SIZE + 2) { ret = -EINVAL; goto exit; } - if (item->size > KDBUS_ITEM_HEADER_SIZE + KDBUS_MAKE_MAX_LEN + 1) { + if (item->size > KDBUS_PART_HEADER_SIZE + KDBUS_MAKE_MAX_LEN + 1) { ret = -ENAMETOOLONG; goto exit; } if (!kdbus_validate_nul(item->str, - item->size - KDBUS_ITEM_HEADER_SIZE)) { + item->size - KDBUS_PART_HEADER_SIZE)) { ret = -EINVAL; goto exit; } @@ -275,9 +274,8 @@ int kdbus_ep_kmake_user(void __user *buf, struct kdbus_cmd_ep_kmake **kmake) } } - /* expect correct padding and size values */ - if ((char *)item - ((char *)&km->make + km->make.size) >= 8) - return -EINVAL; + if (!KDBUS_PART_END(item, &km->make)) + return EINVAL; if (!km->name) { ret = -EBADMSG; diff --git a/internal.h b/internal.h index c19521b87b5..32313e8e619 100644 --- a/internal.h +++ b/internal.h @@ -42,22 +42,23 @@ #define KDBUS_ALIGN8(s) ALIGN((s), 8) #define KDBUS_IS_ALIGNED8(s) (IS_ALIGNED(s, 8)) -#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data) -#define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8(KDBUS_ITEM_HEADER_SIZE + (s)) -#define KDBUS_ITEM_NEXT(item) \ - (struct kdbus_item *)((u8 *)item + KDBUS_ALIGN8((item)->size)) -#define KDBUS_ITEM_FOREACH(item, head) \ - for (item = (head)->items; \ - (u8 *)(item) < (u8 *)(head) + (head)->size; \ - item = KDBUS_ITEM_NEXT(item)) -/* same iterator with more consistency checks, to be used with incoming data */ -#define KDBUS_ITEM_FOREACH_VALIDATE(item, head) \ - for (item = (head)->items; \ - (u8 *)(item) + KDBUS_ITEM_HEADER_SIZE <= (u8 *)(head) + (head)->size && \ - (u8 *)(item) + (item)->size <= (u8 *)(head) + (head)->size; \ - item = KDBUS_ITEM_NEXT(item)) +#define KDBUS_PART_HEADER_SIZE (2 * sizeof(__u64)) +#define KDBUS_PART_SIZE(s) KDBUS_ALIGN8(KDBUS_PART_HEADER_SIZE + (s)) +#define KDBUS_PART_NEXT(part) \ + (typeof(part))(((u8 *)part) + KDBUS_ALIGN8((part)->size)) +#define KDBUS_PART_FOREACH(part, head, first) \ + for (part = (head)->first; \ + (u8 *)(part) < (u8 *)(head) + (head)->size; \ + part = KDBUS_PART_NEXT(part)) +#define KDBUS_PART_VALID(part, head) \ + ((part)->size > KDBUS_PART_HEADER_SIZE && \ + (u8 *)(part) + (part)->size <= (u8 *)(head) + (head)->size) +#define KDBUS_PART_END(part, head) \ + ((u8 *)part >= ((u8 *)(head) + (head)->size) && \ + (u8 *)part - ((u8 *)(head) + (head)->size) < 8) #define KDBUS_MSG_HEADER_SIZE offsetof(struct kdbus_msg, items) +#define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8(KDBUS_PART_HEADER_SIZE + (s)) /* read 64bit .size from struct */ #define kdbus_size_get_user(_s, _b, _t) \ @@ -21,6 +21,18 @@ #endif #define KDBUS_IOC_MAGIC 0x95 +#define KDBUS_SRC_ID_KERNEL (0) +#define KDBUS_DST_ID_WELL_KNOWN_NAME (0) +#define KDBUS_MATCH_SRC_ID_ANY (~0ULL) +#define KDBUS_DST_ID_BROADCAST (~0ULL) + +/* Common first elements in a structure which are used to iterate over + * a list of elements. */ +#define KDBUS_PART_HEADER \ + struct { \ + __u64 size; \ + __u64 type; \ + } /* Message sent from kernel to userspace, when the owner or starter of * a well-known name changes */ @@ -60,10 +72,15 @@ struct kdbus_timestamp { __u64 realtime_ns; }; -#define KDBUS_SRC_ID_KERNEL (0) -#define KDBUS_DST_ID_WELL_KNOWN_NAME (0) -#define KDBUS_MATCH_SRC_ID_ANY (~0ULL) -#define KDBUS_DST_ID_BROADCAST (~0ULL) +struct kdbus_vec { + __u64 address; + __u64 size; +}; + +struct kdbus_memfd { + __u64 size; + int fd; +}; /* Message Item Types */ enum { @@ -100,16 +117,6 @@ enum { KDBUS_MSG_REPLY_DEAD, /* dito */ }; -struct kdbus_vec { - __u64 address; - __u64 size; -}; - -struct kdbus_memfd { - __u64 size; - int fd; -}; - /** * struct kdbus_item - chain of data blocks * @@ -117,8 +124,7 @@ struct kdbus_memfd { * type: kdbus_item type of data */ struct kdbus_item { - __u64 size; - __u64 type; + KDBUS_PART_HEADER; union { /* inline data */ __u8 data[0]; @@ -200,23 +206,25 @@ enum { KDBUS_POLICY_OWN = 1 << 0, }; +struct kdbus_policy_access { + __u64 type; /* USER, GROUP, WORLD */ + __u64 bits; /* RECV, SEND, OWN */ + __u64 id; /* uid, gid, 0 */ +}; + +//FIXME: convert access to access[] struct kdbus_policy { - __u64 size; - __u64 type; /* NAME or ACCESS */ + KDBUS_PART_HEADER; union { char name[0]; - struct { - __u32 type; /* USER, GROUP, WORLD */ - __u32 bits; /* RECV, SEND, OWN */ - __u64 id; /* uid, gid, 0 */ - } access; + struct kdbus_policy_access access; }; }; +/* A series of KDBUS_POLICY_NAME, plus one or more KDBUS_POLICY_ACCESS */ struct kdbus_cmd_policy { __u64 size; - __u8 data[0]; /* a series of KDBUS_POLICY_NAME plus one or - * more KDBUS_POLICY_ACCESS each. */ + struct kdbus_policy policies[0]; }; /* Flags for struct kdbus_cmd_hello */ @@ -332,10 +340,11 @@ enum { KDBUS_NAME_IN_QUEUE = 1 << 16, }; +/* We allow (de)regestration of names of other peers */ struct kdbus_cmd_name { __u64 size; - __u64 name_flags; - __u64 id; /* We allow registration/deregestration of names of other peers */ + __u64 flags; + __u64 id; __u64 conn_flags; char name[0]; }; @@ -394,7 +403,7 @@ struct kdbus_cmd_monitor { * starter (via KDBUS_CMD_HELLO with KDBUS_CMD_HELLO_STARTER) * ep owner (via KDBUS_CMD_EP_MAKE) */ -enum kdbus_cmd { +enum { /* kdbus control node commands: require unset state */ KDBUS_CMD_BUS_MAKE = _IOWR(KDBUS_IOC_MAGIC, 0x00, struct kdbus_cmd_bus_make), KDBUS_CMD_NS_MAKE = _IOWR(KDBUS_IOC_MAGIC, 0x10, struct kdbus_cmd_ns_make), @@ -316,12 +316,12 @@ int kdbus_match_db_add(struct kdbus_conn *conn, void __user *buf) e->src_id = cmd_match->src_id; e->cookie = cmd_match->cookie; - KDBUS_ITEM_FOREACH_VALIDATE(item, cmd_match) { + KDBUS_PART_FOREACH(item, cmd_match, items) { struct kdbus_match_db_entry_item *ei; size_t size; - if (item->size < sizeof(*item)) { - ret = -EBADMSG; + if (!KDBUS_PART_VALID(item, cmd_match)) { + ret = -EINVAL; break; } @@ -364,6 +364,9 @@ int kdbus_match_db_add(struct kdbus_conn *conn, void __user *buf) list_add_tail(&ei->list_entry, &e->items_list); } + if (!KDBUS_PART_END(item, cmd_match)) + ret = -EINVAL; + if (ret >= 0) { list_add_tail(&e->list_entry, &db->entries); } else { diff --git a/message.c b/message.c index 823ac464e60..e09c8860e42 100644 --- a/message.c +++ b/message.c @@ -50,7 +50,7 @@ static void __maybe_unused kdbus_msg_dump(const struct kdbus_msg *msg) (unsigned long long) msg->payload_type, (unsigned long long) msg->timeout_ns); - KDBUS_ITEM_FOREACH(item, msg) { + KDBUS_PART_FOREACH(item, msg, items) { switch (item->type) { case KDBUS_MSG_PAYLOAD_VEC: pr_info("+KDBUS_MSG_PAYLOAD_VEC (%zu bytes) address=%p size=%zu\n", @@ -104,9 +104,8 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg bool has_name = false; bool has_bloom = false; - KDBUS_ITEM_FOREACH_VALIDATE(item, msg) { - /* empty items are invalid */ - if (item->size <= KDBUS_ITEM_HEADER_SIZE) + KDBUS_PART_FOREACH(item, msg, items) { + if (!KDBUS_PART_VALID(item, msg)) return -EINVAL; if (++items_count > KDBUS_MSG_MAX_ITEMS) @@ -114,7 +113,7 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg switch (item->type) { case KDBUS_MSG_PAYLOAD_VEC: - if (item->size != KDBUS_ITEM_HEADER_SIZE + + if (item->size != KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_vec)) return -EINVAL; @@ -130,7 +129,7 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg break; case KDBUS_MSG_PAYLOAD_MEMFD: - if (item->size != KDBUS_ITEM_HEADER_SIZE + + if (item->size != KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_memfd)) return -EINVAL; @@ -160,7 +159,7 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg if (msg->dst_id == KDBUS_DST_ID_BROADCAST) return -ENOTUNIQ; - n = (item->size - KDBUS_ITEM_HEADER_SIZE) / sizeof(int); + n = (item->size - KDBUS_PART_HEADER_SIZE) / sizeof(int); if (n > KDBUS_MSG_MAX_FDS) return -EMFILE; @@ -180,11 +179,11 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg return -EBADMSG; /* allow only bloom sizes of a multiple of 64bit */ - if (!KDBUS_IS_ALIGNED8(item->size - KDBUS_ITEM_HEADER_SIZE)) + if (!KDBUS_IS_ALIGNED8(item->size - KDBUS_PART_HEADER_SIZE)) return -EFAULT; /* do not allow mismatching bloom filter sizes */ - if (item->size - KDBUS_ITEM_HEADER_SIZE != conn->ep->bus->bloom_size) + if (item->size - KDBUS_PART_HEADER_SIZE != conn->ep->bus->bloom_size) return -EDOM; kmsg->bloom = item->data64; @@ -197,7 +196,7 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg has_name = true; /* enforce NUL-terminated strings */ - if (!kdbus_validate_nul(item->str, item->size - KDBUS_ITEM_HEADER_SIZE)) + if (!kdbus_validate_nul(item->str, item->size - KDBUS_PART_HEADER_SIZE)) return -EINVAL; if (!kdbus_name_is_valid(item->str)) @@ -211,8 +210,7 @@ static int kdbus_msg_scan_items(struct kdbus_conn *conn, struct kdbus_kmsg *kmsg } } - /* validate correct padding and size values to match the overall size */ - if ((char *)item - ((char *)msg + msg->size) >= 8) + if (!KDBUS_PART_END(item, msg)) return -EINVAL; /* name is needed if no ID is given */ @@ -371,7 +369,7 @@ static int kdbus_kmsg_append_data(struct kdbus_kmsg *kmsg, u64 type, return PTR_ERR(item); item->type = type; - item->size = KDBUS_ITEM_HEADER_SIZE + len; + item->size = KDBUS_PART_HEADER_SIZE + len; memcpy(item->str, buf, len); return 0; @@ -407,7 +405,7 @@ int kdbus_kmsg_append_src_names(struct kdbus_kmsg *kmsg, } item->type = KDBUS_MSG_SRC_NAMES; - item->size = KDBUS_ITEM_HEADER_SIZE + strsize; + item->size = KDBUS_PART_HEADER_SIZE + strsize; list_for_each_entry(name_entry, &conn->names_list, conn_entry) { strcpy(item->data + pos, name_entry->name); @@ -298,7 +298,7 @@ int kdbus_cmd_name_acquire(struct kdbus_name_registry *reg, conn = new_conn; } - cmd_name->name_flags &= ~KDBUS_NAME_IN_QUEUE; + cmd_name->flags &= ~KDBUS_NAME_IN_QUEUE; hash = kdbus_str_hash(cmd_name->name); if (conn->ep->policy_db) { @@ -313,10 +313,10 @@ int kdbus_cmd_name_acquire(struct kdbus_name_registry *reg, if (e) { if (e->conn == conn) { /* just update flags */ - e->flags = cmd_name->name_flags; + e->flags = cmd_name->flags; } else { ret = kdbus_name_handle_conflict(reg, conn, e, - &cmd_name->name_flags); + &cmd_name->flags); if (ret < 0) goto exit_unlock; } @@ -339,7 +339,7 @@ int kdbus_cmd_name_acquire(struct kdbus_name_registry *reg, if (conn->flags & KDBUS_HELLO_STARTER) e->starter = conn; - e->flags = cmd_name->name_flags; + e->flags = cmd_name->flags; INIT_LIST_HEAD(&e->queue_list); INIT_LIST_HEAD(&e->conn_entry); @@ -409,11 +409,6 @@ int kdbus_cmd_name_release(struct kdbus_name_registry *reg, return ret; } -#define KDBUS_NAME_SIZE(s) \ - KDBUS_ALIGN8(sizeof(struct kdbus_cmd_name) + strlen(s) + 1) -#define KDBUS_NAME_NEXT(n) \ - (struct kdbus_cmd_name *)((u8 *)n + KDBUS_ALIGN8(n->size)) - int kdbus_cmd_name_list(struct kdbus_name_registry *reg, struct kdbus_conn *conn, void __user *buf) @@ -432,7 +427,8 @@ int kdbus_cmd_name_list(struct kdbus_name_registry *reg, size = sizeof(struct kdbus_cmd_names); hash_for_each(reg->entries_hash, tmp, e, hentry) - size += KDBUS_NAME_SIZE(e->name); + size += KDBUS_ALIGN8(sizeof(struct kdbus_cmd_name) + + strlen(e->name) + 1); if (size > user_size) { kdbus_size_set_user(&size, buf, struct kdbus_cmd_names); @@ -452,10 +448,10 @@ int kdbus_cmd_name_list(struct kdbus_name_registry *reg, hash_for_each(reg->entries_hash, tmp, e, hentry) { cmd_name->size = sizeof(struct kdbus_cmd_name) + strlen(e->name) + 1; - cmd_name->name_flags = e->flags; + cmd_name->flags = e->flags; cmd_name->id = e->conn->id; strcpy(cmd_name->name, e->name); - cmd_name = KDBUS_NAME_NEXT(cmd_name); + cmd_name = KDBUS_PART_NEXT(cmd_name); } if (copy_to_user(buf, cmd_names, size)) { @@ -492,17 +488,17 @@ kdbus_name_fill_info_items(struct kdbus_conn *conn, return -ENOBUFS; #ifdef CONFIG_AUDITSYSCALL - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(conn->audit_ids); + item->size = KDBUS_PART_HEADER_SIZE + sizeof(conn->audit_ids); item->type = KDBUS_NAME_INFO_ITEM_AUDIT; memcpy(item->data, conn->audit_ids, sizeof(conn->audit_ids)); - item = KDBUS_ITEM_NEXT(item); + item = KDBUS_PART_NEXT(item); #endif #ifdef CONFIG_SECURITY - item->size = KDBUS_ITEM_HEADER_SIZE + conn->sec_label_len + 1; + item->size = KDBUS_PART_HEADER_SIZE + conn->sec_label_len + 1; item->type = KDBUS_NAME_INFO_ITEM_SECLABEL; memcpy(item->data, conn->sec_label, conn->sec_label_len); - item = KDBUS_ITEM_NEXT(item); + item = KDBUS_PART_NEXT(item); #endif return ret; @@ -538,11 +534,21 @@ int kdbus_cmd_name_query(struct kdbus_name_registry *reg, owner_conn = kdbus_bus_find_conn_by_id(conn->ep->bus, cmd_name_info->id); if (!owner_conn) - return -ENOENT; + return -ENXIO; } else { - KDBUS_ITEM_FOREACH_VALIDATE(info_item, cmd_name_info) + KDBUS_PART_FOREACH(info_item, cmd_name_info, items) { + if (!KDBUS_PART_VALID(info_item, cmd_name_info)) + return -EINVAL; + + if (name) + return -EBADMSG; + if (info_item->type == KDBUS_NAME_INFO_ITEM_NAME) name = info_item->data; + } + + if (!KDBUS_PART_END(info_item, cmd_name_info)) + return -EINVAL; if (!name) return -EINVAL; diff --git a/namespace.c b/namespace.c index cf6548541fa..d39f95b30c9 100644 --- a/namespace.c +++ b/namespace.c @@ -256,9 +256,8 @@ int kdbus_ns_kmake_user(void __user *buf, struct kdbus_cmd_ns_kmake **kmake) goto exit; } - KDBUS_ITEM_FOREACH_VALIDATE(item, &km->make) { - /* empty items are invalid */ - if (item->size <= KDBUS_ITEM_HEADER_SIZE) { + KDBUS_PART_FOREACH(item, &km->make, items) { + if (!KDBUS_PART_VALID(item, &km->make)) { ret = -EINVAL; goto exit; } @@ -270,18 +269,18 @@ int kdbus_ns_kmake_user(void __user *buf, struct kdbus_cmd_ns_kmake **kmake) goto exit; } - if (item->size < KDBUS_ITEM_HEADER_SIZE + 2) { + if (item->size < KDBUS_PART_HEADER_SIZE + 2) { ret = -EINVAL; goto exit; } - if (item->size > KDBUS_ITEM_HEADER_SIZE + KDBUS_MAKE_MAX_LEN + 1) { + if (item->size > KDBUS_PART_HEADER_SIZE + KDBUS_MAKE_MAX_LEN + 1) { ret = -ENAMETOOLONG; goto exit; } if (!kdbus_validate_nul(item->str, - item->size - KDBUS_ITEM_HEADER_SIZE)) { + item->size - KDBUS_PART_HEADER_SIZE)) { ret = -EINVAL; goto exit; } @@ -295,9 +294,8 @@ int kdbus_ns_kmake_user(void __user *buf, struct kdbus_cmd_ns_kmake **kmake) } } - /* expect correct padding and size values */ - if ((char *)item - ((char *)&km->make + km->make.size) >= 8) - return -EINVAL; + if (!KDBUS_PART_END(item, &km->make)) + return EINVAL; if (!km->name) { ret = -EBADMSG; @@ -226,7 +226,7 @@ static int __kdbus_policy_db_check_send_access(struct kdbus_policy_db *db, } } - return -EPERM; + return 0; } static struct kdbus_policy_db_cache_entry * @@ -371,13 +371,13 @@ static int kdbus_policy_db_parse(struct kdbus_policy_db *db, const struct kdbus_cmd_policy *cmd, u64 size) { - struct kdbus_policy *pol; + const struct kdbus_policy *pol; struct kdbus_policy_db_entry *current_entry = NULL; - size -= offsetof(struct kdbus_cmd_policy, data); - pol = (struct kdbus_policy *) cmd->data; + KDBUS_PART_FOREACH(pol, cmd, policies) { + if (!KDBUS_PART_VALID(pol, cmd)) + return -EINVAL; - while (size > 0) { switch (pol->type) { case KDBUS_POLICY_NAME: { struct kdbus_policy_db_entry *e; @@ -398,6 +398,7 @@ static int kdbus_policy_db_parse(struct kdbus_policy_db *db, current_entry = e; break; } + case KDBUS_POLICY_ACCESS: { struct kdbus_policy_db_entry_access *a; @@ -416,17 +417,17 @@ static int kdbus_policy_db_parse(struct kdbus_policy_db *db, mutex_lock(&db->entries_lock); list_add_tail(&a->list, ¤t_entry->access_list); mutex_unlock(&db->entries_lock); - break; } + default: return -EINVAL; } - - size -= pol->size; - pol = (struct kdbus_policy *) ((u8 *) pol + pol->size); } + if (!KDBUS_PART_END(pol, cmd)) + return -EINVAL; + return 0; } diff --git a/test/kdbus-util.c b/test/kdbus-util.c index c541676b68c..3cc69cf21ee 100644 --- a/test/kdbus-util.c +++ b/test/kdbus-util.c @@ -57,7 +57,7 @@ struct conn *connect_to_bus(const char *path) return NULL; } h.v_type = KDBUS_HELLO_POOL; - h.v_size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); + h.v_size = KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_vec); h.vec.address = (uint64_t)buf; h.vec.size = 16 * 1024 * 1024; @@ -71,7 +71,7 @@ struct conn *connect_to_bus(const char *path) KDBUS_HELLO_ATTACH_AUDIT; h.hello.size = sizeof(struct kdbus_cmd_hello) + - KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); + KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_vec); ret = ioctl(fd, KDBUS_CMD_HELLO, &h.hello); if (ret) { @@ -104,34 +104,36 @@ int msg_send(const struct conn *conn, int memfd; int ret; - ret = ioctl(conn->fd, KDBUS_CMD_MEMFD_NEW, &memfd); - if (ret < 0) { - fprintf(stderr, "KDBUS_CMD_MEMFD_NEW failed: %m\n"); - return EXIT_FAILURE; - } - - if (write(memfd, "kdbus memfd 1234567", 19) != 19) { - fprintf(stderr, "writing to memfd failed: %m\n"); - return EXIT_FAILURE; - } - - ret = ioctl(memfd, KDBUS_CMD_MEMFD_SEAL_SET, true); - if (ret < 0) { - fprintf(stderr, "memfd sealing failed: %m\n"); - return EXIT_FAILURE; - } - size = sizeof(struct kdbus_msg); size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); if (dst_id == KDBUS_DST_ID_BROADCAST) - size += KDBUS_ITEM_HEADER_SIZE + 64; + size += KDBUS_PART_HEADER_SIZE + 64; + else { + ret = ioctl(conn->fd, KDBUS_CMD_MEMFD_NEW, &memfd); + if (ret < 0) { + fprintf(stderr, "KDBUS_CMD_MEMFD_NEW failed: %m\n"); + return EXIT_FAILURE; + } + + if (write(memfd, "kdbus memfd 1234567", 19) != 19) { + fprintf(stderr, "writing to memfd failed: %m\n"); + return EXIT_FAILURE; + } + + ret = ioctl(memfd, KDBUS_CMD_MEMFD_SEAL_SET, true); + if (ret < 0) { + fprintf(stderr, "memfd sealing failed: %m\n"); + return EXIT_FAILURE; + } + + size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); + } if (name) - size += KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1; + size += KDBUS_ITEM_SIZE(strlen(name) + 1); msg = malloc(size); if (!msg) { @@ -150,40 +152,40 @@ int msg_send(const struct conn *conn, if (name) { item->type = KDBUS_MSG_DST_NAME; - item->size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1; + item->size = KDBUS_PART_HEADER_SIZE + strlen(name) + 1; strcpy(item->str, name); - item = KDBUS_ITEM_NEXT(item); + item = KDBUS_PART_NEXT(item); } item->type = KDBUS_MSG_PAYLOAD_VEC; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); + item->size = KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_vec); item->vec.address = (uint64_t)&ref1; item->vec.size = sizeof(ref1); - item = KDBUS_ITEM_NEXT(item); + item = KDBUS_PART_NEXT(item); /* data padding for ref1 */ item->type = KDBUS_MSG_PAYLOAD_VEC; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); + item->size = KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_vec); item->vec.address = (uint64_t)NULL; item->vec.size = KDBUS_ALIGN8(sizeof(ref1)) - sizeof(ref1); - item = KDBUS_ITEM_NEXT(item); + item = KDBUS_PART_NEXT(item); item->type = KDBUS_MSG_PAYLOAD_VEC; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); + item->size = KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_vec); item->vec.address = (uint64_t)&ref2; item->vec.size = sizeof(ref2); - item = KDBUS_ITEM_NEXT(item); - - item->type = KDBUS_MSG_PAYLOAD_MEMFD; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_memfd); - item->memfd.size = 16; - item->memfd.fd = memfd; - item = KDBUS_ITEM_NEXT(item); + item = KDBUS_PART_NEXT(item); if (dst_id == KDBUS_DST_ID_BROADCAST) { item->type = KDBUS_MSG_BLOOM; - item->size = KDBUS_ITEM_HEADER_SIZE + 64; - item = KDBUS_ITEM_NEXT(item); + item->size = KDBUS_PART_HEADER_SIZE + 64; + item = KDBUS_PART_NEXT(item); + } else { + item->type = KDBUS_MSG_PAYLOAD_MEMFD; + item->size = KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_memfd); + item->memfd.size = 16; + item->memfd.fd = memfd; + item = KDBUS_PART_NEXT(item); } ret = ioctl(conn->fd, KDBUS_CMD_MSG_SEND, msg); @@ -219,8 +221,8 @@ void msg_dump(struct kdbus_msg *msg) msg_id(msg->src_id, buf), msg_id(msg->dst_id, buf), (unsigned long long) msg->cookie, (unsigned long long) msg->timeout_ns); - KDBUS_ITEM_FOREACH(item, msg) { - if (item->size <= KDBUS_ITEM_HEADER_SIZE) { + KDBUS_PART_FOREACH(item, msg, items) { + if (item->size <= KDBUS_PART_HEADER_SIZE) { printf(" +%s (%llu bytes) invalid data record\n", enum_MSG(item->type), item->size); break; } @@ -279,7 +281,7 @@ void msg_dump(struct kdbus_msg *msg) case KDBUS_MSG_SRC_CMDLINE: case KDBUS_MSG_SRC_NAMES: { - size_t size = item->size - KDBUS_ITEM_HEADER_SIZE; + size_t size = item->size - KDBUS_PART_HEADER_SIZE; char *str = item->str; int count = 0; @@ -309,10 +311,10 @@ void msg_dump(struct kdbus_msg *msg) printf(" +%s (%llu bytes) len=%llu bytes)\n", enum_MSG(item->type), item->size, - (unsigned long long)item->size - KDBUS_ITEM_HEADER_SIZE); + (unsigned long long)item->size - KDBUS_PART_HEADER_SIZE); cap = item->data32; - n = (item->size - KDBUS_ITEM_HEADER_SIZE) / 4 / sizeof(uint32_t); + n = (item->size - KDBUS_PART_HEADER_SIZE) / 4 / sizeof(uint32_t); printf(" CapInh="); for (i = 0; i < n; i++) @@ -463,7 +465,7 @@ int name_list(struct conn *conn) } printf("REGISTRY:\n"); - KDBUS_NAME_FOREACH(name, names) + KDBUS_PART_FOREACH(name, names, names) printf(" '%s' is acquired by id %llx\n", name->name, name->id); printf("\n"); @@ -505,7 +507,8 @@ void append_policy(struct kdbus_cmd_policy *cmd_policy, struct kdbus_policy *pol return; memcpy(dst, policy, policy->size); - cmd_policy->size += policy->size; + cmd_policy->size += KDBUS_ALIGN8(policy->size); + free(policy); } struct kdbus_policy *make_policy_name(const char *name) @@ -517,7 +520,6 @@ struct kdbus_policy *make_policy_name(const char *name) p = malloc(size); if (!p) return NULL; - memset(p, 0, size); p->size = size; p->type = KDBUS_POLICY_NAME; @@ -554,9 +556,10 @@ int upload_policy(int fd) int size = 0xffff; cmd_policy = (struct kdbus_cmd_policy *) alloca(size); + memset(cmd_policy, 0, size); - policy = (struct kdbus_policy *) cmd_policy->data; - cmd_policy->size = offsetof(struct kdbus_cmd_policy, data); + policy = (struct kdbus_policy *) cmd_policy->policies; + cmd_policy->size = offsetof(struct kdbus_cmd_policy, policies); policy = make_policy_name("foo.bar.baz"); append_policy(cmd_policy, policy, size); @@ -576,5 +579,3 @@ int upload_policy(int fd) return ret; } - - diff --git a/test/kdbus-util.h b/test/kdbus-util.h index 34776262c48..3f65154b5c9 100644 --- a/test/kdbus-util.h +++ b/test/kdbus-util.h @@ -16,24 +16,16 @@ #define KDBUS_PTR(addr) ((void *)(uintptr_t)(addr)) -#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data) #define KDBUS_ALIGN8(l) (((l) + 7) & ~7) -#define KDBUS_ITEM_NEXT(item) \ - (struct kdbus_item *)(((uint8_t *)item) + KDBUS_ALIGN8((item)->size)) -#define KDBUS_ITEM_FOREACH(item, head) \ - for (item = (head)->items; \ - (uint8_t *)(item) < (uint8_t *)(head) + (head)->size; \ - item = KDBUS_ITEM_NEXT(item)) -#define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE) - -#define KDBUS_NAME_SIZE(s) \ - KDBUS_ALIGN8(sizeof(struct kdbus_cmd_name) + strlen(s) + 1) -#define KDBUS_NAME_NEXT(n) \ - (struct kdbus_cmd_name *)((char *)n + KDBUS_ALIGN8(n->size)) -#define KDBUS_NAME_FOREACH(name, names) \ - for (name = names->names; \ - (char *)name < (char *)names + name->size; \ - name = KDBUS_NAME_NEXT(name)) +#define KDBUS_PART_HEADER_SIZE offsetof(struct kdbus_item, data) +#define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_PART_HEADER_SIZE) + +#define KDBUS_PART_NEXT(part) \ + (typeof(part))(((uint8_t *)part) + KDBUS_ALIGN8((part)->size)) +#define KDBUS_PART_FOREACH(part, head, first) \ + for (part = (head)->first; \ + (uint8_t *)(part) < (uint8_t *)(head) + (head)->size; \ + part = KDBUS_PART_NEXT(part)) struct conn { int fd; diff --git a/test/test-kdbus-daemon.c b/test/test-kdbus-daemon.c index b7caec4c870..6b09e9e1398 100644 --- a/test/test-kdbus-daemon.c +++ b/test/test-kdbus-daemon.c @@ -49,11 +49,11 @@ int main(int argc, char *argv[]) bus_make.cgroup_id = cgroup_systemd(); bus_make.c_type = KDBUS_MAKE_CGROUP; - bus_make.c_size = KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t); + bus_make.c_size = KDBUS_PART_HEADER_SIZE + sizeof(uint64_t); snprintf(bus_make.name, sizeof(bus_make.name), "%u-testbus", getuid()); bus_make.n_type = KDBUS_MAKE_NAME; - bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; + bus_make.n_size = KDBUS_PART_HEADER_SIZE + strlen(bus_make.name) + 1; bus_make.head.size = sizeof(struct kdbus_cmd_bus_make) + bus_make.c_size + diff --git a/test/test-kdbus.c b/test/test-kdbus.c index ec0d2af29d3..e1055a5f1d8 100644 --- a/test/test-kdbus.c +++ b/test/test-kdbus.c @@ -61,15 +61,15 @@ int main(int argc, char *argv[]) } memset(&bus_make, 0, sizeof(bus_make)); - bus_make.head.bloom_size = 8; + bus_make.head.bloom_size = 64; bus_make.cgroup_id = cgroup_systemd(); bus_make.c_type = KDBUS_MAKE_CGROUP; - bus_make.c_size = KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t); + bus_make.c_size = KDBUS_PART_HEADER_SIZE + sizeof(uint64_t); snprintf(bus_make.name, sizeof(bus_make.name), "%u-testbus", getuid()); bus_make.n_type = KDBUS_MAKE_NAME; - bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; + bus_make.n_size = KDBUS_PART_HEADER_SIZE + strlen(bus_make.name) + 1; bus_make.head.size = sizeof(struct kdbus_cmd_bus_make) + bus_make.c_size + @@ -100,7 +100,7 @@ int main(int argc, char *argv[]) add_match_empty(conn_b->fd); cookie = 0; - msg_send(conn_b, "foo.bar.baz", 0xc0000000 | cookie, KDBUS_DST_ID_BROADCAST); + msg_send(conn_b, NULL, 0xc0000000 | cookie, KDBUS_DST_ID_BROADCAST); fds[0].fd = conn_a->fd; fds[1].fd = conn_b->fd; |