Commit 2543fdbd authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '6.2-rc5-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull ksmbd server fixes from Steve French:
 "Four smb3 server fixes, all also for stable:

   - fix for signing bug

   - fix to more strictly check packet length

   - add a max connections parm to limit simultaneous connections

   - fix error message flood that can occur with newer Samba xattr
     format"

* tag '6.2-rc5-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: downgrade ndr version error message to debug
  ksmbd: limit pdu length size according to connection status
  ksmbd: do not sign response to session request for guest login
  ksmbd: add max connections parameter
parents 5af6ce70 a34dc4a9
...@@ -280,7 +280,7 @@ int ksmbd_conn_handler_loop(void *p) ...@@ -280,7 +280,7 @@ int ksmbd_conn_handler_loop(void *p)
{ {
struct ksmbd_conn *conn = (struct ksmbd_conn *)p; struct ksmbd_conn *conn = (struct ksmbd_conn *)p;
struct ksmbd_transport *t = conn->transport; struct ksmbd_transport *t = conn->transport;
unsigned int pdu_size; unsigned int pdu_size, max_allowed_pdu_size;
char hdr_buf[4] = {0,}; char hdr_buf[4] = {0,};
int size; int size;
...@@ -305,13 +305,26 @@ int ksmbd_conn_handler_loop(void *p) ...@@ -305,13 +305,26 @@ int ksmbd_conn_handler_loop(void *p)
pdu_size = get_rfc1002_len(hdr_buf); pdu_size = get_rfc1002_len(hdr_buf);
ksmbd_debug(CONN, "RFC1002 header %u bytes\n", pdu_size); ksmbd_debug(CONN, "RFC1002 header %u bytes\n", pdu_size);
if (conn->status == KSMBD_SESS_GOOD)
max_allowed_pdu_size =
SMB3_MAX_MSGSIZE + conn->vals->max_write_size;
else
max_allowed_pdu_size = SMB3_MAX_MSGSIZE;
if (pdu_size > max_allowed_pdu_size) {
pr_err_ratelimited("PDU length(%u) excceed maximum allowed pdu size(%u) on connection(%d)\n",
pdu_size, max_allowed_pdu_size,
conn->status);
break;
}
/* /*
* Check if pdu size is valid (min : smb header size, * Check if pdu size is valid (min : smb header size,
* max : 0x00FFFFFF). * max : 0x00FFFFFF).
*/ */
if (pdu_size < __SMB2_HEADER_STRUCTURE_SIZE || if (pdu_size < __SMB2_HEADER_STRUCTURE_SIZE ||
pdu_size > MAX_STREAM_PROT_LEN) { pdu_size > MAX_STREAM_PROT_LEN) {
continue; break;
} }
/* 4 for rfc1002 length field */ /* 4 for rfc1002 length field */
......
...@@ -106,7 +106,8 @@ struct ksmbd_startup_request { ...@@ -106,7 +106,8 @@ struct ksmbd_startup_request {
__u32 sub_auth[3]; /* Subauth value for Security ID */ __u32 sub_auth[3]; /* Subauth value for Security ID */
__u32 smb2_max_credits; /* MAX credits */ __u32 smb2_max_credits; /* MAX credits */
__u32 smbd_max_io_size; /* smbd read write size */ __u32 smbd_max_io_size; /* smbd read write size */
__u32 reserved[127]; /* Reserved room */ __u32 max_connections; /* Number of maximum simultaneous connections */
__u32 reserved[126]; /* Reserved room */
__u32 ifc_list_sz; /* interfaces list size */ __u32 ifc_list_sz; /* interfaces list size */
__s8 ____payload[]; __s8 ____payload[];
}; };
......
...@@ -242,7 +242,7 @@ int ndr_decode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da) ...@@ -242,7 +242,7 @@ int ndr_decode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da)
return ret; return ret;
if (da->version != 3 && da->version != 4) { if (da->version != 3 && da->version != 4) {
pr_err("v%d version is not supported\n", da->version); ksmbd_debug(VFS, "v%d version is not supported\n", da->version);
return -EINVAL; return -EINVAL;
} }
...@@ -251,7 +251,7 @@ int ndr_decode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da) ...@@ -251,7 +251,7 @@ int ndr_decode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da)
return ret; return ret;
if (da->version != version2) { if (da->version != version2) {
pr_err("ndr version mismatched(version: %d, version2: %d)\n", ksmbd_debug(VFS, "ndr version mismatched(version: %d, version2: %d)\n",
da->version, version2); da->version, version2);
return -EINVAL; return -EINVAL;
} }
...@@ -457,7 +457,7 @@ int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl) ...@@ -457,7 +457,7 @@ int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)
if (ret) if (ret)
return ret; return ret;
if (acl->version != 4) { if (acl->version != 4) {
pr_err("v%d version is not supported\n", acl->version); ksmbd_debug(VFS, "v%d version is not supported\n", acl->version);
return -EINVAL; return -EINVAL;
} }
...@@ -465,7 +465,7 @@ int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl) ...@@ -465,7 +465,7 @@ int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)
if (ret) if (ret)
return ret; return ret;
if (acl->version != version2) { if (acl->version != version2) {
pr_err("ndr version mismatched(version: %d, version2: %d)\n", ksmbd_debug(VFS, "ndr version mismatched(version: %d, version2: %d)\n",
acl->version, version2); acl->version, version2);
return -EINVAL; return -EINVAL;
} }
......
...@@ -41,6 +41,7 @@ struct ksmbd_server_config { ...@@ -41,6 +41,7 @@ struct ksmbd_server_config {
unsigned int share_fake_fscaps; unsigned int share_fake_fscaps;
struct smb_sid domain_sid; struct smb_sid domain_sid;
unsigned int auth_mechs; unsigned int auth_mechs;
unsigned int max_connections;
char *conf[SERVER_CONF_WORK_GROUP + 1]; char *conf[SERVER_CONF_WORK_GROUP + 1];
}; };
......
...@@ -8663,6 +8663,7 @@ int smb3_decrypt_req(struct ksmbd_work *work) ...@@ -8663,6 +8663,7 @@ int smb3_decrypt_req(struct ksmbd_work *work)
bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work) bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work)
{ {
struct ksmbd_conn *conn = work->conn; struct ksmbd_conn *conn = work->conn;
struct ksmbd_session *sess = work->sess;
struct smb2_hdr *rsp = smb2_get_msg(work->response_buf); struct smb2_hdr *rsp = smb2_get_msg(work->response_buf);
if (conn->dialect < SMB30_PROT_ID) if (conn->dialect < SMB30_PROT_ID)
...@@ -8672,6 +8673,7 @@ bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work) ...@@ -8672,6 +8673,7 @@ bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work)
rsp = ksmbd_resp_buf_next(work); rsp = ksmbd_resp_buf_next(work);
if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE && if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE &&
sess->user && !user_guest(sess->user) &&
rsp->Status == STATUS_SUCCESS) rsp->Status == STATUS_SUCCESS)
return true; return true;
return false; return false;
......
...@@ -24,8 +24,9 @@ ...@@ -24,8 +24,9 @@
#define SMB21_DEFAULT_IOSIZE (1024 * 1024) #define SMB21_DEFAULT_IOSIZE (1024 * 1024)
#define SMB3_DEFAULT_TRANS_SIZE (1024 * 1024) #define SMB3_DEFAULT_TRANS_SIZE (1024 * 1024)
#define SMB3_MIN_IOSIZE (64 * 1024) #define SMB3_MIN_IOSIZE (64 * 1024)
#define SMB3_MAX_IOSIZE (8 * 1024 * 1024) #define SMB3_MAX_IOSIZE (8 * 1024 * 1024)
#define SMB3_MAX_MSGSIZE (4 * 4096)
/* /*
* Definitions for SMB2 Protocol Data Units (network frames) * Definitions for SMB2 Protocol Data Units (network frames)
......
...@@ -308,6 +308,9 @@ static int ipc_server_config_on_startup(struct ksmbd_startup_request *req) ...@@ -308,6 +308,9 @@ static int ipc_server_config_on_startup(struct ksmbd_startup_request *req)
if (req->smbd_max_io_size) if (req->smbd_max_io_size)
init_smbd_max_io_size(req->smbd_max_io_size); init_smbd_max_io_size(req->smbd_max_io_size);
if (req->max_connections)
server_conf.max_connections = req->max_connections;
ret = ksmbd_set_netbios_name(req->netbios_name); ret = ksmbd_set_netbios_name(req->netbios_name);
ret |= ksmbd_set_server_string(req->server_string); ret |= ksmbd_set_server_string(req->server_string);
ret |= ksmbd_set_work_group(req->work_group); ret |= ksmbd_set_work_group(req->work_group);
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#define IFACE_STATE_DOWN BIT(0) #define IFACE_STATE_DOWN BIT(0)
#define IFACE_STATE_CONFIGURED BIT(1) #define IFACE_STATE_CONFIGURED BIT(1)
static atomic_t active_num_conn;
struct interface { struct interface {
struct task_struct *ksmbd_kthread; struct task_struct *ksmbd_kthread;
struct socket *ksmbd_socket; struct socket *ksmbd_socket;
...@@ -185,8 +187,10 @@ static int ksmbd_tcp_new_connection(struct socket *client_sk) ...@@ -185,8 +187,10 @@ static int ksmbd_tcp_new_connection(struct socket *client_sk)
struct tcp_transport *t; struct tcp_transport *t;
t = alloc_transport(client_sk); t = alloc_transport(client_sk);
if (!t) if (!t) {
sock_release(client_sk);
return -ENOMEM; return -ENOMEM;
}
csin = KSMBD_TCP_PEER_SOCKADDR(KSMBD_TRANS(t)->conn); csin = KSMBD_TCP_PEER_SOCKADDR(KSMBD_TRANS(t)->conn);
if (kernel_getpeername(client_sk, csin) < 0) { if (kernel_getpeername(client_sk, csin) < 0) {
...@@ -239,6 +243,15 @@ static int ksmbd_kthread_fn(void *p) ...@@ -239,6 +243,15 @@ static int ksmbd_kthread_fn(void *p)
continue; continue;
} }
if (server_conf.max_connections &&
atomic_inc_return(&active_num_conn) >= server_conf.max_connections) {
pr_info_ratelimited("Limit the maximum number of connections(%u)\n",
atomic_read(&active_num_conn));
atomic_dec(&active_num_conn);
sock_release(client_sk);
continue;
}
ksmbd_debug(CONN, "connect success: accepted new connection\n"); ksmbd_debug(CONN, "connect success: accepted new connection\n");
client_sk->sk->sk_rcvtimeo = KSMBD_TCP_RECV_TIMEOUT; client_sk->sk->sk_rcvtimeo = KSMBD_TCP_RECV_TIMEOUT;
client_sk->sk->sk_sndtimeo = KSMBD_TCP_SEND_TIMEOUT; client_sk->sk->sk_sndtimeo = KSMBD_TCP_SEND_TIMEOUT;
...@@ -368,6 +381,8 @@ static int ksmbd_tcp_writev(struct ksmbd_transport *t, struct kvec *iov, ...@@ -368,6 +381,8 @@ static int ksmbd_tcp_writev(struct ksmbd_transport *t, struct kvec *iov,
static void ksmbd_tcp_disconnect(struct ksmbd_transport *t) static void ksmbd_tcp_disconnect(struct ksmbd_transport *t)
{ {
free_transport(TCP_TRANS(t)); free_transport(TCP_TRANS(t));
if (server_conf.max_connections)
atomic_dec(&active_num_conn);
} }
static void tcp_destroy_socket(struct socket *ksmbd_socket) static void tcp_destroy_socket(struct socket *ksmbd_socket)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment