lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <YFS66J9CjCQYR0xi@mwanda>
Date:   Fri, 19 Mar 2021 17:53:28 +0300
From:   Dan Carpenter <dan.carpenter@...cle.com>
To:     Namjae Jeon <namjae.jeon@...sung.com>
Cc:     Hyunchul Lee <hyc.lee@...il.com>,
        Steve French <stfrench@...rosoft.com>,
        Ronnie Sahlberg <lsahlber@...hat.com>,
        Fredrik Ternerot <fredrikt@...s.com>,
        Marios Makassikis <mmakassikis@...ebox.fr>,
        Sergey Senozhatsky <sergey.senozhatsky@...il.com>,
        linux-kernel@...r.kernel.org, kernel-janitors@...r.kernel.org
Subject: [PATCH] cifsd: fix error handling in ksmbd_server_init()

The error handling in ksmbd_server_init() uses "one function to free
everything style" which is impossible to audit and leads to several
canonical bugs.  When we free something that wasn't allocated it may be
uninitialized, an error pointer, freed in a different function or we
try freeing "foo->bar" when "foo" is a NULL pointer.  And since the
code is impossible to audit then it leads to memory leaks.

In the ksmbd_server_init() function, every goto will lead to a crash
because we have not allocated the work queue but we call
ksmbd_workqueue_destroy() which tries to flush a NULL work queue.
Another bug is if ksmbd_init_buffer_pools() fails then it leads to a
double free because we free "work_cache" twice.  A third type of bug is
that we forgot to call ksmbd_release_inode_hash() so that is a resource
leak.

A better way to write error handling is for every function to clean up
after itself and never leave things partially allocated.  Then we can
use "free the last successfully allocated resource" style.  That way
when someone is reading the code they can just track the last resource
in their head and verify that the goto matches what they expect.

In this patch I modified ksmbd_ipc_init() to clean up after itself and
then I converted ksmbd_server_init() to use gotos to clean up.

Fixes: cabcebc31de4 ("cifsd: introduce SMB3 kernel server")
Signed-off-by: Dan Carpenter <dan.carpenter@...cle.com>
---
 fs/cifsd/server.c        | 33 +++++++++++++++++++++++----------
 fs/cifsd/transport_ipc.c | 14 +++++++++++---
 2 files changed, 34 insertions(+), 13 deletions(-)

diff --git a/fs/cifsd/server.c b/fs/cifsd/server.c
index b9e114f8a5d2..aea7b6788cac 100644
--- a/fs/cifsd/server.c
+++ b/fs/cifsd/server.c
@@ -569,39 +569,52 @@ static int __init ksmbd_server_init(void)
 
 	ret = server_conf_init();
 	if (ret)
-		return ret;
+		goto err_unregister;
 
 	ret = ksmbd_init_buffer_pools();
 	if (ret)
-		return ret;
+		goto err_unregister;
 
 	ret = ksmbd_init_session_table();
 	if (ret)
-		goto error;
+		goto err_destroy_pools;
 
 	ret = ksmbd_ipc_init();
 	if (ret)
-		goto error;
+		goto err_free_session_table;
 
 	ret = ksmbd_init_global_file_table();
 	if (ret)
-		goto error;
+		goto err_ipc_release;
 
 	ret = ksmbd_inode_hash_init();
 	if (ret)
-		goto error;
+		goto err_destroy_file_table;
 
 	ret = ksmbd_crypto_create();
 	if (ret)
-		goto error;
+		goto err_release_inode_hash;
 
 	ret = ksmbd_workqueue_init();
 	if (ret)
-		goto error;
+		goto err_crypto_destroy;
 	return 0;
 
-error:
-	ksmbd_server_shutdown();
+err_crypto_destroy:
+	ksmbd_crypto_destroy();
+err_release_inode_hash:
+	ksmbd_release_inode_hash();
+err_destroy_file_table:
+	ksmbd_free_global_file_table();
+err_ipc_release:
+	ksmbd_ipc_release();
+err_free_session_table:
+	ksmbd_free_session_table();
+err_destroy_pools:
+	ksmbd_destroy_buffer_pools();
+err_unregister:
+	class_unregister(&ksmbd_control_class);
+
 	return ret;
 }
 
diff --git a/fs/cifsd/transport_ipc.c b/fs/cifsd/transport_ipc.c
index b91fa265f85d..d2432f656635 100644
--- a/fs/cifsd/transport_ipc.c
+++ b/fs/cifsd/transport_ipc.c
@@ -890,11 +890,19 @@ int ksmbd_ipc_init(void)
 	if (ret) {
 		ksmbd_err("Failed to register KSMBD netlink interface %d\n",
 				ret);
-		return ret;
+		goto cancel_work;
 	}
 
 	ida = ksmbd_ida_alloc();
-	if (!ida)
-		return -ENOMEM;
+	if (!ida) {
+		ret = -ENOMEM;
+		goto unregister;
+	}
 	return 0;
+
+unregister:
+	genl_unregister_family(&ksmbd_genl_family);
+cancel_work:
+	cancel_delayed_work_sync(&ipc_timer_work);
+	return ret;
 }
-- 
2.30.2

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ