From 78004e9a87f240df03e2f73120d291763c32e0a7 Mon Sep 17 00:00:00 2001 From: Ali Ahmet Memis Date: Fri, 21 Aug 2026 01:45:27 +0000 Subject: openrisc: fix arbitrary kernel memory access via or1k_atomic syscall sys_or1k_atomic() (syscall 244 in the "or1k" ABI) takes two user pointers, v1 and v2, and swaps the words they point to in hand-written assembly. l.lwz r29,0(r4) l.lwz r27,0(r5) l.sw 0(r4),r27 l.sw 0(r5),r29 The pointers are not checked with access_ok(). The four memory accesses also have no exception table entries. A caller passes a kernel address as either pointer, and the syscall reads from and writes to it directly. This gives an unprivileged process a kernel read/write primitive. It overwrites kernel data such as the sys_call_table, gaining code execution in kernel context. Check both pointers before entering the critical section. Add fixups for the four memory accesses so faults on valid but unmapped user addresses return -EFAULT. [shorne@gmail.com: fix comment style] Fixes: 9d02a4283e9c ("OpenRISC: Boot code") Cc: stable@vger.kernel.org Signed-off-by: Ali Ahmet Memis Signed-off-by: Stafford Horne --- security/keys/compat.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 security/keys/compat.c (limited to 'security/keys/compat.c') diff --git a/security/keys/compat.c b/security/keys/compat.c new file mode 100644 index 000000000..1545efdca --- /dev/null +++ b/security/keys/compat.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* 32-bit compatibility syscall for 64-bit systems + * + * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#include +#include +#include +#include +#include "internal.h" + +/* + * The key control system call, 32-bit compatibility version for 64-bit archs + */ +COMPAT_SYSCALL_DEFINE5(keyctl, u32, option, + u32, arg2, u32, arg3, u32, arg4, u32, arg5) +{ + switch (option) { + case KEYCTL_GET_KEYRING_ID: + return keyctl_get_keyring_ID(arg2, arg3); + + case KEYCTL_JOIN_SESSION_KEYRING: + return keyctl_join_session_keyring(compat_ptr(arg2)); + + case KEYCTL_UPDATE: + return keyctl_update_key(arg2, compat_ptr(arg3), arg4); + + case KEYCTL_REVOKE: + return keyctl_revoke_key(arg2); + + case KEYCTL_DESCRIBE: + return keyctl_describe_key(arg2, compat_ptr(arg3), arg4); + + case KEYCTL_CLEAR: + return keyctl_keyring_clear(arg2); + + case KEYCTL_LINK: + return keyctl_keyring_link(arg2, arg3); + + case KEYCTL_UNLINK: + return keyctl_keyring_unlink(arg2, arg3); + + case KEYCTL_SEARCH: + return keyctl_keyring_search(arg2, compat_ptr(arg3), + compat_ptr(arg4), arg5); + + case KEYCTL_READ: + return keyctl_read_key(arg2, compat_ptr(arg3), arg4); + + case KEYCTL_CHOWN: + return keyctl_chown_key(arg2, arg3, arg4); + + case KEYCTL_SETPERM: + return keyctl_setperm_key(arg2, arg3); + + case KEYCTL_INSTANTIATE: + return keyctl_instantiate_key(arg2, compat_ptr(arg3), arg4, + arg5); + + case KEYCTL_NEGATE: + return keyctl_negate_key(arg2, arg3, arg4); + + case KEYCTL_SET_REQKEY_KEYRING: + return keyctl_set_reqkey_keyring(arg2); + + case KEYCTL_SET_TIMEOUT: + return keyctl_set_timeout(arg2, arg3); + + case KEYCTL_ASSUME_AUTHORITY: + return keyctl_assume_authority(arg2); + + case KEYCTL_GET_SECURITY: + return keyctl_get_security(arg2, compat_ptr(arg3), arg4); + + case KEYCTL_SESSION_TO_PARENT: + return keyctl_session_to_parent(); + + case KEYCTL_REJECT: + return keyctl_reject_key(arg2, arg3, arg4, arg5); + + case KEYCTL_INSTANTIATE_IOV: + return keyctl_instantiate_key_iov(arg2, compat_ptr(arg3), arg4, + arg5); + + case KEYCTL_INVALIDATE: + return keyctl_invalidate_key(arg2); + + case KEYCTL_GET_PERSISTENT: + return keyctl_get_persistent(arg2, arg3); + + case KEYCTL_DH_COMPUTE: + return compat_keyctl_dh_compute(compat_ptr(arg2), + compat_ptr(arg3), + arg4, compat_ptr(arg5)); + + case KEYCTL_RESTRICT_KEYRING: + return keyctl_restrict_keyring(arg2, compat_ptr(arg3), + compat_ptr(arg4)); + + case KEYCTL_PKEY_QUERY: + if (arg3 != 0) + return -EINVAL; + return keyctl_pkey_query(arg2, + compat_ptr(arg4), + compat_ptr(arg5)); + + case KEYCTL_PKEY_ENCRYPT: + case KEYCTL_PKEY_DECRYPT: + case KEYCTL_PKEY_SIGN: + return keyctl_pkey_e_d_s(option, + compat_ptr(arg2), compat_ptr(arg3), + compat_ptr(arg4), compat_ptr(arg5)); + + case KEYCTL_PKEY_VERIFY: + return keyctl_pkey_verify(compat_ptr(arg2), compat_ptr(arg3), + compat_ptr(arg4), compat_ptr(arg5)); + + case KEYCTL_MOVE: + return keyctl_keyring_move(arg2, arg3, arg4, arg5); + + case KEYCTL_CAPABILITIES: + return keyctl_capabilities(compat_ptr(arg2), arg3); + + case KEYCTL_WATCH_KEY: + return keyctl_watch_key(arg2, arg3, arg4); + + default: + return -EOPNOTSUPP; + } +} -- cgit v1.3.1