BUG_ON(*c);
- is_monitor = hello->conn_flags & KDBUS_HELLO_MONITOR;
- is_activator = hello->conn_flags & KDBUS_HELLO_ACTIVATOR;
- is_policy_holder = hello->conn_flags & KDBUS_HELLO_POLICY_HOLDER;
+ is_monitor = hello->flags & KDBUS_HELLO_MONITOR;
+ is_activator = hello->flags & KDBUS_HELLO_ACTIVATOR;
+ is_policy_holder = hello->flags & KDBUS_HELLO_POLICY_HOLDER;
/* can't be activator or policy holder and monitor at the same time */
if (is_monitor && (is_activator || is_policy_holder))
BUILD_BUG_ON(sizeof(bus->id128) != sizeof(hello->id128));
memcpy(hello->id128, bus->id128, sizeof(hello->id128));
- conn->flags = hello->conn_flags;
+ conn->flags = hello->flags;
atomic64_set(&conn->attach_flags, hello->attach_flags);
if (is_activator) {
make = p;
- ret = kdbus_negotiate_flags(make->flags, buf,
- offsetof(typeof(*make), flags),
+ ret = kdbus_negotiate_flags(make, buf, typeof(*make),
KDBUS_MAKE_ACCESS_GROUP |
KDBUS_MAKE_ACCESS_WORLD);
if (ret < 0)
make = p;
- ret = kdbus_negotiate_flags(make->flags, buf,
- offsetof(typeof(*make), flags),
+ ret = kdbus_negotiate_flags(make, buf, typeof(*make),
KDBUS_MAKE_ACCESS_GROUP |
KDBUS_MAKE_ACCESS_WORLD);
if (ret < 0)
make = p;
- ret = kdbus_negotiate_flags(make->flags, buf,
- offsetof(typeof(*make), flags),
+ ret = kdbus_negotiate_flags(make, buf, typeof(*make),
KDBUS_MAKE_ACCESS_GROUP |
KDBUS_MAKE_ACCESS_WORLD);
if (ret < 0)
hello = p;
- ret = kdbus_negotiate_flags(hello->conn_flags, buf,
- offsetof(struct kdbus_cmd_hello,
- conn_flags),
+ ret = kdbus_negotiate_flags(hello, buf, typeof(*hello),
KDBUS_HELLO_ACCEPT_FD |
KDBUS_HELLO_ACTIVATOR |
KDBUS_HELLO_POLICY_HOLDER |
cmd_name = p;
- ret = kdbus_negotiate_flags(cmd_name->flags, buf,
- offsetof(typeof(*cmd_name), flags),
+ ret = kdbus_negotiate_flags(cmd_name, buf, typeof(*cmd_name),
KDBUS_NAME_REPLACE_EXISTING |
KDBUS_NAME_ALLOW_REPLACEMENT |
KDBUS_NAME_QUEUE);
break;
/* return flags to the caller */
- if (copy_to_user(buf, p, ((struct kdbus_cmd_name *)p)->size))
+ if (copy_to_user(buf, p, cmd_name->size))
ret = -EFAULT;
break;
cmd_name = p;
- ret = kdbus_negotiate_flags(cmd_name->flags, buf,
- offsetof(typeof(*cmd_name), flags),
+ ret = kdbus_negotiate_flags(cmd_name, buf, typeof(*cmd_name),
0);
if (ret < 0)
break;
break;
}
- ret = kdbus_negotiate_flags(cmd_list.flags, buf,
- offsetof(typeof(cmd_list), flags),
+ ret = kdbus_negotiate_flags(&cmd_list, buf, typeof(cmd_list),
KDBUS_NAME_LIST_UNIQUE |
KDBUS_NAME_LIST_NAMES |
KDBUS_NAME_LIST_ACTIVATORS |
cmd_info = p;
- ret = kdbus_negotiate_flags(cmd_info->flags, buf,
- offsetof(typeof(*cmd_info), flags),
+ ret = kdbus_negotiate_flags(cmd_info, buf, typeof(*cmd_info),
_KDBUS_ATTACH_ALL);
if (ret < 0)
break;
cmd_update = p;
- ret = kdbus_negotiate_flags(cmd_update->flags, buf,
- offsetof(typeof(*cmd_update),
- flags),
- 0);
+ ret = kdbus_negotiate_flags(cmd_update, buf,
+ typeof(*cmd_update), 0);
if (ret < 0)
break;
cmd_match = p;
- ret = kdbus_negotiate_flags(cmd_match->flags, buf,
- offsetof(typeof(*cmd_match),
- flags),
+ ret = kdbus_negotiate_flags(cmd_match, buf, typeof(*cmd_match),
KDBUS_MATCH_REPLACE);
if (ret < 0)
break;
cmd_match = p;
- ret = kdbus_negotiate_flags(cmd_match->flags, buf,
- offsetof(typeof(*cmd_match),
- flags),
+ ret = kdbus_negotiate_flags(cmd_match, buf, typeof(*cmd_match),
0);
if (ret < 0)
break;
if (ret < 0)
break;
- ret = kdbus_negotiate_flags(cmd_recv.flags, buf,
- offsetof(typeof(cmd_recv), flags),
+ ret = kdbus_negotiate_flags(&cmd_recv, buf, typeof(cmd_recv),
KDBUS_RECV_PEEK | KDBUS_RECV_DROP |
KDBUS_RECV_USE_PRIORITY);
if (ret < 0)
if (ret < 0)
break;
- ret = kdbus_negotiate_flags(cmd_free.flags, buf,
- offsetof(typeof(cmd_free), flags),
+ ret = kdbus_negotiate_flags(&cmd_free, buf, typeof(cmd_free),
0);
if (ret < 0)
break;
cmd_update = p;
- ret = kdbus_negotiate_flags(cmd_update->flags, buf,
- offsetof(typeof(*cmd_update),
- flags),
- 0);
+ ret = kdbus_negotiate_flags(cmd_update, buf,
+ typeof(*cmd_update), 0);
if (ret < 0)
break;
/**
* struct kdbus_msg - the representation of a kdbus message
* @size: Total size of the message
- * @flags: Message flags (KDBUS_MSG_FLAGS_*)
+ * @flags: Message flags (KDBUS_MSG_FLAGS_*), userspace → kernel
+ * @kernel_flags: Supported message flags, kernel → userspace
* @priority: Message queue priority value
* @dst_id: 64-bit ID of the destination connection
* @src_id: 64-bit ID of the source connection
struct kdbus_msg {
__u64 size;
__u64 flags;
+ __u64 kernel_flags;
__s64 priority;
__u64 dst_id;
__u64 src_id;
/**
* struct kdbus_cmd_recv - struct to de-queue a buffered message
- * @flags: KDBUS_RECV_* flags
+ * @flags: KDBUS_RECV_* flags, userspace → kernel
+ * @kernel_flags: Supported KDBUS_RECV_* flags, kernel → userspace
* @priority: Minimum priority of the messages to de-queue. Lowest
* values have the highest priority.
* @offset: Returned offset in the pool where the message is
*/
struct kdbus_cmd_recv {
__u64 flags;
+ __u64 kernel_flags;
__s64 priority;
__u64 offset;
} __attribute__((aligned(8)));
/**
* struct kdbus_cmd_free - struct to free a slice of memory in the pool
- * @offset The offset of the memory slice, as returned by other
+ * @offset: The offset of the memory slice, as returned by other
* ioctls
- * @flags Flags for the free command. Currently unused.
+ * @flags: Flags for the free command, userspace → kernel
+ * @kernel_flags: Supported flags of the free command, userspace → kernel
*
* This struct is used with the KDBUS_CMD_FREE ioctl.
*/
struct kdbus_cmd_free {
__u64 offset;
__u64 flags;
+ __u64 kernel_flags;
} __attribute__((aligned(8)));
/**
/**
* struct kdbus_cmd_hello - struct to say hello to kdbus
* @size: The total size of the structure
- * @conn_flags: Connection flags (KDBUS_HELLO_*).
+ * @flags: Connection flags (KDBUS_HELLO_*), userspace → kernel
+ * @kernel_flags: Supported connection flags, kernel → userspace
* @attach_flags: Mask of metadata to attach to each message sent
* (KDBUS_ATTACH_*)
* @bus_flags: The flags field copied verbatim from the original
*/
struct kdbus_cmd_hello {
__u64 size;
- __u64 conn_flags;
+ __u64 flags;
+ __u64 kernel_flags;
__u64 attach_flags;
__u64 bus_flags;
__u64 id;
/**
* struct kdbus_cmd_make - struct to make a bus, an endpoint or a domain
* @size: The total size of the struct
- * @flags: Properties for the bus/ep/domain to create
+ * @flags: Properties for the bus/ep/domain to create,
+ * userspace → kernel
+ * @kernel_flags: Supported flags for the used command, kernel → userspace
* @items: Items describing details
*
* This structure is used with the KDBUS_CMD_BUS_MAKE, KDBUS_CMD_ENDPOINT_MAKE
struct kdbus_cmd_make {
__u64 size;
__u64 flags;
+ __u64 kernel_flags;
struct kdbus_item items[0];
} __attribute__((aligned(8)));
/**
* struct kdbus_cmd_name - struct to describe a well-known name
* @size: The total size of the struct
- * @flags: Flags for a name entry (KDBUS_NAME_*)
+ * @flags: Flags for a name entry (KDBUS_NAME_*),
+ * userspace → kernel, kernel → userspace
+ * @kernel_flags: Supported flags for a name entry, kernel → userspace
* @items: Item list, containing the well-known name as
* KDBUS_ITEM_NAME
*
struct kdbus_cmd_name {
__u64 size;
__u64 flags;
+ __u64 kernel_flags;
struct kdbus_item items[0];
} __attribute__((aligned(8)));
/**
* struct kdbus_cmd_name_list - request a list of name entries
- * @flags: Flags for the query (KDBUS_NAME_LIST_*)
+ * @flags: Flags for the query (KDBUS_NAME_LIST_*),
+ * userspace → kernel
+ * @kernel_flags: Supported flags for queries, kernel → userspace
* @offset: The returned offset in the caller's pool buffer.
* The user must use KDBUS_CMD_FREE to free the
* allocated memory.
*/
struct kdbus_cmd_name_list {
__u64 flags;
+ __u64 kernel_flags;
__u64 offset;
} __attribute__((aligned(8)));
/**
* struct kdbus_cmd_conn_info - struct used for KDBUS_CMD_CONN_INFO ioctl
* @size: The total size of the struct
- * @flags: KDBUS_ATTACH_* flags
+ * @flags: KDBUS_ATTACH_* flags, userspace → kernel
+ * @kernel_flags: Supported KDBUS_ATTACH_* flags, kernel → userspace
* @id: The 64-bit ID of the connection. If set to zero, passing
* @name is required. kdbus will look up the name to
* determine the ID in this case.
struct kdbus_cmd_conn_info {
__u64 size;
__u64 flags;
+ __u64 kernel_flags;
__u64 id;
__u64 offset;
struct kdbus_item items[0];
/**
* struct kdbus_cmd_update - update flags of a connection
* @size: The total size of the struct
+ * @flags: Flags for the update command, userspace → kernel
+ * @kernel_flags: Supported flags for this command, kernel → userspace
* @items: A list of struct kdbus_item
*
* This struct is used with the KDBUS_CMD_CONN_UPDATE ioctl.
struct kdbus_cmd_update {
__u64 size;
__u64 flags;
+ __u64 kernel_flags;
struct kdbus_item items[0];
} __attribute__((aligned(8)));
* @size: The total size of the struct
* @cookie: Userspace supplied cookie. When removing, the cookie
* identifies the match to remove
+ * @flags: Flags for match command (KDBUS_MATCH_*),
+ * userspace → kernel
+ * @kernel_flags: Supported flags of the used command, kernel → userspace
* @items: A list of items for additional information
*
* This structure is used with the KDBUS_CMD_ADD_MATCH and
__u64 size;
__u64 cookie;
__u64 flags;
+ __u64 kernel_flags;
struct kdbus_item items[0];
} __attribute__((aligned(8)));
3.2 Flags
---------
-All ioctls used in the communication with the driver contain a 64-bit flags
-field. All bits that are not recognized by the kernel are rejected, and the
-ioctl fails with -EINVAL. Regardless of whether the kernel accepts the
-provided flags or not, the flags field in the ioctl buffer will be updated with
-all the bits the kernel driver knows about in its current state, and set the
-highest bit (KDBUS_FLAGS_KERNEL) as well. Userspace can use the returned value
-to negotiate features. The KDBUS_FLAGS_KERNEL bit will never be valid in any
-flags field of any command, so setting it will always make the ioctl fail.
-Hence, this is a way to probe possible kernel features.
+All ioctls used in the communication with the driver contain two 64-bit fields,
+'flags' and 'kernel_flags'. In 'flags', the behavior of the command can be
+tweaked, whereas in 'kernel_flags', the kernel driver writes back the mask of
+supported bits upon each call, and sets the KDBUS_FLAGS_KERNEL bit. This is a
+way to probe possible kernel features and make code forward and backward
+compatible.
+
+All bits that are not recognized by the kernel in 'flags' are rejected, and the
+ioctl fails with -EINVAL.
4. Items
KDBUS_MAKE_ACCESS_WORLD
Make the device node world-accessible
+ __u64 kernel_flags;
+ Valid flags for this command, returned by the kernel upon each call.
+
struct kdbus_item items[0];
A list of items, only used for creating custom endpoints. Ignored for
buses and domains.
After the ioctl returns, this field will contain the current metadata
attach flags of the connection.
+ __u64 kernel_flags;
+ Valid flags for this command, returned by the kernel upon each call.
+
__u64 id;
The connection's numerical ID to retrieve information for. If set to
non-zero value, the 'name' field is ignored.
__u64 flags;
The connection's flags as specified when it was created.
+ __u64 kernel_flags;
+ Valid flags for this command, returned by the kernel upon each call.
+
struct kdbus_item items[0];
Depending on the 'flags' field in struct kdbus_cmd_conn_info, items of
types KDBUS_ITEM_NAME and KDBUS_ITEM_CONN_NAME are followed here.
that behavior. With this bit set, and the remote being an activator,
-EADDRNOTAVAIL is returned from the ioctl.
+ __u64 kernel_flags;
+ Valid flags for this command, returned by the kernel upon each call of
+ KDBUS_MSG_SEND.
+
__s64 priority;
The priority of this message. Receiving messages (see below) may
optionally be constrained to messages of a minimal priority. This
KDBUS_RECV_USE_PRIORITY
Use the priority field (see below).
+ __u64 kernel_flags;
+ Valid flags for this command, returned by the kernel upon each call.
+
__s64 priority;
With KDBUS_RECV_USE_PRIORITY set in flags, receive the next message in
the queue with at least the given priority. If no such message is waiting
first connection in that queue becomes the new owner and is notified
accordingly.
- __u64 owner_id;
- __u64 conn_flags;
- Unused in this use case.
+ __u64 kernel_flags;
+ Valid flags for this command, returned by the kernel upon each call.
struct kdbus_item items[0];
Items to submit the name. Currently, one one item of type KDBUS_ITEM_NAME
terminator.
__u64 flags;
- __u64 owner_id;
- __u64 conn_flags;
- All unused for this use case.
struct kdbus_item items[0];
Items to submit the name. Currently, one one item of type KDBUS_ITEM_NAME
contains a dynamic number of struct kdbus_cmd_name that carry the actual
information. The fields inside that struct kdbus_cmd_name is described next.
-struct kdbus_cmd_name {
+struct kdbus_name_info {
__u64 size;
The overall size of this struct, including the name with its 0-byte string
terminator.
__u64 flags;
Unused for this use case,
+ __u64 kernel_flags;
+ Valid flags for this command, returned by the kernel upon each call.
+
struct kdbus_item items[0];
Unused for this use case.
};
goto exit_free;
}
- ret = kdbus_negotiate_flags(m->msg.flags, msg,
- offsetof(struct kdbus_msg, flags),
+ ret = kdbus_negotiate_flags(&m->msg, msg, struct kdbus_msg,
KDBUS_MSG_FLAGS_EXPECT_REPLY |
KDBUS_MSG_FLAGS_SYNC_REPLY |
KDBUS_MSG_FLAGS_NO_AUTO_START);
return NULL;
}
- h.hello.conn_flags = flags | KDBUS_HELLO_ACCEPT_FD;
+ h.hello.flags = flags | KDBUS_HELLO_ACCEPT_FD;
h.hello.attach_flags = _KDBUS_ATTACH_ALL;
h.conn_name.type = KDBUS_ITEM_CONN_NAME;
strcpy(h.conn_name.str, "this-is-my-name");
cmd_name->size = size;
if (flags)
cmd_name->flags = *flags;
- else
- cmd_name->flags = 0;
ret = ioctl(conn->fd, KDBUS_CMD_NAME_ACQUIRE, cmd_name);
if (ret < 0) {
bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
bus_make.head.size = sizeof(struct kdbus_cmd_make) +
sizeof(bus_make.bs) + bus_make.n_size;
- bus_make.head.flags = 0;
ret = ioctl(env->control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);
ASSERT_RETURN(ret == -1 && errno == EINVAL);
bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
bus_make.head.size = sizeof(struct kdbus_cmd_make) +
sizeof(bus_make.bs) + bus_make.n_size;
- bus_make.head.flags = 0;
ret = ioctl(env->control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);
ASSERT_RETURN(ret == -1 && errno == EINVAL);
bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
bus_make.head.size = sizeof(struct kdbus_cmd_make) +
sizeof(bus_make.bs) + bus_make.n_size;
- bus_make.head.flags = 0;
ret = ioctl(env->control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);
ASSERT_RETURN(ret == -1 && errno == EINVAL);
bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1;
bus_make.head.size = sizeof(struct kdbus_cmd_make) +
sizeof(bus_make.bs) + bus_make.n_size;
- bus_make.head.flags = 0;
ret = ioctl(env->control_fd, KDBUS_CMD_BUS_MAKE, &bus_make);
ASSERT_RETURN(ret == 0);
snprintf(s, sizeof(s), "/dev/" KBUILD_MODNAME "/%u-blah-1/bus", uid);
if (fd < 0)
return TEST_ERR;
- hello.conn_flags = KDBUS_HELLO_ACCEPT_FD;
+ hello.flags = KDBUS_HELLO_ACCEPT_FD;
hello.attach_flags = _KDBUS_ATTACH_ALL;
hello.size = sizeof(struct kdbus_cmd_hello);
hello.pool_size = POOL_SIZE;
/* a size of 0 must return EMSGSIZE */
hello.size = 1;
- hello.conn_flags = KDBUS_HELLO_ACCEPT_FD;
+ hello.flags = KDBUS_HELLO_ACCEPT_FD;
ret = ioctl(fd, KDBUS_CMD_HELLO, &hello);
ASSERT_RETURN(ret == -1 && errno == EINVAL);
hello.size = sizeof(struct kdbus_cmd_hello);
/* check faulty flags */
- hello.conn_flags = 1ULL << 32;
+ hello.flags = 1ULL << 32;
ret = ioctl(fd, KDBUS_CMD_HELLO, &hello);
ASSERT_RETURN(ret == -1 && errno == EINVAL);
/* kernel must have set its bit in the ioctl buffer */
- ASSERT_RETURN(hello.conn_flags & KDBUS_FLAG_KERNEL);
-
- hello.conn_flags = KDBUS_HELLO_ACCEPT_FD;
+ ASSERT_RETURN(hello.kernel_flags & KDBUS_FLAG_KERNEL);
/* check for faulty pool sizes */
hello.pool_size = 0;
- hello.conn_flags = KDBUS_HELLO_ACCEPT_FD;
+ hello.flags = KDBUS_HELLO_ACCEPT_FD;
ret = ioctl(fd, KDBUS_CMD_HELLO, &hello);
ASSERT_RETURN(ret == -1 && errno == EFAULT);
hello.pool_size = 4097;
- hello.conn_flags = KDBUS_HELLO_ACCEPT_FD;
ret = ioctl(fd, KDBUS_CMD_HELLO, &hello);
ASSERT_RETURN(ret == -1 && errno == EFAULT);
hello.pool_size = POOL_SIZE;
/* success test */
- hello.conn_flags = KDBUS_HELLO_ACCEPT_FD;
ret = ioctl(fd, KDBUS_CMD_HELLO, &hello);
ASSERT_RETURN(ret == 0);
ASSERT_RETURN(fd >= 0);
/* no ACTIVATOR flag without a name */
- hello.conn_flags = KDBUS_HELLO_ACTIVATOR;
+ hello.flags = KDBUS_HELLO_ACTIVATOR;
ret = ioctl(fd, KDBUS_CMD_HELLO, &hello);
ASSERT_RETURN(ret == -1 && errno == EINVAL);
ASSERT_RETURN(fd >= 0);
memset(&hello, 0, sizeof(hello));
- hello.conn_flags = KDBUS_HELLO_ACCEPT_FD;
+ hello.flags = KDBUS_HELLO_ACCEPT_FD;
hello.attach_flags = _KDBUS_ATTACH_ALL;
hello.size = sizeof(struct kdbus_cmd_hello);
hello.pool_size = POOL_SIZE;
F_OK) == 0);
/* can't use the same fd for domain make twice */
- domain_make.head.flags = 0;
ret = ioctl(fd, KDBUS_CMD_DOMAIN_MAKE, &domain_make);
ASSERT_RETURN(ret == -1 && errno == EBADFD);
/* can't register the same name twice */
fd2 = open("/dev/" KBUILD_MODNAME "/control", O_RDWR|O_CLOEXEC);
- domain_make.head.flags = 0;
ret = ioctl(fd2, KDBUS_CMD_DOMAIN_MAKE, &domain_make);
ASSERT_RETURN(ret == -1 && errno == EEXIST);
close(fd2);
ASSERT_RETURN(ret == -1 && errno == ENXIO);
/* free a buffer out of the pool's bounds */
- cmd_free.flags = 0;
cmd_free.offset = POOL_SIZE + 1;
ret = ioctl(env->conn->fd, KDBUS_CMD_FREE, &cmd_free);
ASSERT_RETURN(ret == -1 && errno == ENXIO);
return NULL;
}
- h.hello.conn_flags = flags | KDBUS_HELLO_ACCEPT_FD;
+ h.hello.flags = flags | KDBUS_HELLO_ACCEPT_FD;
h.hello.attach_flags = _KDBUS_ATTACH_ALL;
h.type = KDBUS_ITEM_CONN_NAME;
strncpy(h.comm, "monitor", sizeof(h.comm) - 1);
}
/**
- * kdbus_negotiate_flags() - check flags provided by user, and write the
- * valid mask back
+ * kdbus_check_and_write_flags() - check flags provided by user, and write the
+ * valid mask back
* @flags: The flags mask provided by userspace
* @buf: The buffer provided by userspace
- * @offset: Offset of the flags field inside the user-provided struct
+ * @offset_out: Offset of the kernel_flags field inside the user-provided struct
* @valid: Mask of valid bits
*
* This function will check whether the flags provided by userspace are within
* Return: 0 on success, -EFAULT if copy_to_user() failed, or -EINVAL if
* userspace submitted invalid bits in its mask.
*/
-int kdbus_negotiate_flags(u64 flags, void __user *buf, off_t offset, u64 valid)
+int kdbus_check_and_write_flags(u64 flags, void __user *buf,
+ off_t offset_out, u64 valid)
{
u64 val = valid | KDBUS_FLAG_KERNEL;
*/
WARN_ON_ONCE(valid & KDBUS_FLAG_KERNEL);
- if (copy_to_user(((u8 __user *) buf) + offset, &val, sizeof(val)))
+ if (copy_to_user(((u8 __user *) buf) + offset_out, &val, sizeof(val)))
return -EFAULT;
if (flags & ~valid)
}
int kdbus_sysname_is_valid(const char *name);
-int kdbus_negotiate_flags(u64 flags, void __user *buf, off_t offset, u64 valid);
void kdbus_fput_files(struct file **files, unsigned int count);
+int kdbus_check_and_write_flags(u64 flags, void __user *buf,
+ off_t offset_out, u64 valid);
+
+#define kdbus_negotiate_flags(_s, _b, _t, _v) \
+ kdbus_check_and_write_flags((_s)->flags, _b, \
+ offsetof(_t, kernel_flags), _v) \
#endif