CVE-2017-2647 (C, published 2017-03-31T04:59Z)
Description: value: The KEYS subsystem in the Linux kernel before 3.18 allows local users to gain privileges or cause a denial of service (NULL pointer dereference and system crash) via vectors involving a NULL value for a certain match field, related to the keyring_search_iterator function in keyring.c.
Severity: HIGH (CVSS v3 base score: 7.8)
Weakness: CWE-476 \u2014 NULL Pointer Dereference
The product dereferences a pointer that it expects to be valid but is NULL.
Repository: https://github.com/torvalds/linux
Files changed:
crypto/asymmetric_keys/asymmetric_type.c
crypto/asymmetric_keys/pkcs7_key_type.c
fs/cifs/cifs_spnego.c
fs/cifs/cifsacl.c
fs/nfs/idmap.c
include/keys/user-type.h
include/linux/key-type.h
net/ceph/crypto.c
net/dns_resolver/dns_key.c
net/rxrpc/ar-key.c
security/keys/big_key.c
security/keys/encrypted-keys/encrypted.c
security/keys/internal.h
security/keys/key.c
security/keys/keyring.c
security/keys/request_key.c
security/keys/request_key_auth.c
security/keys/trusted.c
security/keys/user_defined.c
Commit message: KEYS: Remove key_type::match in favour of overriding default by match_preparse

A previous patch added a ->match_preparse() method to the key type.  This is
allowed to override the function called by the iteration algorithm.
Therefore, we can just set a default that simply checks for an exact match of
the key description with the original criterion data and allow match_preparse
to override it as needed.

The key_type::match op is then redundant and can be removed, as can the
user_match() function.

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Vivek Goyal <vgoyal@redhat.com>


Vulnerable code:
static int asymmetric_key_match(const struct key *key,
				const struct key_match_data *match_data)
	.match		= asymmetric_key_match,
	.match			= user_match,
	.match		= user_match,
	.match       = user_match,
	.match		= user_match,
	.match		= user_match,
struct key_match_data;
extern int user_match(const struct key *key,
		      const struct key_match_data *match_data);
	/* match a key against a description */
	int (*match)(const struct key *key,
		     const struct key_match_data *match_data);

	.match		= user_match,
static int
dns_resolver_match(const struct key *key,
		   const struct key_match_data *match_data)
	.match		= dns_resolver_match,
	.match		= user_match,
	.match		= user_match,
	.match			= user_match,
	.match = user_match,
	if (!index_key.type->match || !index_key.type->instantiate ||
	.match		= user_match,
		.match_data.cmp		= type->match,
	if (!ctx.match_data.cmp)
		return ERR_PTR(-ENOKEY);

		.match_data.cmp		= type->match,
		.match_data.cmp		= user_match,
	.match = user_match,
	.match			= user_match,
	.match			= user_match,
/*
 * match users on their name
 */
int user_match(const struct key *key, const struct key_match_data *match_data)
{
	return strcmp(key->description, match_data->raw_data) == 0;
}

EXPORT_SYMBOL_GPL(user_match);


Fixed code:
static int asymmetric_key_cmp(const struct key *key,
			      const struct key_match_data *match_data)
	match_data->cmp = asymmetric_key_cmp;
static int dns_resolver_cmp(const struct key *key,
			    const struct key_match_data *match_data)
/*
 * Preparse the match criterion.
 */
static int dns_resolver_match_preparse(struct key_match_data *match_data)
{
	match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
	match_data->cmp = dns_resolver_cmp;
	return 0;
}

	.match_preparse	= dns_resolver_match_preparse,
extern int key_default_cmp(const struct key *key,
			   const struct key_match_data *match_data);
	if (!index_key.type->instantiate ||
/*
 * By default, we keys found by getting an exact match on their descriptions.
 */
int key_default_cmp(const struct key *key,
		    const struct key_match_data *match_data)
{
	return strcmp(key->description, match_data->raw_data) == 0;
}

		.match_data.cmp		= key_default_cmp,
		.match_data.cmp		= key_default_cmp,
		.match_data.cmp		= key_default_cmp,