ksmbd: throttle session setup failures to avoid dictionary attacks
authorNamjae Jeon <linkinjeon@kernel.org>
Wed, 13 Oct 2021 08:28:31 +0000 (17:28 +0900)
committerSteve French <stfrench@microsoft.com>
Wed, 20 Oct 2021 05:07:10 +0000 (00:07 -0500)
To avoid dictionary attacks (repeated session setups rapidly sent) to
connect to server, ksmbd make a delay of a 5 seconds on session setup
failure to make it harder to send enough random connection requests
to break into a server if a user insert the wrong password 10 times
in a row.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/ksmbd/ksmbd_netlink.h
fs/ksmbd/mgmt/user_config.c
fs/ksmbd/mgmt/user_config.h
fs/ksmbd/smb2pdu.c
fs/ksmbd/transport_ipc.c
fs/ksmbd/transport_ipc.h

index 2fbe2bc..c6718a0 100644 (file)
@@ -211,6 +211,7 @@ struct ksmbd_tree_disconnect_request {
  */
 struct ksmbd_logout_request {
        __s8    account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; /* user account name */
+       __u32   account_flags;
 };
 
 /*
@@ -317,6 +318,7 @@ enum KSMBD_TREE_CONN_STATUS {
 #define KSMBD_USER_FLAG_BAD_UID                BIT(2)
 #define KSMBD_USER_FLAG_BAD_USER       BIT(3)
 #define KSMBD_USER_FLAG_GUEST_ACCOUNT  BIT(4)
+#define KSMBD_USER_FLAG_DELAY_SESSION  BIT(5)
 
 /*
  * Share config flags.
index d21629a..1019d36 100644 (file)
@@ -55,7 +55,7 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp)
 
 void ksmbd_free_user(struct ksmbd_user *user)
 {
-       ksmbd_ipc_logout_request(user->name);
+       ksmbd_ipc_logout_request(user->name, user->flags);
        kfree(user->name);
        kfree(user->passkey);
        kfree(user);
index b2bb074..aff80b0 100644 (file)
@@ -18,6 +18,7 @@ struct ksmbd_user {
 
        size_t                  passkey_sz;
        char                    *passkey;
+       unsigned int            failed_login_count;
 };
 
 static inline bool user_guest(struct ksmbd_user *user)
index e0f3a44..cf7db5f 100644 (file)
@@ -1779,9 +1779,30 @@ out_err:
                conn->mechToken = NULL;
        }
 
-       if (rc < 0 && sess) {
-               ksmbd_session_destroy(sess);
-               work->sess = NULL;
+       if (rc < 0) {
+               /*
+                * SecurityBufferOffset should be set to zero
+                * in session setup error response.
+                */
+               rsp->SecurityBufferOffset = 0;
+
+               if (sess) {
+                       bool try_delay = false;
+
+                       /*
+                        * To avoid dictionary attacks (repeated session setups rapidly sent) to
+                        * connect to server, ksmbd make a delay of a 5 seconds on session setup
+                        * failure to make it harder to send enough random connection requests
+                        * to break into a server.
+                        */
+                       if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION)
+                               try_delay = true;
+
+                       ksmbd_session_destroy(sess);
+                       work->sess = NULL;
+                       if (try_delay)
+                               ssleep(5);
+               }
        }
 
        return rc;
index 44aea33..1acf189 100644 (file)
@@ -601,7 +601,7 @@ int ksmbd_ipc_tree_disconnect_request(unsigned long long session_id,
        return ret;
 }
 
-int ksmbd_ipc_logout_request(const char *account)
+int ksmbd_ipc_logout_request(const char *account, int flags)
 {
        struct ksmbd_ipc_msg *msg;
        struct ksmbd_logout_request *req;
@@ -616,6 +616,7 @@ int ksmbd_ipc_logout_request(const char *account)
 
        msg->type = KSMBD_EVENT_LOGOUT_REQUEST;
        req = (struct ksmbd_logout_request *)msg->payload;
+       req->account_flags = flags;
        strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ);
 
        ret = ipc_msg_send(msg);
index 9eacc89..5e5b90a 100644 (file)
@@ -25,7 +25,7 @@ ksmbd_ipc_tree_connect_request(struct ksmbd_session *sess,
                               struct sockaddr *peer_addr);
 int ksmbd_ipc_tree_disconnect_request(unsigned long long session_id,
                                      unsigned long long connect_id);
-int ksmbd_ipc_logout_request(const char *account);
+int ksmbd_ipc_logout_request(const char *account, int flags);
 struct ksmbd_share_config_response *
 ksmbd_ipc_share_config_request(const char *name);
 struct ksmbd_spnego_authen_response *