From 5614c8c487f6af627614dd2efca038e4afe0c6d7 Mon Sep 17 00:00:00 2001 From: Marios Makassikis Date: Thu, 22 Feb 2024 10:58:19 +0100 Subject: ksmbd: replace generic_fillattr with vfs_getattr generic_fillattr should not be used outside of ->getattr implementations. Use vfs_getattr instead, and adapt functions to return an error code to the caller. Cc: stable@vger.kernel.org Signed-off-by: Marios Makassikis Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 170 +++++++++++++++++++++++++++++---------------- fs/smb/server/smb_common.c | 11 +-- fs/smb/server/vfs.c | 12 +++- 3 files changed, 127 insertions(+), 66 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 0c97d3c860726a..f6cc5d2730ffb7 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -3828,11 +3828,16 @@ static int process_query_dir_entries(struct smb2_query_dir_private *priv) } ksmbd_kstat.kstat = &kstat; - if (priv->info_level != FILE_NAMES_INFORMATION) - ksmbd_vfs_fill_dentry_attrs(priv->work, - idmap, - dent, - &ksmbd_kstat); + if (priv->info_level != FILE_NAMES_INFORMATION) { + rc = ksmbd_vfs_fill_dentry_attrs(priv->work, + idmap, + dent, + &ksmbd_kstat); + if (rc) { + dput(dent); + continue; + } + } rc = smb2_populate_readdir_entry(priv->work->conn, priv->info_level, @@ -4480,6 +4485,7 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp, struct smb2_file_basic_info *basic_info; struct kstat stat; u64 time; + int ret; if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) { pr_err("no right to read the attributes : 0x%x\n", @@ -4487,9 +4493,12 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp, return -EACCES; } + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, + AT_STATX_SYNC_AS_STAT); + if (ret) + return ret; + basic_info = (struct smb2_file_basic_info *)rsp->Buffer; - generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, - file_inode(fp->filp), &stat); basic_info->CreationTime = cpu_to_le64(fp->create_time); time = ksmbd_UnixTimeToNT(stat.atime); basic_info->LastAccessTime = cpu_to_le64(time); @@ -4504,27 +4513,31 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp, return 0; } -static void get_file_standard_info(struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, void *rsp_org) +static int get_file_standard_info(struct smb2_query_info_rsp *rsp, + struct ksmbd_file *fp, void *rsp_org) { struct smb2_file_standard_info *sinfo; unsigned int delete_pending; - struct inode *inode; struct kstat stat; + int ret; - inode = file_inode(fp->filp); - generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat); + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, + AT_STATX_SYNC_AS_STAT); + if (ret) + return ret; sinfo = (struct smb2_file_standard_info *)rsp->Buffer; delete_pending = ksmbd_inode_pending_delete(fp); - sinfo->AllocationSize = cpu_to_le64(inode->i_blocks << 9); + sinfo->AllocationSize = cpu_to_le64(stat.blocks << 9); sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); sinfo->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending); sinfo->DeletePending = delete_pending; sinfo->Directory = S_ISDIR(stat.mode) ? 1 : 0; rsp->OutputBufferLength = cpu_to_le32(sizeof(struct smb2_file_standard_info)); + + return 0; } static void get_file_alignment_info(struct smb2_query_info_rsp *rsp, @@ -4546,11 +4559,11 @@ static int get_file_all_info(struct ksmbd_work *work, struct ksmbd_conn *conn = work->conn; struct smb2_file_all_info *file_info; unsigned int delete_pending; - struct inode *inode; struct kstat stat; int conv_len; char *filename; u64 time; + int ret; if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) { ksmbd_debug(SMB, "no right to read the attributes : 0x%x\n", @@ -4562,8 +4575,10 @@ static int get_file_all_info(struct ksmbd_work *work, if (IS_ERR(filename)) return PTR_ERR(filename); - inode = file_inode(fp->filp); - generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat); + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, + AT_STATX_SYNC_AS_STAT); + if (ret) + return ret; ksmbd_debug(SMB, "filename = %s\n", filename); delete_pending = ksmbd_inode_pending_delete(fp); @@ -4579,7 +4594,7 @@ static int get_file_all_info(struct ksmbd_work *work, file_info->Attributes = fp->f_ci->m_fattr; file_info->Pad1 = 0; file_info->AllocationSize = - cpu_to_le64(inode->i_blocks << 9); + cpu_to_le64(stat.blocks << 9); file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); file_info->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending); @@ -4623,10 +4638,10 @@ static void get_file_alternate_info(struct ksmbd_work *work, cpu_to_le32(sizeof(struct smb2_file_alt_name_info) + conv_len); } -static void get_file_stream_info(struct ksmbd_work *work, - struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, - void *rsp_org) +static int get_file_stream_info(struct ksmbd_work *work, + struct smb2_query_info_rsp *rsp, + struct ksmbd_file *fp, + void *rsp_org) { struct ksmbd_conn *conn = work->conn; struct smb2_file_stream_info *file_info; @@ -4637,9 +4652,13 @@ static void get_file_stream_info(struct ksmbd_work *work, int nbytes = 0, streamlen, stream_name_len, next, idx = 0; int buf_free_len; struct smb2_query_info_req *req = ksmbd_req_buf_next(work); + int ret; + + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, + AT_STATX_SYNC_AS_STAT); + if (ret) + return ret; - generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, - file_inode(fp->filp), &stat); file_info = (struct smb2_file_stream_info *)rsp->Buffer; buf_free_len = @@ -4720,29 +4739,37 @@ out: kvfree(xattr_list); rsp->OutputBufferLength = cpu_to_le32(nbytes); + + return 0; } -static void get_file_internal_info(struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, void *rsp_org) +static int get_file_internal_info(struct smb2_query_info_rsp *rsp, + struct ksmbd_file *fp, void *rsp_org) { struct smb2_file_internal_info *file_info; struct kstat stat; + int ret; + + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, + AT_STATX_SYNC_AS_STAT); + if (ret) + return ret; - generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, - file_inode(fp->filp), &stat); file_info = (struct smb2_file_internal_info *)rsp->Buffer; file_info->IndexNumber = cpu_to_le64(stat.ino); rsp->OutputBufferLength = cpu_to_le32(sizeof(struct smb2_file_internal_info)); + + return 0; } static int get_file_network_open_info(struct smb2_query_info_rsp *rsp, struct ksmbd_file *fp, void *rsp_org) { struct smb2_file_ntwrk_info *file_info; - struct inode *inode; struct kstat stat; u64 time; + int ret; if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) { pr_err("no right to read the attributes : 0x%x\n", @@ -4750,10 +4777,12 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp, return -EACCES; } - file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer; + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, + AT_STATX_SYNC_AS_STAT); + if (ret) + return ret; - inode = file_inode(fp->filp); - generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat); + file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer; file_info->CreationTime = cpu_to_le64(fp->create_time); time = ksmbd_UnixTimeToNT(stat.atime); @@ -4763,8 +4792,7 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp, time = ksmbd_UnixTimeToNT(stat.ctime); file_info->ChangeTime = cpu_to_le64(time); file_info->Attributes = fp->f_ci->m_fattr; - file_info->AllocationSize = - cpu_to_le64(inode->i_blocks << 9); + file_info->AllocationSize = cpu_to_le64(stat.blocks << 9); file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); file_info->Reserved = cpu_to_le32(0); rsp->OutputBufferLength = @@ -4804,14 +4832,17 @@ static void get_file_mode_info(struct smb2_query_info_rsp *rsp, cpu_to_le32(sizeof(struct smb2_file_mode_info)); } -static void get_file_compression_info(struct smb2_query_info_rsp *rsp, - struct ksmbd_file *fp, void *rsp_org) +static int get_file_compression_info(struct smb2_query_info_rsp *rsp, + struct ksmbd_file *fp, void *rsp_org) { struct smb2_file_comp_info *file_info; struct kstat stat; + int ret; - generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, - file_inode(fp->filp), &stat); + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, + AT_STATX_SYNC_AS_STAT); + if (ret) + return ret; file_info = (struct smb2_file_comp_info *)rsp->Buffer; file_info->CompressedFileSize = cpu_to_le64(stat.blocks << 9); @@ -4823,6 +4854,8 @@ static void get_file_compression_info(struct smb2_query_info_rsp *rsp, rsp->OutputBufferLength = cpu_to_le32(sizeof(struct smb2_file_comp_info)); + + return 0; } static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp, @@ -4844,7 +4877,7 @@ static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp, return 0; } -static void find_file_posix_info(struct smb2_query_info_rsp *rsp, +static int find_file_posix_info(struct smb2_query_info_rsp *rsp, struct ksmbd_file *fp, void *rsp_org) { struct smb311_posix_qinfo *file_info; @@ -4852,24 +4885,31 @@ static void find_file_posix_info(struct smb2_query_info_rsp *rsp, struct mnt_idmap *idmap = file_mnt_idmap(fp->filp); vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode); vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode); + struct kstat stat; u64 time; int out_buf_len = sizeof(struct smb311_posix_qinfo) + 32; + int ret; + + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, + AT_STATX_SYNC_AS_STAT); + if (ret) + return ret; file_info = (struct smb311_posix_qinfo *)rsp->Buffer; file_info->CreationTime = cpu_to_le64(fp->create_time); - time = ksmbd_UnixTimeToNT(inode_get_atime(inode)); + time = ksmbd_UnixTimeToNT(stat.atime); file_info->LastAccessTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(inode_get_mtime(inode)); + time = ksmbd_UnixTimeToNT(stat.mtime); file_info->LastWriteTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(inode_get_ctime(inode)); + time = ksmbd_UnixTimeToNT(stat.ctime); file_info->ChangeTime = cpu_to_le64(time); file_info->DosAttributes = fp->f_ci->m_fattr; - file_info->Inode = cpu_to_le64(inode->i_ino); - file_info->EndOfFile = cpu_to_le64(inode->i_size); - file_info->AllocationSize = cpu_to_le64(inode->i_blocks << 9); - file_info->HardLinks = cpu_to_le32(inode->i_nlink); - file_info->Mode = cpu_to_le32(inode->i_mode & 0777); - file_info->DeviceId = cpu_to_le32(inode->i_rdev); + file_info->Inode = cpu_to_le64(stat.ino); + file_info->EndOfFile = cpu_to_le64(stat.size); + file_info->AllocationSize = cpu_to_le64(stat.blocks << 9); + file_info->HardLinks = cpu_to_le32(stat.nlink); + file_info->Mode = cpu_to_le32(stat.mode & 0777); + file_info->DeviceId = cpu_to_le32(stat.rdev); /* * Sids(32) contain two sids(Domain sid(16), UNIX group sid(16)). @@ -4882,6 +4922,8 @@ static void find_file_posix_info(struct smb2_query_info_rsp *rsp, SIDUNIX_GROUP, (struct smb_sid *)&file_info->Sids[16]); rsp->OutputBufferLength = cpu_to_le32(out_buf_len); + + return 0; } static int smb2_get_info_file(struct ksmbd_work *work, @@ -4930,7 +4972,7 @@ static int smb2_get_info_file(struct ksmbd_work *work, break; case FILE_STANDARD_INFORMATION: - get_file_standard_info(rsp, fp, work->response_buf); + rc = get_file_standard_info(rsp, fp, work->response_buf); break; case FILE_ALIGNMENT_INFORMATION: @@ -4946,11 +4988,11 @@ static int smb2_get_info_file(struct ksmbd_work *work, break; case FILE_STREAM_INFORMATION: - get_file_stream_info(work, rsp, fp, work->response_buf); + rc = get_file_stream_info(work, rsp, fp, work->response_buf); break; case FILE_INTERNAL_INFORMATION: - get_file_internal_info(rsp, fp, work->response_buf); + rc = get_file_internal_info(rsp, fp, work->response_buf); break; case FILE_NETWORK_OPEN_INFORMATION: @@ -4974,7 +5016,7 @@ static int smb2_get_info_file(struct ksmbd_work *work, break; case FILE_COMPRESSION_INFORMATION: - get_file_compression_info(rsp, fp, work->response_buf); + rc = get_file_compression_info(rsp, fp, work->response_buf); break; case FILE_ATTRIBUTE_TAG_INFORMATION: @@ -4985,7 +5027,7 @@ static int smb2_get_info_file(struct ksmbd_work *work, pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n"); rc = -EOPNOTSUPP; } else { - find_file_posix_info(rsp, fp, work->response_buf); + rc = find_file_posix_info(rsp, fp, work->response_buf); } break; default: @@ -5398,7 +5440,6 @@ int smb2_close(struct ksmbd_work *work) struct smb2_close_rsp *rsp; struct ksmbd_conn *conn = work->conn; struct ksmbd_file *fp; - struct inode *inode; u64 time; int err = 0; @@ -5453,24 +5494,33 @@ int smb2_close(struct ksmbd_work *work) rsp->Reserved = 0; if (req->Flags == SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB) { + struct kstat stat; + int ret; + fp = ksmbd_lookup_fd_fast(work, volatile_id); if (!fp) { err = -ENOENT; goto out; } - inode = file_inode(fp->filp); + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, + AT_STATX_SYNC_AS_STAT); + if (ret) { + ksmbd_fd_put(work, fp); + goto out; + } + rsp->Flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; - rsp->AllocationSize = S_ISDIR(inode->i_mode) ? 0 : - cpu_to_le64(inode->i_blocks << 9); - rsp->EndOfFile = cpu_to_le64(inode->i_size); + rsp->AllocationSize = S_ISDIR(stat.mode) ? 0 : + cpu_to_le64(stat.blocks << 9); + rsp->EndOfFile = cpu_to_le64(stat.size); rsp->Attributes = fp->f_ci->m_fattr; rsp->CreationTime = cpu_to_le64(fp->create_time); - time = ksmbd_UnixTimeToNT(inode_get_atime(inode)); + time = ksmbd_UnixTimeToNT(stat.atime); rsp->LastAccessTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(inode_get_mtime(inode)); + time = ksmbd_UnixTimeToNT(stat.mtime); rsp->LastWriteTime = cpu_to_le64(time); - time = ksmbd_UnixTimeToNT(inode_get_ctime(inode)); + time = ksmbd_UnixTimeToNT(stat.ctime); rsp->ChangeTime = cpu_to_le64(time); ksmbd_fd_put(work, fp); } else { diff --git a/fs/smb/server/smb_common.c b/fs/smb/server/smb_common.c index 7c98bf699772f2..fcaf373cc00804 100644 --- a/fs/smb/server/smb_common.c +++ b/fs/smb/server/smb_common.c @@ -457,10 +457,13 @@ int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level, } ksmbd_kstat.kstat = &kstat; - ksmbd_vfs_fill_dentry_attrs(work, - idmap, - dentry, - &ksmbd_kstat); + rc = ksmbd_vfs_fill_dentry_attrs(work, + idmap, + dentry, + &ksmbd_kstat); + if (rc) + break; + rc = fn(conn, info_level, d_info, &ksmbd_kstat); if (rc) break; diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c index a6961bfe3e1394..2e992fadeaa7df 100644 --- a/fs/smb/server/vfs.c +++ b/fs/smb/server/vfs.c @@ -1682,11 +1682,19 @@ int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work, struct dentry *dentry, struct ksmbd_kstat *ksmbd_kstat) { + struct ksmbd_share_config *share_conf = work->tcon->share_conf; u64 time; int rc; + struct path path = { + .mnt = share_conf->vfs_path.mnt, + .dentry = dentry, + }; - generic_fillattr(idmap, STATX_BASIC_STATS, d_inode(dentry), - ksmbd_kstat->kstat); + rc = vfs_getattr(&path, ksmbd_kstat->kstat, + STATX_BASIC_STATS | STATX_BTIME, + AT_STATX_SYNC_AS_STAT); + if (rc) + return rc; time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->ctime); ksmbd_kstat->create_time = time; -- cgit 1.2.3-korg From 34cd86b6632718b7df3999d96f51e63de41c5e4f Mon Sep 17 00:00:00 2001 From: Marios Makassikis Date: Thu, 22 Feb 2024 10:58:21 +0100 Subject: ksmbd: retrieve number of blocks using vfs_getattr in set_file_allocation_info Use vfs_getattr() to retrieve stat information, rather than make assumptions about how a filesystem fills inode structs. Cc: stable@vger.kernel.org Signed-off-by: Marios Makassikis Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index f6cc5d2730ffb7..199c31c275e5be 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -5809,15 +5809,21 @@ static int set_file_allocation_info(struct ksmbd_work *work, loff_t alloc_blks; struct inode *inode; + struct kstat stat; int rc; if (!(fp->daccess & FILE_WRITE_DATA_LE)) return -EACCES; + rc = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, + AT_STATX_SYNC_AS_STAT); + if (rc) + return rc; + alloc_blks = (le64_to_cpu(file_alloc_info->AllocationSize) + 511) >> 9; inode = file_inode(fp->filp); - if (alloc_blks > inode->i_blocks) { + if (alloc_blks > stat.blocks) { smb_break_all_levII_oplock(work, fp, 1); rc = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0, alloc_blks * 512); @@ -5825,7 +5831,7 @@ static int set_file_allocation_info(struct ksmbd_work *work, pr_err("vfs_fallocate is failed : %d\n", rc); return rc; } - } else if (alloc_blks < inode->i_blocks) { + } else if (alloc_blks < stat.blocks) { loff_t size; /* -- cgit 1.2.3-korg From fa9415d4024fd0c58d24a4ad4f1826fb8bfcc4aa Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 10 Mar 2024 19:30:51 +0900 Subject: ksmbd: mark SMB2_SESSION_EXPIRED to session when destroying previous session Currently ksmbd exit connection as well destroying previous session. When testing durable handle feaure, I found that destroy_previous_session() should destroy only session, i.e. the connection should be still alive. This patch mark SMB2_SESSION_EXPIRED on the previous session to be destroyed later and not used anymore. Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/mgmt/user_session.c | 27 ++++++++++++++++++++++++++- fs/smb/server/mgmt/user_session.h | 3 +++ fs/smb/server/smb2pdu.c | 24 ------------------------ 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c index 15f68ee0508946..83074672fe8122 100644 --- a/fs/smb/server/mgmt/user_session.c +++ b/fs/smb/server/mgmt/user_session.c @@ -156,7 +156,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess) kfree(sess); } -static struct ksmbd_session *__session_lookup(unsigned long long id) +struct ksmbd_session *__session_lookup(unsigned long long id) { struct ksmbd_session *sess; @@ -305,6 +305,31 @@ struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn, return sess; } +void destroy_previous_session(struct ksmbd_conn *conn, + struct ksmbd_user *user, u64 id) +{ + struct ksmbd_session *prev_sess; + struct ksmbd_user *prev_user; + + down_write(&sessions_table_lock); + down_write(&conn->session_lock); + prev_sess = __session_lookup(id); + if (!prev_sess || prev_sess->state == SMB2_SESSION_EXPIRED) + goto out; + + prev_user = prev_sess->user; + if (!prev_user || + strcmp(user->name, prev_user->name) || + user->passkey_sz != prev_user->passkey_sz || + memcmp(user->passkey, prev_user->passkey, user->passkey_sz)) + goto out; + + prev_sess->state = SMB2_SESSION_EXPIRED; +out: + up_write(&conn->session_lock); + up_write(&sessions_table_lock); +} + static bool ksmbd_preauth_session_id_match(struct preauth_session *sess, unsigned long long id) { diff --git a/fs/smb/server/mgmt/user_session.h b/fs/smb/server/mgmt/user_session.h index 63cb08fffde84c..dc9fded2cd4379 100644 --- a/fs/smb/server/mgmt/user_session.h +++ b/fs/smb/server/mgmt/user_session.h @@ -88,8 +88,11 @@ struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, int ksmbd_session_register(struct ksmbd_conn *conn, struct ksmbd_session *sess); void ksmbd_sessions_deregister(struct ksmbd_conn *conn); +struct ksmbd_session *__session_lookup(unsigned long long id); struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, unsigned long long id); +void destroy_previous_session(struct ksmbd_conn *conn, + struct ksmbd_user *user, u64 id); struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn, u64 sess_id); struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn, diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 199c31c275e5be..201d78310bde19 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -607,30 +607,6 @@ int smb2_check_user_session(struct ksmbd_work *work) return -ENOENT; } -static void destroy_previous_session(struct ksmbd_conn *conn, - struct ksmbd_user *user, u64 id) -{ - struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id); - struct ksmbd_user *prev_user; - struct channel *chann; - long index; - - if (!prev_sess) - return; - - prev_user = prev_sess->user; - - if (!prev_user || - strcmp(user->name, prev_user->name) || - user->passkey_sz != prev_user->passkey_sz || - memcmp(user->passkey, prev_user->passkey, user->passkey_sz)) - return; - - prev_sess->state = SMB2_SESSION_EXPIRED; - xa_for_each(&prev_sess->ksmbd_chann_list, index, chann) - ksmbd_conn_set_exiting(chann->conn); -} - /** * smb2_get_name() - get filename string from on the wire smb format * @src: source buffer -- cgit 1.2.3-korg From c8efcc786146a951091588e5fa7e3c754850cb3c Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 12 Mar 2024 14:05:57 +0900 Subject: ksmbd: add support for durable handles v1/v2 Durable file handles allow reopening a file preserved on a short network outage and transparent client reconnection within a timeout. i.e. Durable handles aren't necessarily cleaned up when the opening process terminates. This patch add support for durable handle version 1 and 2. To prove durable handles work on ksmbd, I have tested this patch with the following smbtorture tests: smb2.durable-open.open-oplock smb2.durable-open.open-lease smb2.durable-open.reopen1 smb2.durable-open.reopen1a smb2.durable-open.reopen1a-lease smb2.durable-open.reopen2 smb2.durable-open.reopen2a smb2.durable-open.reopen2-lease smb2.durable-open.reopen2-lease-v2 smb2.durable-open.reopen3 smb2.durable-open.reopen4 smb2.durable-open.delete_on_close2 smb2.durable-open.file-position smb2.durable-open.lease smb2.durable-open.alloc-size smb2.durable-open.read-only smb2.durable-v2-open.create-blob smb2.durable-v2-open.open-oplock smb2.durable-v2-open.open-lease smb2.durable-v2-open.reopen1 smb2.durable-v2-open.reopen1a smb2.durable-v2-open.reopen1a-lease smb2.durable-v2-open.reopen2 smb2.durable-v2-open.reopen2b Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/ksmbd_netlink.h | 1 + fs/smb/server/mgmt/user_session.c | 1 + fs/smb/server/oplock.c | 94 ++++++++++++-- fs/smb/server/oplock.h | 7 +- fs/smb/server/smb2ops.c | 6 + fs/smb/server/smb2pdu.c | 257 +++++++++++++++++++++++++++++++++++++- fs/smb/server/smb2pdu.h | 15 +++ fs/smb/server/vfs_cache.c | 137 +++++++++++++++++++- fs/smb/server/vfs_cache.h | 9 ++ 9 files changed, 506 insertions(+), 21 deletions(-) diff --git a/fs/smb/server/ksmbd_netlink.h b/fs/smb/server/ksmbd_netlink.h index 0ebf91ffa2361c..8ca8a45c4c621c 100644 --- a/fs/smb/server/ksmbd_netlink.h +++ b/fs/smb/server/ksmbd_netlink.h @@ -75,6 +75,7 @@ struct ksmbd_heartbeat { #define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION BIT(1) #define KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL BIT(2) #define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF BIT(3) +#define KSMBD_GLOBAL_FLAG_DURABLE_HANDLE BIT(4) /* * IPC request for ksmbd server startup diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c index 83074672fe8122..aec0a7a124052a 100644 --- a/fs/smb/server/mgmt/user_session.c +++ b/fs/smb/server/mgmt/user_session.c @@ -324,6 +324,7 @@ void destroy_previous_session(struct ksmbd_conn *conn, memcmp(user->passkey, prev_user->passkey, user->passkey_sz)) goto out; + ksmbd_destroy_file_table(&prev_sess->file_table); prev_sess->state = SMB2_SESSION_EXPIRED; out: up_write(&conn->session_lock); diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c index 53dfaac425c68d..9af5fd68bd85b4 100644 --- a/fs/smb/server/oplock.c +++ b/fs/smb/server/oplock.c @@ -159,7 +159,8 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci) opinfo = list_first_or_null_rcu(&ci->m_op_list, struct oplock_info, op_entry); if (opinfo) { - if (!atomic_inc_not_zero(&opinfo->refcount)) + if (opinfo->conn == NULL || + !atomic_inc_not_zero(&opinfo->refcount)) opinfo = NULL; else { atomic_inc(&opinfo->conn->r_count); @@ -527,7 +528,7 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci, */ read_lock(&ci->m_lock); list_for_each_entry(opinfo, &ci->m_op_list, op_entry) { - if (!opinfo->is_lease) + if (!opinfo->is_lease || !opinfo->conn) continue; read_unlock(&ci->m_lock); lease = opinfo->o_lease; @@ -641,7 +642,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk) struct smb2_hdr *rsp_hdr; struct ksmbd_file *fp; - fp = ksmbd_lookup_durable_fd(br_info->fid); + fp = ksmbd_lookup_global_fd(br_info->fid); if (!fp) goto out; @@ -1106,7 +1107,7 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp, read_lock(&p_ci->m_lock); list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) { - if (!opinfo->is_lease) + if (opinfo->conn == NULL || !opinfo->is_lease) continue; if (opinfo->o_lease->state != SMB2_OPLOCK_LEVEL_NONE && @@ -1151,7 +1152,7 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp) read_lock(&p_ci->m_lock); list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) { - if (!opinfo->is_lease) + if (opinfo->conn == NULL || !opinfo->is_lease) continue; if (opinfo->o_lease->state != SMB2_OPLOCK_LEVEL_NONE) { @@ -1361,6 +1362,9 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp, rcu_read_lock(); list_for_each_entry_rcu(brk_op, &ci->m_op_list, op_entry) { + if (brk_op->conn == NULL) + continue; + if (!atomic_inc_not_zero(&brk_op->refcount)) continue; @@ -1496,11 +1500,10 @@ void create_lease_buf(u8 *rbuf, struct lease *lease) /** * parse_lease_state() - parse lease context containted in file open request * @open_req: buffer containing smb2 file open(create) request - * @is_dir: whether leasing file is directory * * Return: oplock state, -ENOENT if create lease context not found */ -struct lease_ctx_info *parse_lease_state(void *open_req, bool is_dir) +struct lease_ctx_info *parse_lease_state(void *open_req) { struct create_context *cc; struct smb2_create_req *req = (struct smb2_create_req *)open_req; @@ -1518,12 +1521,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req, bool is_dir) struct create_lease_v2 *lc = (struct create_lease_v2 *)cc; memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); - if (is_dir) { - lreq->req_state = lc->lcontext.LeaseState & - ~SMB2_LEASE_WRITE_CACHING_LE; - lreq->is_dir = true; - } else - lreq->req_state = lc->lcontext.LeaseState; + lreq->req_state = lc->lcontext.LeaseState; lreq->flags = lc->lcontext.LeaseFlags; lreq->epoch = lc->lcontext.Epoch; lreq->duration = lc->lcontext.LeaseDuration; @@ -1646,6 +1644,8 @@ void create_durable_v2_rsp_buf(char *cc, struct ksmbd_file *fp) buf->Name[3] = 'Q'; buf->Timeout = cpu_to_le32(fp->durable_timeout); + if (fp->is_persistent) + buf->Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT); } /** @@ -1813,3 +1813,71 @@ out: read_unlock(&lease_list_lock); return ret_op; } + +int smb2_check_durable_oplock(struct ksmbd_conn *conn, + struct ksmbd_share_config *share, + struct ksmbd_file *fp, + struct lease_ctx_info *lctx, + char *name) +{ + struct oplock_info *opinfo = opinfo_get(fp); + int ret = 0; + + if (!opinfo) + return 0; + + if (opinfo->is_lease == false) { + if (lctx) { + pr_err("create context include lease\n"); + ret = -EBADF; + goto out; + } + + if (opinfo->level != SMB2_OPLOCK_LEVEL_BATCH) { + pr_err("oplock level is not equal to SMB2_OPLOCK_LEVEL_BATCH\n"); + ret = -EBADF; + } + + goto out; + } + + if (memcmp(conn->ClientGUID, fp->client_guid, + SMB2_CLIENT_GUID_SIZE)) { + ksmbd_debug(SMB, "Client guid of fp is not equal to the one of connction\n"); + ret = -EBADF; + goto out; + } + + if (!lctx) { + ksmbd_debug(SMB, "create context does not include lease\n"); + ret = -EBADF; + goto out; + } + + if (memcmp(opinfo->o_lease->lease_key, lctx->lease_key, + SMB2_LEASE_KEY_SIZE)) { + ksmbd_debug(SMB, + "lease key of fp does not match lease key in create context\n"); + ret = -EBADF; + goto out; + } + + if (!(opinfo->o_lease->state & SMB2_LEASE_HANDLE_CACHING_LE)) { + ksmbd_debug(SMB, "lease state does not contain SMB2_LEASE_HANDLE_CACHING\n"); + ret = -EBADF; + goto out; + } + + if (opinfo->o_lease->version != lctx->version) { + ksmbd_debug(SMB, + "lease version of fp does not match the one in create context\n"); + ret = -EBADF; + goto out; + } + + if (!ksmbd_inode_pending_delete(fp)) + ret = ksmbd_validate_name_reconnect(share, fp, name); +out: + opinfo_put(opinfo); + return ret; +} diff --git a/fs/smb/server/oplock.h b/fs/smb/server/oplock.h index 5b93ea9196c013..e9da63f25b2061 100644 --- a/fs/smb/server/oplock.h +++ b/fs/smb/server/oplock.h @@ -111,7 +111,7 @@ void opinfo_put(struct oplock_info *opinfo); /* Lease related functions */ void create_lease_buf(u8 *rbuf, struct lease *lease); -struct lease_ctx_info *parse_lease_state(void *open_req, bool is_dir); +struct lease_ctx_info *parse_lease_state(void *open_req); __u8 smb2_map_lease_to_oplock(__le32 lease_state); int lease_read_to_write(struct oplock_info *opinfo); @@ -130,4 +130,9 @@ void destroy_lease_table(struct ksmbd_conn *conn); void smb_send_parent_lease_break_noti(struct ksmbd_file *fp, struct lease_ctx_info *lctx); void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp); +int smb2_check_durable_oplock(struct ksmbd_conn *conn, + struct ksmbd_share_config *share, + struct ksmbd_file *fp, + struct lease_ctx_info *lctx, + char *name); #endif /* __KSMBD_OPLOCK_H */ diff --git a/fs/smb/server/smb2ops.c b/fs/smb/server/smb2ops.c index 27a9dce3e03abe..a45f7dca482e01 100644 --- a/fs/smb/server/smb2ops.c +++ b/fs/smb/server/smb2ops.c @@ -256,6 +256,9 @@ void init_smb3_02_server(struct ksmbd_conn *conn) if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE) + conn->vals->capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES; } /** @@ -283,6 +286,9 @@ int init_smb3_11_server(struct ksmbd_conn *conn) if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; + if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE) + conn->vals->capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES; + INIT_LIST_HEAD(&conn->preauth_sess_table); return 0; } diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 201d78310bde19..1ef3859fed1b30 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2618,6 +2618,165 @@ static void ksmbd_acls_fattr(struct smb_fattr *fattr, } } +enum { + DURABLE_RECONN_V2 = 1, + DURABLE_RECONN, + DURABLE_REQ_V2, + DURABLE_REQ, +}; + +struct durable_info { + struct ksmbd_file *fp; + unsigned short int type; + bool persistent; + bool reconnected; + unsigned int timeout; + char *CreateGuid; +}; + +static int parse_durable_handle_context(struct ksmbd_work *work, + struct smb2_create_req *req, + struct lease_ctx_info *lc, + struct durable_info *dh_info) +{ + struct ksmbd_conn *conn = work->conn; + struct create_context *context; + int dh_idx, err = 0; + u64 persistent_id = 0; + int req_op_level; + static const char * const durable_arr[] = {"DH2C", "DHnC", "DH2Q", "DHnQ"}; + + req_op_level = req->RequestedOplockLevel; + for (dh_idx = DURABLE_RECONN_V2; dh_idx <= ARRAY_SIZE(durable_arr); + dh_idx++) { + context = smb2_find_context_vals(req, durable_arr[dh_idx - 1], 4); + if (IS_ERR(context)) { + err = PTR_ERR(context); + goto out; + } + if (!context) + continue; + + switch (dh_idx) { + case DURABLE_RECONN_V2: + { + struct create_durable_reconn_v2_req *recon_v2; + + if (dh_info->type == DURABLE_RECONN || + dh_info->type == DURABLE_REQ_V2) { + err = -EINVAL; + goto out; + } + + recon_v2 = (struct create_durable_reconn_v2_req *)context; + persistent_id = recon_v2->Fid.PersistentFileId; + dh_info->fp = ksmbd_lookup_durable_fd(persistent_id); + if (!dh_info->fp) { + ksmbd_debug(SMB, "Failed to get durable handle state\n"); + err = -EBADF; + goto out; + } + + if (memcmp(dh_info->fp->create_guid, recon_v2->CreateGuid, + SMB2_CREATE_GUID_SIZE)) { + err = -EBADF; + ksmbd_put_durable_fd(dh_info->fp); + goto out; + } + + dh_info->type = dh_idx; + dh_info->reconnected = true; + ksmbd_debug(SMB, + "reconnect v2 Persistent-id from reconnect = %llu\n", + persistent_id); + break; + } + case DURABLE_RECONN: + { + struct create_durable_reconn_req *recon; + + if (dh_info->type == DURABLE_RECONN_V2 || + dh_info->type == DURABLE_REQ_V2) { + err = -EINVAL; + goto out; + } + + recon = (struct create_durable_reconn_req *)context; + persistent_id = recon->Data.Fid.PersistentFileId; + dh_info->fp = ksmbd_lookup_durable_fd(persistent_id); + if (!dh_info->fp) { + ksmbd_debug(SMB, "Failed to get durable handle state\n"); + err = -EBADF; + goto out; + } + + dh_info->type = dh_idx; + dh_info->reconnected = true; + ksmbd_debug(SMB, "reconnect Persistent-id from reconnect = %llu\n", + persistent_id); + break; + } + case DURABLE_REQ_V2: + { + struct create_durable_req_v2 *durable_v2_blob; + + if (dh_info->type == DURABLE_RECONN || + dh_info->type == DURABLE_RECONN_V2) { + err = -EINVAL; + goto out; + } + + durable_v2_blob = + (struct create_durable_req_v2 *)context; + ksmbd_debug(SMB, "Request for durable v2 open\n"); + dh_info->fp = ksmbd_lookup_fd_cguid(durable_v2_blob->CreateGuid); + if (dh_info->fp) { + if (!memcmp(conn->ClientGUID, dh_info->fp->client_guid, + SMB2_CLIENT_GUID_SIZE)) { + if (!(req->hdr.Flags & SMB2_FLAGS_REPLAY_OPERATION)) { + err = -ENOEXEC; + goto out; + } + + dh_info->fp->conn = conn; + dh_info->reconnected = true; + goto out; + } + } + + if (((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) || + req_op_level == SMB2_OPLOCK_LEVEL_BATCH)) { + dh_info->CreateGuid = + durable_v2_blob->CreateGuid; + dh_info->persistent = + le32_to_cpu(durable_v2_blob->Flags); + dh_info->timeout = + le32_to_cpu(durable_v2_blob->Timeout); + dh_info->type = dh_idx; + } + break; + } + case DURABLE_REQ: + if (dh_info->type == DURABLE_RECONN) + goto out; + if (dh_info->type == DURABLE_RECONN_V2 || + dh_info->type == DURABLE_REQ_V2) { + err = -EINVAL; + goto out; + } + + if (((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) || + req_op_level == SMB2_OPLOCK_LEVEL_BATCH)) { + ksmbd_debug(SMB, "Request for durable open\n"); + dh_info->type = dh_idx; + } + } + } + +out: + return err; +} + /** * smb2_open() - handler for smb file open request * @work: smb work containing request buffer @@ -2641,6 +2800,7 @@ int smb2_open(struct ksmbd_work *work) struct lease_ctx_info *lc = NULL; struct create_ea_buf_req *ea_buf = NULL; struct oplock_info *opinfo; + struct durable_info dh_info = {0}; __le32 *next_ptr = NULL; int req_op_level = 0, open_flags = 0, may_flags = 0, file_info = 0; int rc = 0; @@ -2721,6 +2881,49 @@ int smb2_open(struct ksmbd_work *work) } } + req_op_level = req->RequestedOplockLevel; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE && + req->CreateContextsOffset) { + lc = parse_lease_state(req); + rc = parse_durable_handle_context(work, req, lc, &dh_info); + if (rc) { + ksmbd_debug(SMB, "error parsing durable handle context\n"); + goto err_out2; + } + + if (dh_info.reconnected == true) { + rc = smb2_check_durable_oplock(conn, share, dh_info.fp, lc, name); + if (rc) { + ksmbd_put_durable_fd(dh_info.fp); + goto err_out2; + } + + rc = ksmbd_reopen_durable_fd(work, dh_info.fp); + if (rc) { + ksmbd_put_durable_fd(dh_info.fp); + goto err_out2; + } + + if (ksmbd_override_fsids(work)) { + rc = -ENOMEM; + ksmbd_put_durable_fd(dh_info.fp); + goto err_out2; + } + + fp = dh_info.fp; + file_info = FILE_OPENED; + + rc = ksmbd_vfs_getattr(&fp->filp->f_path, &stat); + if (rc) + goto err_out2; + + ksmbd_put_durable_fd(fp); + goto reconnected_fp; + } + } else if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) + lc = parse_lease_state(req); + if (le32_to_cpu(req->ImpersonationLevel) > le32_to_cpu(IL_DELEGATE)) { pr_err("Invalid impersonationlevel : 0x%x\n", le32_to_cpu(req->ImpersonationLevel)); @@ -3183,10 +3386,6 @@ int smb2_open(struct ksmbd_work *work) need_truncate = 1; } - req_op_level = req->RequestedOplockLevel; - if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) - lc = parse_lease_state(req, S_ISDIR(file_inode(filp)->i_mode)); - share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp); if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) || (req_op_level == SMB2_OPLOCK_LEVEL_LEASE && @@ -3197,6 +3396,11 @@ int smb2_open(struct ksmbd_work *work) } } else { if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) { + if (S_ISDIR(file_inode(filp)->i_mode)) { + lc->req_state &= ~SMB2_LEASE_WRITE_CACHING_LE; + lc->is_dir = true; + } + /* * Compare parent lease using parent key. If there is no * a lease that has same parent key, Send lease break @@ -3293,6 +3497,24 @@ int smb2_open(struct ksmbd_work *work) memcpy(fp->client_guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE); + if (dh_info.type == DURABLE_REQ_V2 || dh_info.type == DURABLE_REQ) { + if (dh_info.type == DURABLE_REQ_V2 && dh_info.persistent) + fp->is_persistent = true; + else + fp->is_durable = true; + + if (dh_info.type == DURABLE_REQ_V2) { + memcpy(fp->create_guid, dh_info.CreateGuid, + SMB2_CREATE_GUID_SIZE); + if (dh_info.timeout) + fp->durable_timeout = min(dh_info.timeout, + 300000); + else + fp->durable_timeout = 60; + } + } + +reconnected_fp: rsp->StructureSize = cpu_to_le16(89); rcu_read_lock(); opinfo = rcu_dereference(fp->f_opinfo); @@ -3379,6 +3601,33 @@ int smb2_open(struct ksmbd_work *work) next_off = conn->vals->create_disk_id_size; } + if (dh_info.type == DURABLE_REQ || dh_info.type == DURABLE_REQ_V2) { + struct create_context *durable_ccontext; + + durable_ccontext = (struct create_context *)(rsp->Buffer + + le32_to_cpu(rsp->CreateContextsLength)); + contxt_cnt++; + if (dh_info.type == DURABLE_REQ) { + create_durable_rsp_buf(rsp->Buffer + + le32_to_cpu(rsp->CreateContextsLength)); + le32_add_cpu(&rsp->CreateContextsLength, + conn->vals->create_durable_size); + iov_len += conn->vals->create_durable_size; + } else { + create_durable_v2_rsp_buf(rsp->Buffer + + le32_to_cpu(rsp->CreateContextsLength), + fp); + le32_add_cpu(&rsp->CreateContextsLength, + conn->vals->create_durable_v2_size); + iov_len += conn->vals->create_durable_v2_size; + } + + if (next_ptr) + *next_ptr = cpu_to_le32(next_off); + next_ptr = &durable_ccontext->Next; + next_off = conn->vals->create_durable_size; + } + if (posix_ctxt) { contxt_cnt++; create_posix_rsp_buf(rsp->Buffer + diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h index d12cfd3b09278e..bd1d2a0e9203a4 100644 --- a/fs/smb/server/smb2pdu.h +++ b/fs/smb/server/smb2pdu.h @@ -72,6 +72,18 @@ struct create_durable_req_v2 { __u8 CreateGuid[16]; } __packed; +struct create_durable_reconn_req { + struct create_context ccontext; + __u8 Name[8]; + union { + __u8 Reserved[16]; + struct { + __u64 PersistentFileId; + __u64 VolatileFileId; + } Fid; + } Data; +} __packed; + struct create_durable_reconn_v2_req { struct create_context ccontext; __u8 Name[8]; @@ -98,6 +110,9 @@ struct create_durable_rsp { } Data; } __packed; +/* See MS-SMB2 2.2.13.2.11 */ +/* Flags */ +#define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002 struct create_durable_v2_rsp { struct create_context ccontext; __u8 Name[8]; diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c index 4e82ff627d1224..030f70700036c1 100644 --- a/fs/smb/server/vfs_cache.c +++ b/fs/smb/server/vfs_cache.c @@ -305,7 +305,8 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp) fd_limit_close(); __ksmbd_remove_durable_fd(fp); - __ksmbd_remove_fd(ft, fp); + if (ft) + __ksmbd_remove_fd(ft, fp); close_id_del_oplock(fp); filp = fp->filp; @@ -465,11 +466,32 @@ struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id, return fp; } -struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id) +struct ksmbd_file *ksmbd_lookup_global_fd(unsigned long long id) { return __ksmbd_lookup_fd(&global_ft, id); } +struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id) +{ + struct ksmbd_file *fp; + + fp = __ksmbd_lookup_fd(&global_ft, id); + if (fp && fp->conn) { + ksmbd_put_durable_fd(fp); + fp = NULL; + } + + return fp; +} + +void ksmbd_put_durable_fd(struct ksmbd_file *fp) +{ + if (!atomic_dec_and_test(&fp->refcount)) + return; + + __ksmbd_close_fd(NULL, fp); +} + struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid) { struct ksmbd_file *fp = NULL; @@ -639,6 +661,32 @@ __close_file_table_ids(struct ksmbd_file_table *ft, return num; } +static inline bool is_reconnectable(struct ksmbd_file *fp) +{ + struct oplock_info *opinfo = opinfo_get(fp); + bool reconn = false; + + if (!opinfo) + return false; + + if (opinfo->op_state != OPLOCK_STATE_NONE) { + opinfo_put(opinfo); + return false; + } + + if (fp->is_resilient || fp->is_persistent) + reconn = true; + else if (fp->is_durable && opinfo->is_lease && + opinfo->o_lease->state & SMB2_LEASE_HANDLE_CACHING_LE) + reconn = true; + + else if (fp->is_durable && opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) + reconn = true; + + opinfo_put(opinfo); + return reconn; +} + static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon, struct ksmbd_file *fp) { @@ -648,7 +696,28 @@ static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon, static bool session_fd_check(struct ksmbd_tree_connect *tcon, struct ksmbd_file *fp) { - return false; + struct ksmbd_inode *ci; + struct oplock_info *op; + struct ksmbd_conn *conn; + + if (!is_reconnectable(fp)) + return false; + + conn = fp->conn; + ci = fp->f_ci; + write_lock(&ci->m_lock); + list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) { + if (op->conn != conn) + continue; + op->conn = NULL; + } + write_unlock(&ci->m_lock); + + fp->conn = NULL; + fp->tcon = NULL; + fp->volatile_id = KSMBD_NO_FID; + + return true; } void ksmbd_close_tree_conn_fds(struct ksmbd_work *work) @@ -687,6 +756,68 @@ void ksmbd_free_global_file_table(void) ksmbd_destroy_file_table(&global_ft); } +int ksmbd_validate_name_reconnect(struct ksmbd_share_config *share, + struct ksmbd_file *fp, char *name) +{ + char *pathname, *ab_pathname; + int ret = 0; + + pathname = kmalloc(PATH_MAX, GFP_KERNEL); + if (!pathname) + return -EACCES; + + ab_pathname = d_path(&fp->filp->f_path, pathname, PATH_MAX); + if (IS_ERR(ab_pathname)) { + kfree(pathname); + return -EACCES; + } + + if (name && strcmp(&ab_pathname[share->path_sz + 1], name)) { + ksmbd_debug(SMB, "invalid name reconnect %s\n", name); + ret = -EINVAL; + } + + kfree(pathname); + + return ret; +} + +int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp) +{ + struct ksmbd_inode *ci; + struct oplock_info *op; + + if (!fp->is_durable || fp->conn || fp->tcon) { + pr_err("Invalid durable fd [%p:%p]\n", fp->conn, fp->tcon); + return -EBADF; + } + + if (has_file_id(fp->volatile_id)) { + pr_err("Still in use durable fd: %llu\n", fp->volatile_id); + return -EBADF; + } + + fp->conn = work->conn; + fp->tcon = work->tcon; + + ci = fp->f_ci; + write_lock(&ci->m_lock); + list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) { + if (op->conn) + continue; + op->conn = fp->conn; + } + write_unlock(&ci->m_lock); + + __open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID); + if (!has_file_id(fp->volatile_id)) { + fp->conn = NULL; + fp->tcon = NULL; + return -EBADF; + } + return 0; +} + int ksmbd_init_file_table(struct ksmbd_file_table *ft) { ft->idr = kzalloc(sizeof(struct idr), GFP_KERNEL); diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h index a528f0cc775ae0..ed44fb4e18e79c 100644 --- a/fs/smb/server/vfs_cache.h +++ b/fs/smb/server/vfs_cache.h @@ -14,6 +14,7 @@ #include #include "vfs.h" +#include "mgmt/share_config.h" /* Windows style file permissions for extended response */ #define FILE_GENERIC_ALL 0x1F01FF @@ -106,6 +107,9 @@ struct ksmbd_file { int dot_dotdot[2]; unsigned int f_state; bool reserve_lease_break; + bool is_durable; + bool is_persistent; + bool is_resilient; }; static inline void set_ctx_actor(struct dir_context *ctx, @@ -141,7 +145,9 @@ struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id, void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp); struct ksmbd_inode *ksmbd_inode_lookup_lock(struct dentry *d); void ksmbd_inode_put(struct ksmbd_inode *ci); +struct ksmbd_file *ksmbd_lookup_global_fd(unsigned long long id); struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id); +void ksmbd_put_durable_fd(struct ksmbd_file *fp); struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid); struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry); unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp); @@ -173,6 +179,9 @@ void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp); void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp); void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp, int file_info); +int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp); +int ksmbd_validate_name_reconnect(struct ksmbd_share_config *share, + struct ksmbd_file *fp, char *name); int ksmbd_init_file_cache(void); void ksmbd_exit_file_cache(void); #endif /* __VFS_CACHE_H__ */ -- cgit 1.2.3-korg From 5fb282ba4fef8985a5acf2b32681f2ec07732561 Mon Sep 17 00:00:00 2001 From: Marios Makassikis Date: Wed, 13 Mar 2024 15:11:38 +0100 Subject: ksmbd: fix possible null-deref in smb_lazy_parent_lease_break_close rcu_dereference can return NULL, so make sure we check against that. Signed-off-by: Marios Makassikis Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/oplock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c index 9af5fd68bd85b4..b30ff8b9777df6 100644 --- a/fs/smb/server/oplock.c +++ b/fs/smb/server/oplock.c @@ -1143,7 +1143,7 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp) opinfo = rcu_dereference(fp->f_opinfo); rcu_read_unlock(); - if (!opinfo->is_lease || opinfo->o_lease->version != 2) + if (!opinfo || !opinfo->is_lease || opinfo->o_lease->version != 2) return; p_ci = ksmbd_inode_lookup_lock(fp->filp->f_path.dentry->d_parent); -- cgit 1.2.3-korg From e758fa6956cbc873e4819ec3dd97cfd05a4c147e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 13 Mar 2024 09:16:16 +0000 Subject: ksmbd: Fix spelling mistake "connction" -> "connection" There is a spelling mistake in a ksmbd_debug debug message. Fix it. Signed-off-by: Colin Ian King Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/oplock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c index b30ff8b9777df6..4978edfb15f9d7 100644 --- a/fs/smb/server/oplock.c +++ b/fs/smb/server/oplock.c @@ -1843,7 +1843,7 @@ int smb2_check_durable_oplock(struct ksmbd_conn *conn, if (memcmp(conn->ClientGUID, fp->client_guid, SMB2_CLIENT_GUID_SIZE)) { - ksmbd_debug(SMB, "Client guid of fp is not equal to the one of connction\n"); + ksmbd_debug(SMB, "Client guid of fp is not equal to the one of connection\n"); ret = -EBADF; goto out; } -- cgit 1.2.3-korg From a80a486d72e20bd12c335bcd38b6e6f19356b0aa Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sat, 16 Mar 2024 23:36:36 +0900 Subject: ksmbd: fix slab-out-of-bounds in smb_strndup_from_utf16() If ->NameOffset of smb2_create_req is smaller than Buffer offset of smb2_create_req, slab-out-of-bounds read can happen from smb2_open. This patch set the minimum value of the name offset to the buffer offset to validate name length of smb2_create_req(). Cc: stable@vger.kernel.org Reported-by: Xuanzhe Yu Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2misc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/smb/server/smb2misc.c b/fs/smb/server/smb2misc.c index 03dded29a98042..7c872ffb4b0a98 100644 --- a/fs/smb/server/smb2misc.c +++ b/fs/smb/server/smb2misc.c @@ -107,7 +107,10 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len, case SMB2_CREATE: { unsigned short int name_off = - le16_to_cpu(((struct smb2_create_req *)hdr)->NameOffset); + max_t(unsigned short int, + le16_to_cpu(((struct smb2_create_req *)hdr)->NameOffset), + offsetof(struct smb2_create_req, Buffer)); + unsigned short int name_len = le16_to_cpu(((struct smb2_create_req *)hdr)->NameLength); -- cgit 1.2.3-korg From c6cd2e8d2d9aa7ee35b1fa6a668e32a22a9753da Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 19 Mar 2024 08:40:48 +0900 Subject: ksmbd: fix potencial out-of-bounds when buffer offset is invalid I found potencial out-of-bounds when buffer offset fields of a few requests is invalid. This patch set the minimum value of buffer offset field to ->Buffer offset to validate buffer length. Cc: stable@vger.kernel.org Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2misc.c | 23 ++++++++++++++++------- fs/smb/server/smb2pdu.c | 48 ++++++++++++++++++++++++++---------------------- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/fs/smb/server/smb2misc.c b/fs/smb/server/smb2misc.c index 7c872ffb4b0a98..727cb49926ee52 100644 --- a/fs/smb/server/smb2misc.c +++ b/fs/smb/server/smb2misc.c @@ -101,7 +101,9 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len, *len = le16_to_cpu(((struct smb2_sess_setup_req *)hdr)->SecurityBufferLength); break; case SMB2_TREE_CONNECT: - *off = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset); + *off = max_t(unsigned short int, + le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset), + offsetof(struct smb2_tree_connect_req, Buffer)); *len = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathLength); break; case SMB2_CREATE: @@ -110,7 +112,6 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len, max_t(unsigned short int, le16_to_cpu(((struct smb2_create_req *)hdr)->NameOffset), offsetof(struct smb2_create_req, Buffer)); - unsigned short int name_len = le16_to_cpu(((struct smb2_create_req *)hdr)->NameLength); @@ -131,11 +132,15 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len, break; } case SMB2_QUERY_INFO: - *off = le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset); + *off = max_t(unsigned int, + le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset), + offsetof(struct smb2_query_info_req, Buffer)); *len = le32_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferLength); break; case SMB2_SET_INFO: - *off = le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset); + *off = max_t(unsigned int, + le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset), + offsetof(struct smb2_set_info_req, Buffer)); *len = le32_to_cpu(((struct smb2_set_info_req *)hdr)->BufferLength); break; case SMB2_READ: @@ -145,7 +150,7 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len, case SMB2_WRITE: if (((struct smb2_write_req *)hdr)->DataOffset || ((struct smb2_write_req *)hdr)->Length) { - *off = max_t(unsigned int, + *off = max_t(unsigned short int, le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset), offsetof(struct smb2_write_req, Buffer)); *len = le32_to_cpu(((struct smb2_write_req *)hdr)->Length); @@ -156,7 +161,9 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len, *len = le16_to_cpu(((struct smb2_write_req *)hdr)->WriteChannelInfoLength); break; case SMB2_QUERY_DIRECTORY: - *off = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset); + *off = max_t(unsigned short int, + le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset), + offsetof(struct smb2_query_directory_req, Buffer)); *len = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameLength); break; case SMB2_LOCK: @@ -171,7 +178,9 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len, break; } case SMB2_IOCTL: - *off = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset); + *off = max_t(unsigned int, + le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset), + offsetof(struct smb2_ioctl_req, Buffer)); *len = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputCount); break; default: diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 1ef3859fed1b30..3f3408f086699f 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -1927,7 +1927,7 @@ int smb2_tree_connect(struct ksmbd_work *work) WORK_BUFFERS(work, req, rsp); - treename = smb_strndup_from_utf16(req->Buffer, + treename = smb_strndup_from_utf16((char *)req + le16_to_cpu(req->PathOffset), le16_to_cpu(req->PathLength), true, conn->local_nls); if (IS_ERR(treename)) { @@ -2840,7 +2840,7 @@ int smb2_open(struct ksmbd_work *work) goto err_out2; } - name = smb2_get_name(req->Buffer, + name = smb2_get_name((char *)req + le16_to_cpu(req->NameOffset), le16_to_cpu(req->NameLength), work->conn->local_nls); if (IS_ERR(name)) { @@ -4305,7 +4305,7 @@ int smb2_query_dir(struct ksmbd_work *work) } srch_flag = req->Flags; - srch_ptr = smb_strndup_from_utf16(req->Buffer, + srch_ptr = smb_strndup_from_utf16((char *)req + le16_to_cpu(req->FileNameOffset), le16_to_cpu(req->FileNameLength), 1, conn->local_nls); if (IS_ERR(srch_ptr)) { @@ -4565,7 +4565,8 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp, sizeof(struct smb2_ea_info_req)) return -EINVAL; - ea_req = (struct smb2_ea_info_req *)req->Buffer; + ea_req = (struct smb2_ea_info_req *)((char *)req + + le16_to_cpu(req->InputBufferOffset)); } else { /* need to send all EAs, if no specific EA is requested*/ if (le32_to_cpu(req->Flags) & SL_RETURN_SINGLE_ENTRY) @@ -6211,6 +6212,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, struct ksmbd_share_config *share) { unsigned int buf_len = le32_to_cpu(req->BufferLength); + char *buffer = (char *)req + le16_to_cpu(req->BufferOffset); switch (req->FileInfoClass) { case FILE_BASIC_INFORMATION: @@ -6218,7 +6220,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, if (buf_len < sizeof(struct smb2_file_basic_info)) return -EINVAL; - return set_file_basic_info(fp, (struct smb2_file_basic_info *)req->Buffer, share); + return set_file_basic_info(fp, (struct smb2_file_basic_info *)buffer, share); } case FILE_ALLOCATION_INFORMATION: { @@ -6226,7 +6228,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, return -EINVAL; return set_file_allocation_info(work, fp, - (struct smb2_file_alloc_info *)req->Buffer); + (struct smb2_file_alloc_info *)buffer); } case FILE_END_OF_FILE_INFORMATION: { @@ -6234,7 +6236,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, return -EINVAL; return set_end_of_file_info(work, fp, - (struct smb2_file_eof_info *)req->Buffer); + (struct smb2_file_eof_info *)buffer); } case FILE_RENAME_INFORMATION: { @@ -6242,7 +6244,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, return -EINVAL; return set_rename_info(work, fp, - (struct smb2_file_rename_info *)req->Buffer, + (struct smb2_file_rename_info *)buffer, buf_len); } case FILE_LINK_INFORMATION: @@ -6251,7 +6253,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, return -EINVAL; return smb2_create_link(work, work->tcon->share_conf, - (struct smb2_file_link_info *)req->Buffer, + (struct smb2_file_link_info *)buffer, buf_len, fp->filp, work->conn->local_nls); } @@ -6261,7 +6263,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, return -EINVAL; return set_file_disposition_info(fp, - (struct smb2_file_disposition_info *)req->Buffer); + (struct smb2_file_disposition_info *)buffer); } case FILE_FULL_EA_INFORMATION: { @@ -6274,7 +6276,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, if (buf_len < sizeof(struct smb2_ea_info)) return -EINVAL; - return smb2_set_ea((struct smb2_ea_info *)req->Buffer, + return smb2_set_ea((struct smb2_ea_info *)buffer, buf_len, &fp->filp->f_path, true); } case FILE_POSITION_INFORMATION: @@ -6282,14 +6284,14 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, if (buf_len < sizeof(struct smb2_file_pos_info)) return -EINVAL; - return set_file_position_info(fp, (struct smb2_file_pos_info *)req->Buffer); + return set_file_position_info(fp, (struct smb2_file_pos_info *)buffer); } case FILE_MODE_INFORMATION: { if (buf_len < sizeof(struct smb2_file_mode_info)) return -EINVAL; - return set_file_mode_info(fp, (struct smb2_file_mode_info *)req->Buffer); + return set_file_mode_info(fp, (struct smb2_file_mode_info *)buffer); } } @@ -6370,7 +6372,7 @@ int smb2_set_info(struct ksmbd_work *work) } rc = smb2_set_info_sec(fp, le32_to_cpu(req->AdditionalInformation), - req->Buffer, + (char *)req + le16_to_cpu(req->BufferOffset), le32_to_cpu(req->BufferLength)); ksmbd_revert_fsids(work); break; @@ -7816,7 +7818,7 @@ static int fsctl_pipe_transceive(struct ksmbd_work *work, u64 id, struct smb2_ioctl_rsp *rsp) { struct ksmbd_rpc_command *rpc_resp; - char *data_buf = (char *)&req->Buffer[0]; + char *data_buf = (char *)req + le32_to_cpu(req->InputOffset); int nbytes = 0; rpc_resp = ksmbd_rpc_ioctl(work->sess, id, data_buf, @@ -7929,6 +7931,7 @@ int smb2_ioctl(struct ksmbd_work *work) u64 id = KSMBD_NO_FID; struct ksmbd_conn *conn = work->conn; int ret = 0; + char *buffer; if (work->next_smb2_rcv_hdr_off) { req = ksmbd_req_buf_next(work); @@ -7951,6 +7954,8 @@ int smb2_ioctl(struct ksmbd_work *work) goto out; } + buffer = (char *)req + le32_to_cpu(req->InputOffset); + cnt_code = le32_to_cpu(req->CtlCode); ret = smb2_calc_max_out_buf_len(work, 48, le32_to_cpu(req->MaxOutputResponse)); @@ -8008,7 +8013,7 @@ int smb2_ioctl(struct ksmbd_work *work) } ret = fsctl_validate_negotiate_info(conn, - (struct validate_negotiate_info_req *)&req->Buffer[0], + (struct validate_negotiate_info_req *)buffer, (struct validate_negotiate_info_rsp *)&rsp->Buffer[0], in_buf_len); if (ret < 0) @@ -8061,7 +8066,7 @@ int smb2_ioctl(struct ksmbd_work *work) rsp->VolatileFileId = req->VolatileFileId; rsp->PersistentFileId = req->PersistentFileId; fsctl_copychunk(work, - (struct copychunk_ioctl_req *)&req->Buffer[0], + (struct copychunk_ioctl_req *)buffer, le32_to_cpu(req->CtlCode), le32_to_cpu(req->InputCount), req->VolatileFileId, @@ -8074,8 +8079,7 @@ int smb2_ioctl(struct ksmbd_work *work) goto out; } - ret = fsctl_set_sparse(work, id, - (struct file_sparse *)&req->Buffer[0]); + ret = fsctl_set_sparse(work, id, (struct file_sparse *)buffer); if (ret < 0) goto out; break; @@ -8098,7 +8102,7 @@ int smb2_ioctl(struct ksmbd_work *work) } zero_data = - (struct file_zero_data_information *)&req->Buffer[0]; + (struct file_zero_data_information *)buffer; off = le64_to_cpu(zero_data->FileOffset); bfz = le64_to_cpu(zero_data->BeyondFinalZero); @@ -8129,7 +8133,7 @@ int smb2_ioctl(struct ksmbd_work *work) } ret = fsctl_query_allocated_ranges(work, id, - (struct file_allocated_range_buffer *)&req->Buffer[0], + (struct file_allocated_range_buffer *)buffer, (struct file_allocated_range_buffer *)&rsp->Buffer[0], out_buf_len / sizeof(struct file_allocated_range_buffer), &nbytes); @@ -8173,7 +8177,7 @@ int smb2_ioctl(struct ksmbd_work *work) goto out; } - dup_ext = (struct duplicate_extents_to_file *)&req->Buffer[0]; + dup_ext = (struct duplicate_extents_to_file *)buffer; fp_in = ksmbd_lookup_fd_slow(work, dup_ext->VolatileFileHandle, dup_ext->PersistentFileHandle); -- cgit 1.2.3-korg From def30e72d8abaf68da10682767e584519c234c4c Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 18 Mar 2024 22:10:10 +0900 Subject: ksmbd: remove module version ksmbd module version marking is not needed. Since there is a Linux kernel version, there is no point in increasing it anymore. Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/glob.h | 2 -- fs/smb/server/server.c | 1 - 2 files changed, 3 deletions(-) diff --git a/fs/smb/server/glob.h b/fs/smb/server/glob.h index 5b8f3e0ebdb36a..d528b20b37a85f 100644 --- a/fs/smb/server/glob.h +++ b/fs/smb/server/glob.h @@ -12,8 +12,6 @@ #include "unicode.h" #include "vfs_cache.h" -#define KSMBD_VERSION "3.4.2" - extern int ksmbd_debug_types; #define KSMBD_DEBUG_SMB BIT(0) diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c index 3079e607c5fe6d..c0788188aa82fa 100644 --- a/fs/smb/server/server.c +++ b/fs/smb/server/server.c @@ -625,7 +625,6 @@ static void __exit ksmbd_server_exit(void) } MODULE_AUTHOR("Namjae Jeon "); -MODULE_VERSION(KSMBD_VERSION); MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER"); MODULE_LICENSE("GPL"); MODULE_SOFTDEP("pre: ecb"); -- cgit 1.2.3-korg