]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ipv6: sr: fix memleak in seg6_hmac_init_algo
authorHangbin Liu <liuhangbin@gmail.com>
Fri, 17 May 2024 00:54:35 +0000 (08:54 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 21 May 2024 11:16:25 +0000 (13:16 +0200)
seg6_hmac_init_algo returns without cleaning up the previous allocations
if one fails, so it's going to leak all that memory and the crypto tfms.

Update seg6_hmac_exit to only free the memory when allocated, so we can
reuse the code directly.

Fixes: bf355b8d2c30 ("ipv6: sr: add core files for SR HMAC support")
Reported-by: Sabrina Dubroca <sd@queasysnail.net>
Closes: https://lore.kernel.org/netdev/Zj3bh-gE7eT6V6aH@hog/
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
Link: https://lore.kernel.org/r/20240517005435.2600277-1-liuhangbin@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
net/ipv6/seg6_hmac.c

index 861e0366f549d523f20dc92c79bef1be8805e0c7..bbf5b84a70fcabe0d380814aa4d99b95006925b8 100644 (file)
@@ -356,6 +356,7 @@ static int seg6_hmac_init_algo(void)
        struct crypto_shash *tfm;
        struct shash_desc *shash;
        int i, alg_count, cpu;
+       int ret = -ENOMEM;
 
        alg_count = ARRAY_SIZE(hmac_algos);
 
@@ -366,12 +367,14 @@ static int seg6_hmac_init_algo(void)
                algo = &hmac_algos[i];
                algo->tfms = alloc_percpu(struct crypto_shash *);
                if (!algo->tfms)
-                       return -ENOMEM;
+                       goto error_out;
 
                for_each_possible_cpu(cpu) {
                        tfm = crypto_alloc_shash(algo->name, 0, 0);
-                       if (IS_ERR(tfm))
-                               return PTR_ERR(tfm);
+                       if (IS_ERR(tfm)) {
+                               ret = PTR_ERR(tfm);
+                               goto error_out;
+                       }
                        p_tfm = per_cpu_ptr(algo->tfms, cpu);
                        *p_tfm = tfm;
                }
@@ -383,18 +386,22 @@ static int seg6_hmac_init_algo(void)
 
                algo->shashs = alloc_percpu(struct shash_desc *);
                if (!algo->shashs)
-                       return -ENOMEM;
+                       goto error_out;
 
                for_each_possible_cpu(cpu) {
                        shash = kzalloc_node(shsize, GFP_KERNEL,
                                             cpu_to_node(cpu));
                        if (!shash)
-                               return -ENOMEM;
+                               goto error_out;
                        *per_cpu_ptr(algo->shashs, cpu) = shash;
                }
        }
 
        return 0;
+
+error_out:
+       seg6_hmac_exit();
+       return ret;
 }
 
 int __init seg6_hmac_init(void)
@@ -412,22 +419,29 @@ int __net_init seg6_hmac_net_init(struct net *net)
 void seg6_hmac_exit(void)
 {
        struct seg6_hmac_algo *algo = NULL;
+       struct crypto_shash *tfm;
+       struct shash_desc *shash;
        int i, alg_count, cpu;
 
        alg_count = ARRAY_SIZE(hmac_algos);
        for (i = 0; i < alg_count; i++) {
                algo = &hmac_algos[i];
-               for_each_possible_cpu(cpu) {
-                       struct crypto_shash *tfm;
-                       struct shash_desc *shash;
 
-                       shash = *per_cpu_ptr(algo->shashs, cpu);
-                       kfree(shash);
-                       tfm = *per_cpu_ptr(algo->tfms, cpu);
-                       crypto_free_shash(tfm);
+               if (algo->shashs) {
+                       for_each_possible_cpu(cpu) {
+                               shash = *per_cpu_ptr(algo->shashs, cpu);
+                               kfree(shash);
+                       }
+                       free_percpu(algo->shashs);
+               }
+
+               if (algo->tfms) {
+                       for_each_possible_cpu(cpu) {
+                               tfm = *per_cpu_ptr(algo->tfms, cpu);
+                               crypto_free_shash(tfm);
+                       }
+                       free_percpu(algo->tfms);
                }
-               free_percpu(algo->tfms);
-               free_percpu(algo->shashs);
        }
 }
 EXPORT_SYMBOL(seg6_hmac_exit);