Просмотр исходного кода

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull key fixes from James Morris:

 - fix a buffer overflow when displaying /proc/keys [CVE-2016-7042].

 - fix broken initialisation in the big_key implementation that can
   result in an oops.

 - make big_key depend on having a random number generator available in
   Kconfig.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  security/keys: make BIG_KEYS dependent on stdrng.
  KEYS: Sort out big_key initialisation
  KEYS: Fix short sprintf buffer in /proc/keys show function
Linus Torvalds 9 лет назад
Родитель
Сommit
43937003de
3 измененных файлов с 34 добавлено и 29 удалено
  1. 1 1
      security/keys/Kconfig
  2. 32 27
      security/keys/big_key.c
  3. 1 1
      security/keys/proc.c

+ 1 - 1
security/keys/Kconfig

@@ -41,7 +41,7 @@ config BIG_KEYS
 	bool "Large payload keys"
 	bool "Large payload keys"
 	depends on KEYS
 	depends on KEYS
 	depends on TMPFS
 	depends on TMPFS
-	select CRYPTO
+	depends on (CRYPTO_ANSI_CPRNG = y || CRYPTO_DRBG = y)
 	select CRYPTO_AES
 	select CRYPTO_AES
 	select CRYPTO_ECB
 	select CRYPTO_ECB
 	select CRYPTO_RNG
 	select CRYPTO_RNG

+ 32 - 27
security/keys/big_key.c

@@ -9,6 +9,7 @@
  * 2 of the Licence, or (at your option) any later version.
  * 2 of the Licence, or (at your option) any later version.
  */
  */
 
 
+#define pr_fmt(fmt) "big_key: "fmt
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/seq_file.h>
 #include <linux/seq_file.h>
 #include <linux/file.h>
 #include <linux/file.h>
@@ -341,44 +342,48 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
  */
  */
 static int __init big_key_init(void)
 static int __init big_key_init(void)
 {
 {
-	return register_key_type(&key_type_big_key);
-}
-
-/*
- * Initialize big_key crypto and RNG algorithms
- */
-static int __init big_key_crypto_init(void)
-{
-	int ret = -EINVAL;
+	struct crypto_skcipher *cipher;
+	struct crypto_rng *rng;
+	int ret;
 
 
-	/* init RNG */
-	big_key_rng = crypto_alloc_rng(big_key_rng_name, 0, 0);
-	if (IS_ERR(big_key_rng)) {
-		big_key_rng = NULL;
-		return -EFAULT;
+	rng = crypto_alloc_rng(big_key_rng_name, 0, 0);
+	if (IS_ERR(rng)) {
+		pr_err("Can't alloc rng: %ld\n", PTR_ERR(rng));
+		return PTR_ERR(rng);
 	}
 	}
 
 
+	big_key_rng = rng;
+
 	/* seed RNG */
 	/* seed RNG */
-	ret = crypto_rng_reset(big_key_rng, NULL, crypto_rng_seedsize(big_key_rng));
-	if (ret)
-		goto error;
+	ret = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
+	if (ret) {
+		pr_err("Can't reset rng: %d\n", ret);
+		goto error_rng;
+	}
 
 
 	/* init block cipher */
 	/* init block cipher */
-	big_key_skcipher = crypto_alloc_skcipher(big_key_alg_name,
-						 0, CRYPTO_ALG_ASYNC);
-	if (IS_ERR(big_key_skcipher)) {
-		big_key_skcipher = NULL;
-		ret = -EFAULT;
-		goto error;
+	cipher = crypto_alloc_skcipher(big_key_alg_name, 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(cipher)) {
+		ret = PTR_ERR(cipher);
+		pr_err("Can't alloc crypto: %d\n", ret);
+		goto error_rng;
+	}
+
+	big_key_skcipher = cipher;
+
+	ret = register_key_type(&key_type_big_key);
+	if (ret < 0) {
+		pr_err("Can't register type: %d\n", ret);
+		goto error_cipher;
 	}
 	}
 
 
 	return 0;
 	return 0;
 
 
-error:
+error_cipher:
+	crypto_free_skcipher(big_key_skcipher);
+error_rng:
 	crypto_free_rng(big_key_rng);
 	crypto_free_rng(big_key_rng);
-	big_key_rng = NULL;
 	return ret;
 	return ret;
 }
 }
 
 
-device_initcall(big_key_init);
-late_initcall(big_key_crypto_init);
+late_initcall(big_key_init);

+ 1 - 1
security/keys/proc.c

@@ -181,7 +181,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
 	struct timespec now;
 	struct timespec now;
 	unsigned long timo;
 	unsigned long timo;
 	key_ref_t key_ref, skey_ref;
 	key_ref_t key_ref, skey_ref;
-	char xbuf[12];
+	char xbuf[16];
 	int rc;
 	int rc;
 
 
 	struct keyring_search_context ctx = {
 	struct keyring_search_context ctx = {