- Prevent unintended data exposure by clearing pipe compound padding and

the response buffer.
 
  - Initialize missing fields in FS_OBJECT_ID_INFORMATION,
    FS_CONTROL_INFORMATION, and FS_POSIX_INFORMATION.
 
  - Propagate DACL parsing and allocation failures so malformed security
    descriptors are rejected.
 
  - Rate-limit errors for unmapped SIDs to prevent kernel log flooding.
 
  - Drain multichannel sessions during LOGOFF, wake deferred locks and
    cancellable requests, and ensure cancellation callbacks run only once.
 
  - Fix listener kthread reference handling and teardown ordering during
    netdevice events.
 
  - Validate normalized-name and IPC share configuration response lengths.
 
  - Update the KSMBD MAINTAINERS entry and add Paulo Alcantara as
    an SMBDIRECT co-maintainer.
 -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEE6NzKS6Uv/XAAGHgyZwv7A1FEIQgFAmqWnz0WHGxpbmtpbmpl
 b25Aa2VybmVsLm9yZwAKCRBnC/sDUUQhCJK8EACCE2K2p9CH6kiy9VnMjEqTbIBF
 ZRCmxrspoPAMuTbK6529dXHUVTsXlUdJ/FVzGwNLtvXwEIVjNaQDqBEFWCdPElE+
 8grKsC1S3gH3t8Z1wT6eNh5cpDoA+rWJDbNK4DsmHdoVagyjd9dd7fkMi7nq0WJS
 NO7BTHaTuTaZDul8UXc1gqkVLviZZWkrtkGVVnsJV1z5cFls6P81cVmtzP0836cU
 kVDYSI0EZnX+1P5CtOxL3r5LDBex6lRHU+rj1ypJRJDM2nR+bYIeJk+XMjylKCHT
 liPj7dwI/ptVzp+n3dbcTyhLZayDhZ0/GeJanX2/midtiNSKhao9h94BymPU91jV
 JugPlkAO8Vqwo7xojWRqudz4Kg/vgr66NexQ/3W2tuRXXFN4kEWmQG0N5+kH0K3d
 sJ5xA9uLj24+d29fjylkdSGpuRLR8XcR01he2CaqLRopXZrCxFChwzZwbads1rI/
 kXtYrORB0u99ScwTRQeW90dzeZ+1R3aHOyf8H86zyJ07l2NxG8t5L/49vuaiaiEZ
 5r4hhPVumlmDQdPoOcugOmkJL68+W4TzS7UfcOSgq43W31BE1dYsaX7u4MHNk/Nq
 UiWJJPArJ3ry8e4GLqQXx4ylZJnykGS9s676gFCO1GAI+eXoQ4R0k7RCKy/TW0ap
 t3oa0Yj+Y4QAZCD3Rw==
 =UL/J
 -----END PGP SIGNATURE-----

Merge tag 'ksmbd-for-7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/smb

Pull smb server fixes from Namjae Jeon:

 - Prevent unintended data exposure by clearing pipe compound padding
   and the response buffer

 - Initialize missing fields in FS_OBJECT_ID_INFORMATION,
   FS_CONTROL_INFORMATION, and FS_POSIX_INFORMATION

 - Propagate DACL parsing and allocation failures so malformed security
   descriptors are rejected

 - Rate-limit errors for unmapped SIDs to prevent kernel log flooding

 - Drain multichannel sessions during LOGOFF, wake deferred locks and
   cancellable requests, and ensure cancellation callbacks run only once

 - Fix listener kthread reference handling and teardown ordering during
   netdevice events

 - Validate normalized-name and IPC share configuration response lengths

 - Update the KSMBD MAINTAINERS entry and add Paulo Alcantara as an
   SMBDIRECT co-maintainer

* tag 'ksmbd-for-7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/smb:
  ksmbd: validate normalized name response length
  ksmbd: fix listener task lifetime on netdev events
  ksmbd: prevent out-of-bounds reads in share config responses
  ksmbd: rate limit unmapped SID errors
  ksmbd: propagate DACL parsing errors
  ksmbd: zero pipe read compound padding
  ksmbd: safely drain sessions during logoff
  MAINTAINERS: Update the KSMBD entry
  MAINTAINERS: Add Paulo Alcantara as an SMBDIRECT co-maintainer
  ksmbd: fill in FileSysIdentifier in FS_POSIX_INFORMATION
  ksmbd: initialize FileSystemControlFlags in FS_CONTROL_INFORMATION
  ksmbd: zero the FS_OBJECT_ID_INFORMATION buffer before filling it in
This commit is contained in:
Linus Torvalds 2026-09-01 08:17:01 -07:00
commit 9a58da8005
11 changed files with 208 additions and 73 deletions

View File

@ -14236,8 +14236,6 @@ F: tools/testing/selftests/
KERNEL SMB3 SERVER (KSMBD)
M: Namjae Jeon <linkinjeon@kernel.org>
M: Namjae Jeon <linkinjeon@samba.org>
M: Steve French <smfrench@gmail.com>
M: Steve French <sfrench@samba.org>
R: Sergey Senozhatsky <senozhatsky@chromium.org>
R: Tom Talpey <tom@talpey.com>
R: ChenXiaoSong <chenxiaosong@chenxiaosong.com>
@ -25232,10 +25230,9 @@ F: Documentation/admin-guide/LSM/Smack.rst
F: security/smack/
SMBDIRECT (RDMA Stream Transport with Read/Write-Offload, MS-SMBD)
M: Steve French <smfrench@gmail.com>
M: Steve French <sfrench@samba.org>
M: Namjae Jeon <linkinjeon@kernel.org>
M: Namjae Jeon <linkinjeon@samba.org>
M: Paulo Alcantara <pc@manguebit.org>
R: Stefan Metzmacher <metze@samba.org>
R: Tom Talpey <tom@talpey.com>
L: linux-cifs@vger.kernel.org

View File

@ -13,6 +13,7 @@
#include "mgmt/ksmbd_ida.h"
#include "mgmt/user_session.h"
#include "connection.h"
#include "vfs_cache.h"
#include "compress.h"
#include "transport_tcp.h"
#include "transport_rdma.h"
@ -384,12 +385,12 @@ static void ksmbd_conn_cancel_async_requests(struct ksmbd_conn *conn)
spin_lock(&conn->request_lock);
list_for_each_entry_safe(work, tmp, &conn->async_requests,
async_request_entry) {
if (work->state != KSMBD_WORK_ACTIVE)
if (cmpxchg(&work->state, KSMBD_WORK_ACTIVE,
KSMBD_WORK_CANCELLED) != KSMBD_WORK_ACTIVE)
continue;
ksmbd_debug(CONN, "Cancel async request id %d\n",
work->async_id);
work->state = KSMBD_WORK_CANCELLED;
if (work->cancel_fn)
work->cancel_fn(work->cancel_argv);
}
@ -473,6 +474,9 @@ int ksmbd_conn_wait_idle_sess(struct ksmbd_conn *curr_conn,
if (retry_count >= max_timeout)
return -EIO;
/* A blocked byte-range lock cannot drain until teardown wakes it. */
ksmbd_wake_session_blocked_works(sess);
down_read(&conn_list_lock);
hash_for_each(conn_list, bkt, conn, hlist) {
if (ksmbd_session_is_bound_to_conn(sess, conn)) {

View File

@ -146,9 +146,9 @@ static struct ksmbd_share_config *__share_lookup(const char *name)
static int parse_veto_list(struct ksmbd_share_config *share,
char *veto_list,
int veto_list_sz)
size_t veto_list_sz)
{
int sz = 0;
size_t sz;
if (!veto_list_sz)
return 0;
@ -156,7 +156,7 @@ static int parse_veto_list(struct ksmbd_share_config *share,
while (veto_list_sz > 0) {
struct ksmbd_veto_pattern *p;
sz = strlen(veto_list);
sz = strnlen(veto_list, veto_list_sz);
if (!sz)
break;
@ -164,7 +164,7 @@ static int parse_veto_list(struct ksmbd_share_config *share,
if (!p)
return -ENOMEM;
p->pattern = kstrdup(veto_list, KSMBD_DEFAULT_GFP);
p->pattern = kstrndup(veto_list, sz, KSMBD_DEFAULT_GFP);
if (!p->pattern) {
kfree(p);
return -ENOMEM;
@ -172,6 +172,9 @@ static int parse_veto_list(struct ksmbd_share_config *share,
list_add(&p->list, &share->veto_list);
if (sz == veto_list_sz)
break;
veto_list += sz + 1;
veto_list_sz -= (sz + 1);
}
@ -224,17 +227,28 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work,
}
if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
int path_len = PATH_MAX;
size_t path_len;
if (resp->payload_sz)
path_len = resp->payload_sz - resp->veto_list_sz;
share->path = kstrndup(ksmbd_share_config_path(resp), path_len,
KSMBD_DEFAULT_GFP);
if (!share->path) {
ret = -ENOMEM;
if (resp->payload_sz <= resp->veto_list_sz) {
ret = -EINVAL;
} else {
ret = 0;
path_len = resp->payload_sz - resp->veto_list_sz;
if (resp->veto_list_sz)
path_len--;
if (!path_len) {
ret = -EINVAL;
} else {
share->path = kstrndup(
ksmbd_share_config_path(resp),
path_len, KSMBD_DEFAULT_GFP);
if (!share->path)
ret = -ENOMEM;
else
ret = 0;
}
}
if (share->path) {
share->path_sz = strlen(share->path);
while (share->path_sz > 1 &&
share->path[share->path_sz - 1] == '/')

View File

@ -666,10 +666,21 @@ void destroy_previous_session(struct ksmbd_conn *conn,
memcmp(user->passkey, prev_user->passkey, user->passkey_sz))
goto out;
down_write(&prev_sess->chann_lock);
if (prev_sess->tearing_down) {
up_write(&prev_sess->chann_lock);
goto out;
}
prev_sess->tearing_down = true;
up_write(&prev_sess->chann_lock);
ksmbd_all_conn_set_status(prev_sess, KSMBD_SESS_NEED_RECONNECT);
err = ksmbd_conn_wait_idle_sess(conn, prev_sess);
if (err) {
ksmbd_all_conn_set_status(prev_sess, KSMBD_SESS_NEED_SETUP);
down_write(&prev_sess->chann_lock);
prev_sess->tearing_down = false;
up_write(&prev_sess->chann_lock);
ksmbd_all_conn_set_status(prev_sess, KSMBD_SESS_GOOD);
goto out;
}

View File

@ -42,6 +42,7 @@ struct ksmbd_session {
bool sign;
bool enc;
bool tearing_down;
int state;
__u8 *Preauth_HashValue;

View File

@ -97,6 +97,11 @@ static int register_session_channel(struct ksmbd_session *sess,
int rc = 0;
down_write(&sess->chann_lock);
if (sess->tearing_down) {
rc = -ESHUTDOWN;
goto out;
}
if (xa_load(&sess->ksmbd_chann_list, (long)conn))
goto out;
@ -873,7 +878,8 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work)
req = smb_get_msg(work->request_buf);
if ((req->InfoType == SMB2_O_INFO_FILE &&
(req->FileInfoClass == FILE_FULL_EA_INFORMATION ||
req->FileInfoClass == FILE_ALL_INFORMATION)) ||
req->FileInfoClass == FILE_ALL_INFORMATION ||
req->FileInfoClass == FILE_NORMALIZED_NAME_INFORMATION)) ||
req->InfoType == SMB2_O_INFO_SECURITY)
sz = large_sz;
}
@ -3086,17 +3092,41 @@ int smb2_session_logoff(struct ksmbd_work *work)
smb2_set_err_rsp(work);
return -ENOENT;
}
down_write(&sess->chann_lock);
if (sess->tearing_down) {
up_write(&sess->chann_lock);
ksmbd_conn_unlock(conn);
rsp->hdr.Status = STATUS_USER_SESSION_DELETED;
smb2_set_err_rsp(work);
return -ENOENT;
}
sess->tearing_down = true;
up_write(&sess->chann_lock);
ksmbd_all_conn_set_status(sess, KSMBD_SESS_NEED_RECONNECT);
ksmbd_conn_unlock(conn);
err = ksmbd_conn_wait_idle_sess(conn, sess);
if (err) {
down_write(&sess->chann_lock);
sess->tearing_down = false;
up_write(&sess->chann_lock);
ksmbd_all_conn_set_status(sess, KSMBD_SESS_GOOD);
rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;
smb2_set_err_rsp(work);
return err;
}
ksmbd_close_session_fds(work);
ksmbd_conn_wait_idle(conn);
if (ksmbd_tree_conn_session_logoff(sess)) {
ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
smb2_set_err_rsp(work);
return -ENOENT;
err = -ENOENT;
} else {
err = 0;
}
down_write(&conn->session_lock);
@ -3106,6 +3136,9 @@ int smb2_session_logoff(struct ksmbd_work *work)
ksmbd_all_conn_set_status(sess, KSMBD_SESS_NEED_SETUP);
if (err)
return err;
rsp->StructureSize = cpu_to_le16(4);
err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp));
if (err) {
@ -6757,7 +6790,7 @@ static int get_file_normalized_name_info(struct ksmbd_work *work,
{
struct smb2_file_alt_name_info *file_info;
char *filename, *normalized, *stream_name;
int conv_len, filename_len;
int buf_free_len, conv_len, filename_len;
if (work->conn->dialect < SMB311_PROT_ID) {
rsp->hdr.Status = STATUS_NOT_SUPPORTED;
@ -6781,6 +6814,14 @@ static int get_file_normalized_name_info(struct ksmbd_work *work,
return -ENOMEM;
filename_len = strlen(normalized);
buf_free_len = smb2_resp_buf_len(work, sizeof(*rsp) +
sizeof(*file_info));
if (buf_free_len < 0 ||
(size_t)buf_free_len < (filename_len + 1) * sizeof(__le16)) {
kfree(normalized);
return -EINVAL;
}
file_info = (struct smb2_file_alt_name_info *)rsp->Buffer;
conv_len = smbConvertToUTF16((__le16 *)file_info->FileName,
normalized, filename_len,
@ -7444,6 +7485,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
struct object_id_info *info;
info = (struct object_id_info *)(rsp->Buffer);
memset(info, 0, sizeof(*info));
if (path.mnt->mnt_sb->s_uuid_len == 16)
memcpy(info->objid, path.mnt->mnt_sb->s_uuid.b,
@ -7499,6 +7541,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->FreeSpaceStopFiltering = 0;
info->DefaultQuotaThreshold = cpu_to_le64(SMB2_NO_FID);
info->DefaultQuotaLimit = cpu_to_le64(SMB2_NO_FID);
info->FileSystemControlFlags = 0;
info->Padding = 0;
rsp->OutputBufferLength = cpu_to_le32(48);
fixed_len = 48;
@ -7521,6 +7564,9 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->UserBlocksAvail = cpu_to_le64(stfs.f_bavail);
info->TotalFileNodes = cpu_to_le64(stfs.f_files);
info->FreeFileNodes = cpu_to_le64(stfs.f_ffree);
info->FileSysIdentifier =
cpu_to_le64((u64)(u32)stfs.f_fsid.val[1] << 32 |
(u32)stfs.f_fsid.val[0]);
rsp->OutputBufferLength = cpu_to_le32(56);
fixed_len = 56;
}
@ -8620,13 +8666,18 @@ static noinline int smb2_read_pipe(struct ksmbd_work *work)
}
aux_payload_buf =
kvmalloc(rpc_resp->payload_sz, KSMBD_DEFAULT_GFP);
kvmalloc(ALIGN(rpc_resp->payload_sz, 8),
KSMBD_DEFAULT_GFP);
if (!aux_payload_buf) {
err = -ENOMEM;
goto out;
}
memcpy(aux_payload_buf, rpc_resp->payload, rpc_resp->payload_sz);
if (rpc_resp->payload_sz & 7)
memset(aux_payload_buf + rpc_resp->payload_sz, 0,
ALIGN(rpc_resp->payload_sz, 8) -
rpc_resp->payload_sz);
nbytes = rpc_resp->payload_sz;
err = ksmbd_iov_pin_rsp_read(work, (void *)rsp,
@ -9680,14 +9731,14 @@ int smb2_cancel(struct ksmbd_work *work)
* still on conn->async_requests with a live cancel_fn
* pointing at the freed file_lock.
*/
if (iter->state != KSMBD_WORK_ACTIVE)
if (cmpxchg(&iter->state, KSMBD_WORK_ACTIVE,
KSMBD_WORK_CANCELLED) != KSMBD_WORK_ACTIVE)
break;
ksmbd_debug(SMB,
"smb2 with AsyncId %llu cancelled command = 0x%x\n",
le64_to_cpu(hdr->Id.AsyncId),
le16_to_cpu(chdr->Command));
iter->state = KSMBD_WORK_CANCELLED;
if (iter->cancel_fn == smb2_notify_cancel_fn)
cancelled_notify =
smb2_notify_cancel_claim(iter->cancel_argv);
@ -9716,11 +9767,16 @@ int smb2_cancel(struct ksmbd_work *work)
iter == work)
continue;
if (cmpxchg(&iter->state, KSMBD_WORK_ACTIVE,
KSMBD_WORK_CANCELLED) != KSMBD_WORK_ACTIVE)
break;
ksmbd_debug(SMB,
"smb2 with mid %llu cancelled command = 0x%x\n",
le64_to_cpu(hdr->MessageId),
le16_to_cpu(chdr->Command));
iter->state = KSMBD_WORK_CANCELLED;
if (iter->cancel_fn)
iter->cancel_fn(iter->cancel_argv);
break;
}
spin_unlock(&conn->request_lock);

View File

@ -383,10 +383,10 @@ void free_acl_state(struct posix_acl_state *state)
kfree(state->groups);
}
static void parse_dacl(struct mnt_idmap *idmap,
struct smb_acl *pdacl, char *end_of_acl,
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
struct smb_fattr *fattr)
static int parse_dacl(struct mnt_idmap *idmap,
struct smb_acl *pdacl, char *end_of_acl,
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
struct smb_fattr *fattr)
{
int i, ret;
u16 num_aces = 0;
@ -400,13 +400,13 @@ static void parse_dacl(struct mnt_idmap *idmap,
bool owner_found = false, group_found = false, others_found = false;
if (!pdacl)
return;
return 0;
/* validate that we do not go past end of acl */
if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) ||
end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
pr_err("ACL too small to parse DACL\n");
return;
return -EINVAL;
}
ksmbd_debug(SMB, "DACL revision %d size %d num aces %d\n",
@ -418,31 +418,31 @@ static void parse_dacl(struct mnt_idmap *idmap,
num_aces = le16_to_cpu(pdacl->num_aces);
if (num_aces <= 0)
return;
return 0;
dacl_size = le16_to_cpu(pdacl->size);
if (dacl_size < sizeof(struct smb_acl))
return;
return -EINVAL;
if (num_aces > (dacl_size - sizeof(struct smb_acl)) /
(offsetof(struct smb_ace, sid) +
offsetof(struct smb_sid, sub_auth) + sizeof(__le16)))
return;
return -EINVAL;
ret = init_acl_state(&acl_state, num_aces);
if (ret)
return;
return ret;
ret = init_acl_state(&default_acl_state, num_aces);
if (ret) {
free_acl_state(&acl_state);
return;
return ret;
}
ppace = kmalloc_objs(struct smb_ace *, num_aces, KSMBD_DEFAULT_GFP);
if (!ppace) {
free_acl_state(&default_acl_state);
free_acl_state(&acl_state);
return;
return -ENOMEM;
}
/*
@ -451,8 +451,10 @@ static void parse_dacl(struct mnt_idmap *idmap,
* user/group/other have no permissions
*/
for (i = 0; i < num_aces; ++i) {
if (end_of_acl - acl_base < acl_size)
break;
if (end_of_acl - acl_base < acl_size) {
ret = -EINVAL;
goto out;
}
ppace[i] = (struct smb_ace *)(acl_base + acl_size);
acl_base = (char *)ppace[i];
@ -465,8 +467,10 @@ static void parse_dacl(struct mnt_idmap *idmap,
(end_of_acl - acl_base <
acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) ||
(le16_to_cpu(ppace[i]->size) <
acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth))
break;
acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth)) {
ret = -EINVAL;
goto out;
}
acl_size = le16_to_cpu(ppace[i]->size);
ppace[i]->access_req =
@ -524,8 +528,8 @@ static void parse_dacl(struct mnt_idmap *idmap,
temp_fattr.cf_uid = INVALID_UID;
ret = sid_to_id(idmap, &ppace[i]->sid, SIDOWNER, &temp_fattr);
if (ret || uid_eq(temp_fattr.cf_uid, INVALID_UID)) {
pr_err("%s: Error %d mapping Owner SID to uid\n",
__func__, ret);
pr_err_ratelimited("%s: Error %d mapping Owner SID to uid\n",
__func__, ret);
continue;
}
@ -541,7 +545,6 @@ static void parse_dacl(struct mnt_idmap *idmap,
((acl_mode & 0700) >> 6) | 0004;
}
}
kfree(ppace);
if (owner_found) {
/* The owner must be set to at least read-only. */
@ -584,10 +587,12 @@ static void parse_dacl(struct mnt_idmap *idmap,
fattr->cf_acls =
posix_acl_alloc(acl_state.users->n +
acl_state.groups->n + 4, KSMBD_DEFAULT_GFP);
if (fattr->cf_acls) {
cf_pace = fattr->cf_acls->a_entries;
posix_state_to_acl(&acl_state, cf_pace);
if (!fattr->cf_acls) {
ret = -ENOMEM;
goto out;
}
cf_pace = fattr->cf_acls->a_entries;
posix_state_to_acl(&acl_state, cf_pace);
}
}
@ -598,14 +603,20 @@ static void parse_dacl(struct mnt_idmap *idmap,
fattr->cf_dacls =
posix_acl_alloc(default_acl_state.users->n +
default_acl_state.groups->n + 4, KSMBD_DEFAULT_GFP);
if (fattr->cf_dacls) {
cf_pdace = fattr->cf_dacls->a_entries;
posix_state_to_acl(&default_acl_state, cf_pdace);
if (!fattr->cf_dacls) {
ret = -ENOMEM;
goto out;
}
cf_pdace = fattr->cf_dacls->a_entries;
posix_state_to_acl(&default_acl_state, cf_pdace);
}
}
ret = 0;
out:
kfree(ppace);
free_acl_state(&acl_state);
free_acl_state(&default_acl_state);
return ret;
}
static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
@ -966,8 +977,10 @@ int parse_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd,
if (dacloffset < sizeof(struct smb_ntsd))
return -EINVAL;
parse_dacl(idmap, dacl_ptr, end_of_acl,
owner_sid_ptr, group_sid_ptr, fattr);
rc = parse_dacl(idmap, dacl_ptr, end_of_acl,
owner_sid_ptr, group_sid_ptr, fattr);
if (rc)
return rc;
}
return 0;

View File

@ -532,14 +532,21 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
if (entry->msg_sz < sizeof(struct ksmbd_share_config_response))
return -EINVAL;
if (resp->payload_sz) {
if (resp->payload_sz < resp->veto_list_sz)
return -EINVAL;
if (strnlen(resp->share_name, sizeof(resp->share_name)) ==
sizeof(resp->share_name))
return -EINVAL;
if (check_add_overflow(sizeof(struct ksmbd_share_config_response),
resp->payload_sz, &msg_sz))
return -EINVAL;
}
if (resp->veto_list_sz > resp->payload_sz)
return -EINVAL;
if (resp->flags != KSMBD_SHARE_FLAG_INVALID &&
!(resp->flags & KSMBD_SHARE_FLAG_PIPE) &&
resp->payload_sz <= resp->veto_list_sz)
return -EINVAL;
if (check_add_overflow(sizeof(struct ksmbd_share_config_response),
resp->payload_sz, &msg_sz))
return -EINVAL;
break;
}
case KSMBD_EVENT_LOGIN_REQUEST_EXT:

View File

@ -39,6 +39,7 @@ struct tcp_transport {
static const struct ksmbd_transport_ops ksmbd_tcp_transport_ops;
static void tcp_stop_kthread(struct task_struct *kthread);
static void ksmbd_tcp_stop_listener(struct interface *iface);
static struct interface *alloc_iface(char *ifname);
static void ksmbd_tcp_disconnect(struct ksmbd_transport *t);
@ -321,13 +322,20 @@ static int ksmbd_tcp_run_kthread(struct interface *iface)
int rc;
struct task_struct *kthread;
kthread = kthread_run(ksmbd_kthread_fn, (void *)iface, "ksmbd-%s",
iface->name);
kthread = kthread_create(ksmbd_kthread_fn, (void *)iface, "ksmbd-%s",
iface->name);
if (IS_ERR(kthread)) {
rc = PTR_ERR(kthread);
return rc;
}
/*
* The listener can exit after its socket is shutdown, so keep the
* task_struct alive until the caller has stopped it.
*/
get_task_struct(kthread);
iface->ksmbd_kthread = kthread;
wake_up_process(kthread);
return 0;
}
@ -598,12 +606,7 @@ static int ksmbd_netdev_event(struct notifier_block *nb, unsigned long event,
if (iface && iface->state == IFACE_STATE_CONFIGURED) {
ksmbd_debug(CONN, "netdev-down event: netdev(%s) is going down\n",
iface->name);
kernel_sock_shutdown(iface->ksmbd_socket, SHUT_RDWR);
tcp_stop_kthread(iface->ksmbd_kthread);
iface->ksmbd_kthread = NULL;
sock_release(iface->ksmbd_socket);
iface->ksmbd_socket = NULL;
ksmbd_tcp_stop_listener(iface);
iface->state = IFACE_STATE_DOWN;
break;
}
@ -631,11 +634,25 @@ static void tcp_stop_kthread(struct task_struct *kthread)
if (!kthread)
return;
ret = kthread_stop(kthread);
ret = kthread_stop_put(kthread);
if (ret)
pr_err("failed to stop forker thread\n");
}
static void ksmbd_tcp_stop_listener(struct interface *iface)
{
if (iface->ksmbd_socket)
kernel_sock_shutdown(iface->ksmbd_socket, SHUT_RDWR);
tcp_stop_kthread(iface->ksmbd_kthread);
iface->ksmbd_kthread = NULL;
if (iface->ksmbd_socket) {
sock_release(iface->ksmbd_socket);
iface->ksmbd_socket = NULL;
}
}
void ksmbd_tcp_destroy(void)
{
struct interface *iface, *tmp;
@ -643,6 +660,7 @@ void ksmbd_tcp_destroy(void)
unregister_netdevice_notifier(&ksmbd_netdev_notifier);
list_for_each_entry_safe(iface, tmp, &iface_list, entry) {
ksmbd_tcp_stop_listener(iface);
list_del(&iface->entry);
kfree(iface->name);
kfree(iface);

View File

@ -846,12 +846,25 @@ static void set_close_state_blocked_works(struct ksmbd_file *fp)
spin_lock(&fp->f_lock);
list_for_each_entry(cancel_work, &fp->blocked_works,
fp_entry) {
cancel_work->state = KSMBD_WORK_CLOSED;
cancel_work->cancel_fn(cancel_work->cancel_argv);
if (xchg(&cancel_work->state, KSMBD_WORK_CLOSED) ==
KSMBD_WORK_ACTIVE)
cancel_work->cancel_fn(cancel_work->cancel_argv);
}
spin_unlock(&fp->f_lock);
}
void ksmbd_wake_session_blocked_works(struct ksmbd_session *sess)
{
struct ksmbd_file_table *ft = &sess->file_table;
struct ksmbd_file *fp;
unsigned int id;
read_lock(&ft->lock);
idr_for_each_entry(ft->idr, fp, id)
set_close_state_blocked_works(fp);
read_unlock(&ft->lock);
}
int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
{
struct ksmbd_file *fp;

View File

@ -226,6 +226,7 @@ void ksmbd_stop_durable_scavenger(void);
bool ksmbd_durable_scavenger_active(void);
void ksmbd_close_tree_conn_fds(struct ksmbd_work *work);
void ksmbd_close_session_fds(struct ksmbd_work *work);
void ksmbd_wake_session_blocked_works(struct ksmbd_session *sess);
int ksmbd_close_inode_fds(struct ksmbd_work *work, struct inode *inode);
int ksmbd_init_global_file_table(void);
void ksmbd_free_global_file_table(void);