Commit e7582edb authored by Nathan Lynch's avatar Nathan Lynch Committed by Michael Ellerman

powerpc/rtas: Move token validation from block_rtas_call() to sys_rtas()

The rtas system call handler sys_rtas() delegates certain input
validation steps to a helper function: block_rtas_call(). One of these
steps ensures that the user-supplied token value maps to a known RTAS
function. This is done by performing a "reverse" token-to-function
lookup via rtas_token_to_function_untrusted() to obtain an
rtas_function object.

In changes to come, sys_rtas() itself will need the function
descriptor for the token. To prepare:

* Move the lookup and validation up into sys_rtas() and pass the
  resulting rtas_function pointer to block_rtas_call(), which is
  otherwise unconcerned with the token value.

* Change block_rtas_call() to report the RTAS function name instead of
  the token value on validation failures, since it can now rely on
  having a valid function descriptor.

One behavior change is that sys_rtas() now silently errors out when
passed a bad token, before calling block_rtas_call(). So we will no
longer log "RTAS call blocked - exploit attempt?" on invalid
tokens. This is consistent with how sys_rtas() currently handles other
"metadata" (nargs and nret), while block_rtas_call() is primarily
concerned with validating the arguments to be passed to specific RTAS
functions.
Signed-off-by: default avatarNathan Lynch <nathanl@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20231212-papr-sys_rtas-vs-lockdown-v6-5-e9eafd0c8c6c@linux.ibm.com
parent 9592aa5a
...@@ -1738,24 +1738,18 @@ static bool in_rmo_buf(u32 base, u32 end) ...@@ -1738,24 +1738,18 @@ static bool in_rmo_buf(u32 base, u32 end)
end < (rtas_rmo_buf + RTAS_USER_REGION_SIZE); end < (rtas_rmo_buf + RTAS_USER_REGION_SIZE);
} }
static bool block_rtas_call(int token, int nargs, static bool block_rtas_call(const struct rtas_function *func, int nargs,
struct rtas_args *args) struct rtas_args *args)
{ {
const struct rtas_function *func;
const struct rtas_filter *f; const struct rtas_filter *f;
const bool is_platform_dump = token == rtas_function_token(RTAS_FN_IBM_PLATFORM_DUMP); const bool is_platform_dump =
const bool is_config_conn = token == rtas_function_token(RTAS_FN_IBM_CONFIGURE_CONNECTOR); func == &rtas_function_table[RTAS_FNIDX__IBM_PLATFORM_DUMP];
const bool is_config_conn =
func == &rtas_function_table[RTAS_FNIDX__IBM_CONFIGURE_CONNECTOR];
u32 base, size, end; u32 base, size, end;
/* /*
* If this token doesn't correspond to a function the kernel * Only functions with filters attached are allowed.
* understands, you're not allowed to call it.
*/
func = rtas_token_to_function_untrusted(token);
if (!func)
goto err;
/*
* And only functions with filters attached are allowed.
*/ */
f = func->filter; f = func->filter;
if (!f) if (!f)
...@@ -1812,14 +1806,15 @@ static bool block_rtas_call(int token, int nargs, ...@@ -1812,14 +1806,15 @@ static bool block_rtas_call(int token, int nargs,
return false; return false;
err: err:
pr_err_ratelimited("sys_rtas: RTAS call blocked - exploit attempt?\n"); pr_err_ratelimited("sys_rtas: RTAS call blocked - exploit attempt?\n");
pr_err_ratelimited("sys_rtas: token=0x%x, nargs=%d (called by %s)\n", pr_err_ratelimited("sys_rtas: %s nargs=%d (called by %s)\n",
token, nargs, current->comm); func->name, nargs, current->comm);
return true; return true;
} }
/* We assume to be passed big endian arguments */ /* We assume to be passed big endian arguments */
SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs) SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs)
{ {
const struct rtas_function *func;
struct pin_cookie cookie; struct pin_cookie cookie;
struct rtas_args args; struct rtas_args args;
unsigned long flags; unsigned long flags;
...@@ -1849,13 +1844,18 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs) ...@@ -1849,13 +1844,18 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs)
nargs * sizeof(rtas_arg_t)) != 0) nargs * sizeof(rtas_arg_t)) != 0)
return -EFAULT; return -EFAULT;
if (token == RTAS_UNKNOWN_SERVICE) /*
* If this token doesn't correspond to a function the kernel
* understands, you're not allowed to call it.
*/
func = rtas_token_to_function_untrusted(token);
if (!func)
return -EINVAL; return -EINVAL;
args.rets = &args.args[nargs]; args.rets = &args.args[nargs];
memset(args.rets, 0, nret * sizeof(rtas_arg_t)); memset(args.rets, 0, nret * sizeof(rtas_arg_t));
if (block_rtas_call(token, nargs, &args)) if (block_rtas_call(func, nargs, &args))
return -EINVAL; return -EINVAL;
if (token_is_restricted_errinjct(token)) { if (token_is_restricted_errinjct(token)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment