Commit 4c205c84 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull keyrings fixes from David Howells:
 "Here's a couple of patches that fix a circular dependency between
  holding key->sem and mm->mmap_sem when reading data from a key.

  One potential issue is that a filesystem looking to use a key inside,
  say, ->readpages() could deadlock if the key being read is the key
  that's required and the buffer the key is being read into is on a page
  that needs to be fetched.

  The case actually detected is a bit more involved - with a filesystem
  calling request_key() and locking the target keyring for write - which
  could be being read"

* tag 'keys-fixes-20200329' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
  KEYS: Avoid false positive ENOMEM error on key read
  KEYS: Don't write out to userspace while holding key semaphore
parents ea9448b2 4f088249
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -17,6 +17,6 @@ extern void big_key_free_preparse(struct key_preparsed_payload *prep);
extern void big_key_revoke(struct key *key);
extern void big_key_destroy(struct key *key);
extern void big_key_describe(const struct key *big_key, struct seq_file *m);
extern long big_key_read(const struct key *key, char __user *buffer, size_t buflen);
extern long big_key_read(const struct key *key, char *buffer, size_t buflen);

#endif /* _KEYS_BIG_KEY_TYPE_H */
+1 −2
Original line number Diff line number Diff line
@@ -41,8 +41,7 @@ extern int user_update(struct key *key, struct key_preparsed_payload *prep);
extern void user_revoke(struct key *key);
extern void user_destroy(struct key *key);
extern void user_describe(const struct key *user, struct seq_file *m);
extern long user_read(const struct key *key,
		      char __user *buffer, size_t buflen);
extern long user_read(const struct key *key, char *buffer, size_t buflen);

static inline const struct user_key_payload *user_key_payload_rcu(const struct key *key)
{
+1 −1
Original line number Diff line number Diff line
@@ -127,7 +127,7 @@ struct key_type {
	 *   much is copied into the buffer
	 * - shouldn't do the copy if the buffer is NULL
	 */
	long (*read)(const struct key *key, char __user *buffer, size_t buflen);
	long (*read)(const struct key *key, char *buffer, size_t buflen);

	/* handle request_key() for this type instead of invoking
	 * /sbin/request-key (optional)
+1 −1
Original line number Diff line number Diff line
@@ -302,7 +302,7 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m)
 * - the key's semaphore is read-locked
 */
static long dns_resolver_read(const struct key *key,
			      char __user *buffer, size_t buflen)
			      char *buffer, size_t buflen)
{
	int err = PTR_ERR(key->payload.data[dns_key_error]);

+9 −18
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ static void rxrpc_free_preparse_s(struct key_preparsed_payload *);
static void rxrpc_destroy(struct key *);
static void rxrpc_destroy_s(struct key *);
static void rxrpc_describe(const struct key *, struct seq_file *);
static long rxrpc_read(const struct key *, char __user *, size_t);
static long rxrpc_read(const struct key *, char *, size_t);

/*
 * rxrpc defined keys take an arbitrary string as the description and an
@@ -1042,12 +1042,12 @@ EXPORT_SYMBOL(rxrpc_get_null_key);
 * - this returns the result in XDR form
 */
static long rxrpc_read(const struct key *key,
		       char __user *buffer, size_t buflen)
		       char *buffer, size_t buflen)
{
	const struct rxrpc_key_token *token;
	const struct krb5_principal *princ;
	size_t size;
	__be32 __user *xdr, *oldxdr;
	__be32 *xdr, *oldxdr;
	u32 cnlen, toksize, ntoks, tok, zero;
	u16 toksizes[AFSTOKEN_MAX];
	int loop;
@@ -1124,30 +1124,25 @@ static long rxrpc_read(const struct key *key,
	if (!buffer || buflen < size)
		return size;

	xdr = (__be32 __user *) buffer;
	xdr = (__be32 *)buffer;
	zero = 0;
#define ENCODE(x)				\
	do {					\
		__be32 y = htonl(x);		\
		if (put_user(y, xdr++) < 0)	\
			goto fault;		\
		*xdr++ = htonl(x);		\
	} while(0)
#define ENCODE_DATA(l, s)						\
	do {								\
		u32 _l = (l);						\
		ENCODE(l);						\
		if (copy_to_user(xdr, (s), _l) != 0)			\
			goto fault;					\
		if (_l & 3 &&						\
		    copy_to_user((u8 __user *)xdr + _l, &zero, 4 - (_l & 3)) != 0) \
			goto fault;					\
		memcpy(xdr, (s), _l);					\
		if (_l & 3)						\
			memcpy((u8 *)xdr + _l, &zero, 4 - (_l & 3));	\
		xdr += (_l + 3) >> 2;					\
	} while(0)
#define ENCODE64(x)					\
	do {						\
		__be64 y = cpu_to_be64(x);		\
		if (copy_to_user(xdr, &y, 8) != 0)	\
			goto fault;			\
		memcpy(xdr, &y, 8);			\
		xdr += 8 >> 2;				\
	} while(0)
#define ENCODE_STR(s)				\
@@ -1238,8 +1233,4 @@ static long rxrpc_read(const struct key *key,
	ASSERTCMP((char __user *) xdr - buffer, ==, size);
	_leave(" = %zu", size);
	return size;

fault:
	_leave(" = -EFAULT");
	return -EFAULT;
}
Loading