ff8376ade4
Some function calls are not implemented in rxrpc_no_security, there are
preparse_server_key, free_preparse_server_key and destroy_server_key.
When rxrpc security type is rxrpc_no_security, user can easily trigger a
null-ptr-deref bug via ioctl. So judgment should be added to prevent it
The crash log:
user@syzkaller:~$ ./rxrpc_preparse_s
[ 37.956878][T15626] BUG: kernel NULL pointer dereference, address: 0000000000000000
[ 37.957645][T15626] #PF: supervisor instruction fetch in kernel mode
[ 37.958229][T15626] #PF: error_code(0x0010) - not-present page
[ 37.958762][T15626] PGD 4aadf067 P4D 4aadf067 PUD 4aade067 PMD 0
[ 37.959321][T15626] Oops: 0010 [#1] PREEMPT SMP
[ 37.959739][T15626] CPU: 0 PID: 15626 Comm: rxrpc_preparse_ Not tainted 5.17.0-01442-gb47d5a4f6b8d #43
[ 37.960588][T15626] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1 04/01/2014
[ 37.961474][T15626] RIP: 0010:0x0
[ 37.961787][T15626] Code: Unable to access opcode bytes at RIP 0xffffffffffffffd6.
[ 37.962480][T15626] RSP: 0018:ffffc9000d9abdc0 EFLAGS: 00010286
[ 37.963018][T15626] RAX: ffffffff84335200 RBX: ffff888012a1ce80 RCX: 0000000000000000
[ 37.963727][T15626] RDX: 0000000000000000 RSI: ffffffff84a736dc RDI: ffffc9000d9abe48
[ 37.964425][T15626] RBP: ffffc9000d9abe48 R08: 0000000000000000 R09: 0000000000000002
[ 37.965118][T15626] R10: 000000000000000a R11: f000000000000000 R12: ffff888013145680
[ 37.965836][T15626] R13: 0000000000000000 R14: ffffffffffffffec R15: ffff8880432aba80
[ 37.966441][T15626] FS: 00007f2177907700(0000) GS:ffff88803ec00000(0000) knlGS:0000000000000000
[ 37.966979][T15626] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 37.967384][T15626] CR2: ffffffffffffffd6 CR3: 000000004aaf1000 CR4: 00000000000006f0
[ 37.967864][T15626] Call Trace:
[ 37.968062][T15626] <TASK>
[ 37.968240][T15626] rxrpc_preparse_s+0x59/0x90
[ 37.968541][T15626] key_create_or_update+0x174/0x510
[ 37.968863][T15626] __x64_sys_add_key+0x139/0x1d0
[ 37.969165][T15626] do_syscall_64+0x35/0xb0
[ 37.969451][T15626] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 37.969824][T15626] RIP: 0033:0x43a1f9
Signed-off-by: Xiaolong Huang <butterflyhuangxx@gmail.com>
Tested-by: Xiaolong Huang <butterflyhuangxx@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
Link: http://lists.infradead.org/pipermail/linux-afs/2022-March/005069.html
Fixes: 12da59fcab
("rxrpc: Hand server key parsing off to the security class")
Link: https://lore.kernel.org/r/164865013439.2941502.8966285221215590921.stgit@warthog.procyon.org.uk
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
147 lines
3.5 KiB
C
147 lines
3.5 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/* RxRPC key management
|
|
*
|
|
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
|
|
* Written by David Howells (dhowells@redhat.com)
|
|
*
|
|
* RxRPC keys should have a description of describing their purpose:
|
|
* "afs@CAMBRIDGE.REDHAT.COM>
|
|
*/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <crypto/skcipher.h>
|
|
#include <linux/module.h>
|
|
#include <linux/net.h>
|
|
#include <linux/skbuff.h>
|
|
#include <linux/key-type.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/slab.h>
|
|
#include <net/sock.h>
|
|
#include <net/af_rxrpc.h>
|
|
#include <keys/rxrpc-type.h>
|
|
#include <keys/user-type.h>
|
|
#include "ar-internal.h"
|
|
|
|
static int rxrpc_vet_description_s(const char *);
|
|
static int rxrpc_preparse_s(struct key_preparsed_payload *);
|
|
static void rxrpc_free_preparse_s(struct key_preparsed_payload *);
|
|
static void rxrpc_destroy_s(struct key *);
|
|
static void rxrpc_describe_s(const struct key *, struct seq_file *);
|
|
|
|
/*
|
|
* rxrpc server keys take "<serviceId>:<securityIndex>[:<sec-specific>]" as the
|
|
* description and the key material as the payload.
|
|
*/
|
|
struct key_type key_type_rxrpc_s = {
|
|
.name = "rxrpc_s",
|
|
.flags = KEY_TYPE_NET_DOMAIN,
|
|
.vet_description = rxrpc_vet_description_s,
|
|
.preparse = rxrpc_preparse_s,
|
|
.free_preparse = rxrpc_free_preparse_s,
|
|
.instantiate = generic_key_instantiate,
|
|
.destroy = rxrpc_destroy_s,
|
|
.describe = rxrpc_describe_s,
|
|
};
|
|
|
|
/*
|
|
* Vet the description for an RxRPC server key.
|
|
*/
|
|
static int rxrpc_vet_description_s(const char *desc)
|
|
{
|
|
unsigned long service, sec_class;
|
|
char *p;
|
|
|
|
service = simple_strtoul(desc, &p, 10);
|
|
if (*p != ':' || service > 65535)
|
|
return -EINVAL;
|
|
sec_class = simple_strtoul(p + 1, &p, 10);
|
|
if ((*p && *p != ':') || sec_class < 1 || sec_class > 255)
|
|
return -EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Preparse a server secret key.
|
|
*/
|
|
static int rxrpc_preparse_s(struct key_preparsed_payload *prep)
|
|
{
|
|
const struct rxrpc_security *sec;
|
|
unsigned int service, sec_class;
|
|
int n;
|
|
|
|
_enter("%zu", prep->datalen);
|
|
|
|
if (!prep->orig_description)
|
|
return -EINVAL;
|
|
|
|
if (sscanf(prep->orig_description, "%u:%u%n", &service, &sec_class, &n) != 2)
|
|
return -EINVAL;
|
|
|
|
sec = rxrpc_security_lookup(sec_class);
|
|
if (!sec)
|
|
return -ENOPKG;
|
|
|
|
prep->payload.data[1] = (struct rxrpc_security *)sec;
|
|
|
|
if (!sec->preparse_server_key)
|
|
return -EINVAL;
|
|
|
|
return sec->preparse_server_key(prep);
|
|
}
|
|
|
|
static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep)
|
|
{
|
|
const struct rxrpc_security *sec = prep->payload.data[1];
|
|
|
|
if (sec && sec->free_preparse_server_key)
|
|
sec->free_preparse_server_key(prep);
|
|
}
|
|
|
|
static void rxrpc_destroy_s(struct key *key)
|
|
{
|
|
const struct rxrpc_security *sec = key->payload.data[1];
|
|
|
|
if (sec && sec->destroy_server_key)
|
|
sec->destroy_server_key(key);
|
|
}
|
|
|
|
static void rxrpc_describe_s(const struct key *key, struct seq_file *m)
|
|
{
|
|
const struct rxrpc_security *sec = key->payload.data[1];
|
|
|
|
seq_puts(m, key->description);
|
|
if (sec && sec->describe_server_key)
|
|
sec->describe_server_key(key, m);
|
|
}
|
|
|
|
/*
|
|
* grab the security keyring for a server socket
|
|
*/
|
|
int rxrpc_server_keyring(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
|
|
{
|
|
struct key *key;
|
|
char *description;
|
|
|
|
_enter("");
|
|
|
|
if (optlen <= 0 || optlen > PAGE_SIZE - 1)
|
|
return -EINVAL;
|
|
|
|
description = memdup_sockptr_nul(optval, optlen);
|
|
if (IS_ERR(description))
|
|
return PTR_ERR(description);
|
|
|
|
key = request_key(&key_type_keyring, description, NULL);
|
|
if (IS_ERR(key)) {
|
|
kfree(description);
|
|
_leave(" = %ld", PTR_ERR(key));
|
|
return PTR_ERR(key);
|
|
}
|
|
|
|
rx->securities = key;
|
|
kfree(description);
|
|
_leave(" = 0 [key %x]", key->serial);
|
|
return 0;
|
|
}
|