Skip to content

Commit 4c205c8

Browse files
committed
Merge tag 'keys-fixes-20200329' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs
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
2 parents ea9448b + 4f08824 commit 4c205c8

File tree

13 files changed

+126
-75
lines changed

13 files changed

+126
-75
lines changed

include/keys/big_key-type.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ extern void big_key_free_preparse(struct key_preparsed_payload *prep);
1717
extern void big_key_revoke(struct key *key);
1818
extern void big_key_destroy(struct key *key);
1919
extern void big_key_describe(const struct key *big_key, struct seq_file *m);
20-
extern long big_key_read(const struct key *key, char __user *buffer, size_t buflen);
20+
extern long big_key_read(const struct key *key, char *buffer, size_t buflen);
2121

2222
#endif /* _KEYS_BIG_KEY_TYPE_H */

include/keys/user-type.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ extern int user_update(struct key *key, struct key_preparsed_payload *prep);
4141
extern void user_revoke(struct key *key);
4242
extern void user_destroy(struct key *key);
4343
extern void user_describe(const struct key *user, struct seq_file *m);
44-
extern long user_read(const struct key *key,
45-
char __user *buffer, size_t buflen);
44+
extern long user_read(const struct key *key, char *buffer, size_t buflen);
4645

4746
static inline const struct user_key_payload *user_key_payload_rcu(const struct key *key)
4847
{

include/linux/key-type.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ struct key_type {
127127
* much is copied into the buffer
128128
* - shouldn't do the copy if the buffer is NULL
129129
*/
130-
long (*read)(const struct key *key, char __user *buffer, size_t buflen);
130+
long (*read)(const struct key *key, char *buffer, size_t buflen);
131131

132132
/* handle request_key() for this type instead of invoking
133133
* /sbin/request-key (optional)

net/dns_resolver/dns_key.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m)
302302
* - the key's semaphore is read-locked
303303
*/
304304
static long dns_resolver_read(const struct key *key,
305-
char __user *buffer, size_t buflen)
305+
char *buffer, size_t buflen)
306306
{
307307
int err = PTR_ERR(key->payload.data[dns_key_error]);
308308

net/rxrpc/key.c

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static void rxrpc_free_preparse_s(struct key_preparsed_payload *);
3131
static void rxrpc_destroy(struct key *);
3232
static void rxrpc_destroy_s(struct key *);
3333
static void rxrpc_describe(const struct key *, struct seq_file *);
34-
static long rxrpc_read(const struct key *, char __user *, size_t);
34+
static long rxrpc_read(const struct key *, char *, size_t);
3535

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

1127-
xdr = (__be32 __user *) buffer;
1127+
xdr = (__be32 *)buffer;
11281128
zero = 0;
11291129
#define ENCODE(x) \
11301130
do { \
1131-
__be32 y = htonl(x); \
1132-
if (put_user(y, xdr++) < 0) \
1133-
goto fault; \
1131+
*xdr++ = htonl(x); \
11341132
} while(0)
11351133
#define ENCODE_DATA(l, s) \
11361134
do { \
11371135
u32 _l = (l); \
11381136
ENCODE(l); \
1139-
if (copy_to_user(xdr, (s), _l) != 0) \
1140-
goto fault; \
1141-
if (_l & 3 && \
1142-
copy_to_user((u8 __user *)xdr + _l, &zero, 4 - (_l & 3)) != 0) \
1143-
goto fault; \
1137+
memcpy(xdr, (s), _l); \
1138+
if (_l & 3) \
1139+
memcpy((u8 *)xdr + _l, &zero, 4 - (_l & 3)); \
11441140
xdr += (_l + 3) >> 2; \
11451141
} while(0)
11461142
#define ENCODE64(x) \
11471143
do { \
11481144
__be64 y = cpu_to_be64(x); \
1149-
if (copy_to_user(xdr, &y, 8) != 0) \
1150-
goto fault; \
1145+
memcpy(xdr, &y, 8); \
11511146
xdr += 8 >> 2; \
11521147
} while(0)
11531148
#define ENCODE_STR(s) \
@@ -1238,8 +1233,4 @@ static long rxrpc_read(const struct key *key,
12381233
ASSERTCMP((char __user *) xdr - buffer, ==, size);
12391234
_leave(" = %zu", size);
12401235
return size;
1241-
1242-
fault:
1243-
_leave(" = -EFAULT");
1244-
return -EFAULT;
12451236
}

security/keys/big_key.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ void big_key_describe(const struct key *key, struct seq_file *m)
352352
* read the key data
353353
* - the key's semaphore is read-locked
354354
*/
355-
long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
355+
long big_key_read(const struct key *key, char *buffer, size_t buflen)
356356
{
357357
size_t datalen = (size_t)key->payload.data[big_key_len];
358358
long ret;
@@ -391,19 +391,16 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
391391

392392
ret = datalen;
393393

394-
/* copy decrypted data to user */
395-
if (copy_to_user(buffer, buf->virt, datalen) != 0)
396-
ret = -EFAULT;
394+
/* copy out decrypted data */
395+
memcpy(buffer, buf->virt, datalen);
397396

398397
err_fput:
399398
fput(file);
400399
error:
401400
big_key_free_buffer(buf);
402401
} else {
403402
ret = datalen;
404-
if (copy_to_user(buffer, key->payload.data[big_key_data],
405-
datalen) != 0)
406-
ret = -EFAULT;
403+
memcpy(buffer, key->payload.data[big_key_data], datalen);
407404
}
408405

409406
return ret;

security/keys/encrypted-keys/encrypted.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -902,14 +902,14 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
902902
}
903903

904904
/*
905-
* encrypted_read - format and copy the encrypted data to userspace
905+
* encrypted_read - format and copy out the encrypted data
906906
*
907907
* The resulting datablob format is:
908908
* <master-key name> <decrypted data length> <encrypted iv> <encrypted data>
909909
*
910910
* On success, return to userspace the encrypted key datablob size.
911911
*/
912-
static long encrypted_read(const struct key *key, char __user *buffer,
912+
static long encrypted_read(const struct key *key, char *buffer,
913913
size_t buflen)
914914
{
915915
struct encrypted_key_payload *epayload;
@@ -957,8 +957,7 @@ static long encrypted_read(const struct key *key, char __user *buffer,
957957
key_put(mkey);
958958
memzero_explicit(derived_key, sizeof(derived_key));
959959

960-
if (copy_to_user(buffer, ascii_buf, asciiblob_len) != 0)
961-
ret = -EFAULT;
960+
memcpy(buffer, ascii_buf, asciiblob_len);
962961
kzfree(ascii_buf);
963962

964963
return asciiblob_len;

security/keys/internal.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include <linux/keyctl.h>
1717
#include <linux/refcount.h>
1818
#include <linux/compat.h>
19+
#include <linux/mm.h>
20+
#include <linux/vmalloc.h>
1921

2022
struct iovec;
2123

@@ -349,4 +351,14 @@ static inline void key_check(const struct key *key)
349351

350352
#endif
351353

354+
/*
355+
* Helper function to clear and free a kvmalloc'ed memory object.
356+
*/
357+
static inline void __kvzfree(const void *addr, size_t len)
358+
{
359+
if (addr) {
360+
memset((void *)addr, 0, len);
361+
kvfree(addr);
362+
}
363+
}
352364
#endif /* _INTERNAL_H */

security/keys/keyctl.c

Lines changed: 86 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ long keyctl_update_key(key_serial_t id,
339339
payload = NULL;
340340
if (plen) {
341341
ret = -ENOMEM;
342-
payload = kmalloc(plen, GFP_KERNEL);
342+
payload = kvmalloc(plen, GFP_KERNEL);
343343
if (!payload)
344344
goto error;
345345

@@ -360,7 +360,7 @@ long keyctl_update_key(key_serial_t id,
360360

361361
key_ref_put(key_ref);
362362
error2:
363-
kzfree(payload);
363+
__kvzfree(payload, plen);
364364
error:
365365
return ret;
366366
}
@@ -797,6 +797,21 @@ long keyctl_keyring_search(key_serial_t ringid,
797797
return ret;
798798
}
799799

800+
/*
801+
* Call the read method
802+
*/
803+
static long __keyctl_read_key(struct key *key, char *buffer, size_t buflen)
804+
{
805+
long ret;
806+
807+
down_read(&key->sem);
808+
ret = key_validate(key);
809+
if (ret == 0)
810+
ret = key->type->read(key, buffer, buflen);
811+
up_read(&key->sem);
812+
return ret;
813+
}
814+
800815
/*
801816
* Read a key's payload.
802817
*
@@ -812,53 +827,107 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
812827
struct key *key;
813828
key_ref_t key_ref;
814829
long ret;
830+
char *key_data = NULL;
831+
size_t key_data_len;
815832

816833
/* find the key first */
817834
key_ref = lookup_user_key(keyid, 0, 0);
818835
if (IS_ERR(key_ref)) {
819836
ret = -ENOKEY;
820-
goto error;
837+
goto out;
821838
}
822839

823840
key = key_ref_to_ptr(key_ref);
824841

825842
ret = key_read_state(key);
826843
if (ret < 0)
827-
goto error2; /* Negatively instantiated */
844+
goto key_put_out; /* Negatively instantiated */
828845

829846
/* see if we can read it directly */
830847
ret = key_permission(key_ref, KEY_NEED_READ);
831848
if (ret == 0)
832849
goto can_read_key;
833850
if (ret != -EACCES)
834-
goto error2;
851+
goto key_put_out;
835852

836853
/* we can't; see if it's searchable from this process's keyrings
837854
* - we automatically take account of the fact that it may be
838855
* dangling off an instantiation key
839856
*/
840857
if (!is_key_possessed(key_ref)) {
841858
ret = -EACCES;
842-
goto error2;
859+
goto key_put_out;
843860
}
844861

845862
/* the key is probably readable - now try to read it */
846863
can_read_key:
847-
ret = -EOPNOTSUPP;
848-
if (key->type->read) {
849-
/* Read the data with the semaphore held (since we might sleep)
850-
* to protect against the key being updated or revoked.
864+
if (!key->type->read) {
865+
ret = -EOPNOTSUPP;
866+
goto key_put_out;
867+
}
868+
869+
if (!buffer || !buflen) {
870+
/* Get the key length from the read method */
871+
ret = __keyctl_read_key(key, NULL, 0);
872+
goto key_put_out;
873+
}
874+
875+
/*
876+
* Read the data with the semaphore held (since we might sleep)
877+
* to protect against the key being updated or revoked.
878+
*
879+
* Allocating a temporary buffer to hold the keys before
880+
* transferring them to user buffer to avoid potential
881+
* deadlock involving page fault and mmap_sem.
882+
*
883+
* key_data_len = (buflen <= PAGE_SIZE)
884+
* ? buflen : actual length of key data
885+
*
886+
* This prevents allocating arbitrary large buffer which can
887+
* be much larger than the actual key length. In the latter case,
888+
* at least 2 passes of this loop is required.
889+
*/
890+
key_data_len = (buflen <= PAGE_SIZE) ? buflen : 0;
891+
for (;;) {
892+
if (key_data_len) {
893+
key_data = kvmalloc(key_data_len, GFP_KERNEL);
894+
if (!key_data) {
895+
ret = -ENOMEM;
896+
goto key_put_out;
897+
}
898+
}
899+
900+
ret = __keyctl_read_key(key, key_data, key_data_len);
901+
902+
/*
903+
* Read methods will just return the required length without
904+
* any copying if the provided length isn't large enough.
905+
*/
906+
if (ret <= 0 || ret > buflen)
907+
break;
908+
909+
/*
910+
* The key may change (unlikely) in between 2 consecutive
911+
* __keyctl_read_key() calls. In this case, we reallocate
912+
* a larger buffer and redo the key read when
913+
* key_data_len < ret <= buflen.
851914
*/
852-
down_read(&key->sem);
853-
ret = key_validate(key);
854-
if (ret == 0)
855-
ret = key->type->read(key, buffer, buflen);
856-
up_read(&key->sem);
915+
if (ret > key_data_len) {
916+
if (unlikely(key_data))
917+
__kvzfree(key_data, key_data_len);
918+
key_data_len = ret;
919+
continue; /* Allocate buffer */
920+
}
921+
922+
if (copy_to_user(buffer, key_data, ret))
923+
ret = -EFAULT;
924+
break;
857925
}
926+
__kvzfree(key_data, key_data_len);
858927

859-
error2:
928+
key_put_out:
860929
key_put(key);
861-
error:
930+
out:
862931
return ret;
863932
}
864933

security/keys/keyring.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -459,18 +459,14 @@ static int keyring_read_iterator(const void *object, void *data)
459459
{
460460
struct keyring_read_iterator_context *ctx = data;
461461
const struct key *key = keyring_ptr_to_key(object);
462-
int ret;
463462

464463
kenter("{%s,%d},,{%zu/%zu}",
465464
key->type->name, key->serial, ctx->count, ctx->buflen);
466465

467466
if (ctx->count >= ctx->buflen)
468467
return 1;
469468

470-
ret = put_user(key->serial, ctx->buffer);
471-
if (ret < 0)
472-
return ret;
473-
ctx->buffer++;
469+
*ctx->buffer++ = key->serial;
474470
ctx->count += sizeof(key->serial);
475471
return 0;
476472
}

0 commit comments

Comments
 (0)