Skip to content

Commit 507e3b4

Browse files
prati0100rppt
authored andcommitted
liveupdate: validate session type before performing operation
The sessions ioctls are not applicable to all session types. PRESERVE_FD is only applicable to outgoing sessions. RETRIEVE_FD and FINISH are only valid for incoming session. Calling a incoming ioctl on an outgoing session is invalid and can cause file handlers to run into unexpected errors. For example, a user can create a (outgoing) session, preserve a memfd, and then immediately do a retrieve without doing a kexec in between. This would result in memfd's retrieve handler to run. The handlers expects to be called from a post-kexec context, and will try to do a kho_restore_vmalloc() or kho_restore_folio() to try and restore memory. KHO catches this (thanks to KHO_PAGE_MAGIC) and returns an error, but since this is considered an internal error and KHO throws out a bunch of WARN()s. Associate a type with each ioctl op and validate the type in luo_session_ioctl() before dispatching the ioctl handler to make sure the op is being called for the right session type. Fixes: 16cec0d ("liveupdate: luo_session: add ioctls for file preservation") Cc: stable@vger.kernel.org Signed-off-by: Pratyush Yadav (Google) <pratyush@kernel.org> Link: https://patch.msgid.link/20260519122428.2378446-1-pratyush@kernel.org Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
1 parent 051a224 commit 507e3b4

1 file changed

Lines changed: 33 additions & 6 deletions

File tree

kernel/liveupdate/luo_session.c

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -309,34 +309,60 @@ union ucmd_buffer {
309309
struct liveupdate_session_get_name get_name;
310310
};
311311

312+
/* Type of sessions the ioctl applies to. */
313+
enum luo_ioctl_type {
314+
LUO_IOCTL_INCOMING,
315+
LUO_IOCTL_OUTGOING,
316+
LUO_IOCTL_ALL,
317+
};
318+
312319
struct luo_ioctl_op {
313320
unsigned int size;
314321
unsigned int min_size;
315322
unsigned int ioctl_num;
323+
enum luo_ioctl_type type;
316324
int (*execute)(struct luo_session *session, struct luo_ucmd *ucmd);
317325
};
318326

319-
#define IOCTL_OP(_ioctl, _fn, _struct, _last) \
327+
#define IOCTL_OP(_ioctl, _fn, _struct, _last, _type) \
320328
[_IOC_NR(_ioctl) - LIVEUPDATE_CMD_SESSION_BASE] = { \
321329
.size = sizeof(_struct) + \
322330
BUILD_BUG_ON_ZERO(sizeof(union ucmd_buffer) < \
323331
sizeof(_struct)), \
324332
.min_size = offsetofend(_struct, _last), \
325333
.ioctl_num = _ioctl, \
334+
.type = _type, \
326335
.execute = _fn, \
327336
}
328337

329338
static const struct luo_ioctl_op luo_session_ioctl_ops[] = {
330339
IOCTL_OP(LIVEUPDATE_SESSION_FINISH, luo_session_finish,
331-
struct liveupdate_session_finish, reserved),
340+
struct liveupdate_session_finish, reserved, LUO_IOCTL_INCOMING),
332341
IOCTL_OP(LIVEUPDATE_SESSION_PRESERVE_FD, luo_session_preserve_fd,
333-
struct liveupdate_session_preserve_fd, token),
342+
struct liveupdate_session_preserve_fd, token, LUO_IOCTL_OUTGOING),
334343
IOCTL_OP(LIVEUPDATE_SESSION_RETRIEVE_FD, luo_session_retrieve_fd,
335-
struct liveupdate_session_retrieve_fd, token),
344+
struct liveupdate_session_retrieve_fd, token, LUO_IOCTL_INCOMING),
336345
IOCTL_OP(LIVEUPDATE_SESSION_GET_NAME, luo_session_get_name,
337-
struct liveupdate_session_get_name, name),
346+
struct liveupdate_session_retrieve_fd, token, LUO_IOCTL_ALL),
338347
};
339348

349+
static bool luo_ioctl_type_valid(struct luo_session *session,
350+
const struct luo_ioctl_op *op)
351+
{
352+
switch (op->type) {
353+
case LUO_IOCTL_INCOMING:
354+
/* Retrieved is only set on incoming sessions */
355+
return session->retrieved;
356+
case LUO_IOCTL_OUTGOING:
357+
return !session->retrieved;
358+
case LUO_IOCTL_ALL:
359+
return true;
360+
}
361+
362+
/* Catch-all. */
363+
return false;
364+
}
365+
340366
static long luo_session_ioctl(struct file *filep, unsigned int cmd,
341367
unsigned long arg)
342368
{
@@ -361,6 +387,8 @@ static long luo_session_ioctl(struct file *filep, unsigned int cmd,
361387
op = &luo_session_ioctl_ops[nr - LIVEUPDATE_CMD_SESSION_BASE];
362388
if (op->ioctl_num != cmd)
363389
return -ENOIOCTLCMD;
390+
if (!luo_ioctl_type_valid(session, op))
391+
return -EINVAL;
364392
if (ucmd.user_size < op->min_size)
365393
return -EINVAL;
366394

@@ -631,4 +659,3 @@ int luo_session_serialize(void)
631659

632660
return err;
633661
}
634-

0 commit comments

Comments
 (0)