Skip to content

Commit cdc1404

Browse files
committed
lsm,io_uring: add LSM hooks to io_uring
A full expalantion of io_uring is beyond the scope of this commit description, but in summary it is an asynchronous I/O mechanism which allows for I/O requests and the resulting data to be queued in memory mapped "rings" which are shared between the kernel and userspace. Optionally, io_uring offers the ability for applications to spawn kernel threads to dequeue I/O requests from the ring and submit the requests in the kernel, helping to minimize the syscall overhead. Rings are accessed in userspace by memory mapping a file descriptor provided by the io_uring_setup(2), and can be shared between applications as one might do with any open file descriptor. Finally, process credentials can be registered with a given ring and any process with access to that ring can submit I/O requests using any of the registered credentials. While the io_uring functionality is widely recognized as offering a vastly improved, and high performing asynchronous I/O mechanism, its ability to allow processes to submit I/O requests with credentials other than its own presents a challenge to LSMs. When a process creates a new io_uring ring the ring's credentials are inhertied from the calling process; if this ring is shared with another process operating with different credentials there is the potential to bypass the LSMs security policy. Similarly, registering credentials with a given ring allows any process with access to that ring to submit I/O requests with those credentials. In an effort to allow LSMs to apply security policy to io_uring I/O operations, this patch adds two new LSM hooks. These hooks, in conjunction with the LSM anonymous inode support previously submitted, allow an LSM to apply access control policy to the sharing of io_uring rings as well as any io_uring credential changes requested by a process. The new LSM hooks are described below: * int security_uring_override_creds(cred) Controls if the current task, executing an io_uring operation, is allowed to override it's credentials with @cred. In cases where the current task is a user application, the current credentials will be those of the user application. In cases where the current task is a kernel thread servicing io_uring requests the current credentials will be those of the io_uring ring (inherited from the process that created the ring). * int security_uring_sqpoll(void) Controls if the current task is allowed to create an io_uring polling thread (IORING_SETUP_SQPOLL). Without a SQPOLL thread in the kernel processes must submit I/O requests via io_uring_enter(2) which allows us to compare any requested credential changes against the application making the request. With a SQPOLL thread, we can no longer compare requested credential changes against the application making the request, the comparison is made against the ring's credentials. Signed-off-by: Paul Moore <[email protected]>
1 parent 91a9ab7 commit cdc1404

File tree

5 files changed

+56
-0
lines changed

5 files changed

+56
-0
lines changed

fs/io_uring.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
#include <linux/io_uring.h>
8181
#include <linux/tracehook.h>
8282
#include <linux/audit.h>
83+
#include <linux/security.h>
8384

8485
#define CREATE_TRACE_POINTS
8586
#include <trace/events/io_uring.h>
@@ -7070,6 +7071,11 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
70707071
if (!req->creds)
70717072
return -EINVAL;
70727073
get_cred(req->creds);
7074+
ret = security_uring_override_creds(req->creds);
7075+
if (ret) {
7076+
put_cred(req->creds);
7077+
return ret;
7078+
}
70737079
req->flags |= REQ_F_CREDS;
70747080
}
70757081
state = &ctx->submit_state;
@@ -8566,6 +8572,10 @@ static int io_sq_offload_create(struct io_ring_ctx *ctx,
85668572
struct io_sq_data *sqd;
85678573
bool attached;
85688574

8575+
ret = security_uring_sqpoll();
8576+
if (ret)
8577+
return ret;
8578+
85698579
sqd = io_get_sq_data(p, &attached);
85708580
if (IS_ERR(sqd)) {
85718581
ret = PTR_ERR(sqd);

include/linux/lsm_hook_defs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,3 +402,8 @@ LSM_HOOK(void, LSM_RET_VOID, perf_event_free, struct perf_event *event)
402402
LSM_HOOK(int, 0, perf_event_read, struct perf_event *event)
403403
LSM_HOOK(int, 0, perf_event_write, struct perf_event *event)
404404
#endif /* CONFIG_PERF_EVENTS */
405+
406+
#ifdef CONFIG_IO_URING
407+
LSM_HOOK(int, 0, uring_override_creds, const struct cred *new)
408+
LSM_HOOK(int, 0, uring_sqpoll, void)
409+
#endif /* CONFIG_IO_URING */

include/linux/lsm_hooks.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,6 +1557,19 @@
15571557
* Read perf_event security info if allowed.
15581558
* @perf_event_write:
15591559
* Write perf_event security info if allowed.
1560+
*
1561+
* Security hooks for io_uring
1562+
*
1563+
* @uring_override_creds:
1564+
* Check if the current task, executing an io_uring operation, is allowed
1565+
* to override it's credentials with @new.
1566+
*
1567+
* @new: the new creds to use
1568+
*
1569+
* @uring_sqpoll:
1570+
* Check whether the current task is allowed to spawn a io_uring polling
1571+
* thread (IORING_SETUP_SQPOLL).
1572+
*
15601573
*/
15611574
union security_list_options {
15621575
#define LSM_HOOK(RET, DEFAULT, NAME, ...) RET (*NAME)(__VA_ARGS__);

include/linux/security.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2038,4 +2038,20 @@ static inline int security_perf_event_write(struct perf_event *event)
20382038
#endif /* CONFIG_SECURITY */
20392039
#endif /* CONFIG_PERF_EVENTS */
20402040

2041+
#ifdef CONFIG_IO_URING
2042+
#ifdef CONFIG_SECURITY
2043+
extern int security_uring_override_creds(const struct cred *new);
2044+
extern int security_uring_sqpoll(void);
2045+
#else
2046+
static inline int security_uring_override_creds(const struct cred *new)
2047+
{
2048+
return 0;
2049+
}
2050+
static inline int security_uring_sqpoll(void)
2051+
{
2052+
return 0;
2053+
}
2054+
#endif /* CONFIG_SECURITY */
2055+
#endif /* CONFIG_IO_URING */
2056+
20412057
#endif /* ! __LINUX_SECURITY_H */

security/security.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2625,3 +2625,15 @@ int security_perf_event_write(struct perf_event *event)
26252625
return call_int_hook(perf_event_write, 0, event);
26262626
}
26272627
#endif /* CONFIG_PERF_EVENTS */
2628+
2629+
#ifdef CONFIG_IO_URING
2630+
int security_uring_override_creds(const struct cred *new)
2631+
{
2632+
return call_int_hook(uring_override_creds, 0, new);
2633+
}
2634+
2635+
int security_uring_sqpoll(void)
2636+
{
2637+
return call_int_hook(uring_sqpoll, 0);
2638+
}
2639+
#endif /* CONFIG_IO_URING */

0 commit comments

Comments
 (0)