Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'v6.9-rc-smb3-server-fixes' of git://git.samba.org/ksmbd

Pull smb server updates from Steve French:

- add support for durable file handles (an important data integrity
feature)

- fixes for potential out of bounds issues

- fix possible null dereference in close

- getattr fixes

- trivial typo fix and minor cleanup

* tag 'v6.9-rc-smb3-server-fixes' of git://git.samba.org/ksmbd:
ksmbd: remove module version
ksmbd: fix potencial out-of-bounds when buffer offset is invalid
ksmbd: fix slab-out-of-bounds in smb_strndup_from_utf16()
ksmbd: Fix spelling mistake "connction" -> "connection"
ksmbd: fix possible null-deref in smb_lazy_parent_lease_break_close
ksmbd: add support for durable handles v1/v2
ksmbd: mark SMB2_SESSION_EXPIRED to session when destroying previous session
ksmbd: retrieve number of blocks using vfs_getattr in set_file_allocation_info
ksmbd: replace generic_fillattr with vfs_getattr

+716 -147
-2
fs/smb/server/glob.h
··· 12 12 #include "unicode.h" 13 13 #include "vfs_cache.h" 14 14 15 - #define KSMBD_VERSION "3.4.2" 16 - 17 15 extern int ksmbd_debug_types; 18 16 19 17 #define KSMBD_DEBUG_SMB BIT(0)
+1
fs/smb/server/ksmbd_netlink.h
··· 75 75 #define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION BIT(1) 76 76 #define KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL BIT(2) 77 77 #define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF BIT(3) 78 + #define KSMBD_GLOBAL_FLAG_DURABLE_HANDLE BIT(4) 78 79 79 80 /* 80 81 * IPC request for ksmbd server startup
+27 -1
fs/smb/server/mgmt/user_session.c
··· 156 156 kfree(sess); 157 157 } 158 158 159 - static struct ksmbd_session *__session_lookup(unsigned long long id) 159 + struct ksmbd_session *__session_lookup(unsigned long long id) 160 160 { 161 161 struct ksmbd_session *sess; 162 162 ··· 303 303 list_add(&sess->preauth_entry, &conn->preauth_sess_table); 304 304 305 305 return sess; 306 + } 307 + 308 + void destroy_previous_session(struct ksmbd_conn *conn, 309 + struct ksmbd_user *user, u64 id) 310 + { 311 + struct ksmbd_session *prev_sess; 312 + struct ksmbd_user *prev_user; 313 + 314 + down_write(&sessions_table_lock); 315 + down_write(&conn->session_lock); 316 + prev_sess = __session_lookup(id); 317 + if (!prev_sess || prev_sess->state == SMB2_SESSION_EXPIRED) 318 + goto out; 319 + 320 + prev_user = prev_sess->user; 321 + if (!prev_user || 322 + strcmp(user->name, prev_user->name) || 323 + user->passkey_sz != prev_user->passkey_sz || 324 + memcmp(user->passkey, prev_user->passkey, user->passkey_sz)) 325 + goto out; 326 + 327 + ksmbd_destroy_file_table(&prev_sess->file_table); 328 + prev_sess->state = SMB2_SESSION_EXPIRED; 329 + out: 330 + up_write(&conn->session_lock); 331 + up_write(&sessions_table_lock); 306 332 } 307 333 308 334 static bool ksmbd_preauth_session_id_match(struct preauth_session *sess,
+3
fs/smb/server/mgmt/user_session.h
··· 88 88 int ksmbd_session_register(struct ksmbd_conn *conn, 89 89 struct ksmbd_session *sess); 90 90 void ksmbd_sessions_deregister(struct ksmbd_conn *conn); 91 + struct ksmbd_session *__session_lookup(unsigned long long id); 91 92 struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, 92 93 unsigned long long id); 94 + void destroy_previous_session(struct ksmbd_conn *conn, 95 + struct ksmbd_user *user, u64 id); 93 96 struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn, 94 97 u64 sess_id); 95 98 struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn,
+82 -14
fs/smb/server/oplock.c
··· 159 159 opinfo = list_first_or_null_rcu(&ci->m_op_list, struct oplock_info, 160 160 op_entry); 161 161 if (opinfo) { 162 - if (!atomic_inc_not_zero(&opinfo->refcount)) 162 + if (opinfo->conn == NULL || 163 + !atomic_inc_not_zero(&opinfo->refcount)) 163 164 opinfo = NULL; 164 165 else { 165 166 atomic_inc(&opinfo->conn->r_count); ··· 528 527 */ 529 528 read_lock(&ci->m_lock); 530 529 list_for_each_entry(opinfo, &ci->m_op_list, op_entry) { 531 - if (!opinfo->is_lease) 530 + if (!opinfo->is_lease || !opinfo->conn) 532 531 continue; 533 532 read_unlock(&ci->m_lock); 534 533 lease = opinfo->o_lease; ··· 642 641 struct smb2_hdr *rsp_hdr; 643 642 struct ksmbd_file *fp; 644 643 645 - fp = ksmbd_lookup_durable_fd(br_info->fid); 644 + fp = ksmbd_lookup_global_fd(br_info->fid); 646 645 if (!fp) 647 646 goto out; 648 647 ··· 1107 1106 1108 1107 read_lock(&p_ci->m_lock); 1109 1108 list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) { 1110 - if (!opinfo->is_lease) 1109 + if (opinfo->conn == NULL || !opinfo->is_lease) 1111 1110 continue; 1112 1111 1113 1112 if (opinfo->o_lease->state != SMB2_OPLOCK_LEVEL_NONE && ··· 1143 1142 opinfo = rcu_dereference(fp->f_opinfo); 1144 1143 rcu_read_unlock(); 1145 1144 1146 - if (!opinfo->is_lease || opinfo->o_lease->version != 2) 1145 + if (!opinfo || !opinfo->is_lease || opinfo->o_lease->version != 2) 1147 1146 return; 1148 1147 1149 1148 p_ci = ksmbd_inode_lookup_lock(fp->filp->f_path.dentry->d_parent); ··· 1152 1151 1153 1152 read_lock(&p_ci->m_lock); 1154 1153 list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) { 1155 - if (!opinfo->is_lease) 1154 + if (opinfo->conn == NULL || !opinfo->is_lease) 1156 1155 continue; 1157 1156 1158 1157 if (opinfo->o_lease->state != SMB2_OPLOCK_LEVEL_NONE) { ··· 1362 1361 1363 1362 rcu_read_lock(); 1364 1363 list_for_each_entry_rcu(brk_op, &ci->m_op_list, op_entry) { 1364 + if (brk_op->conn == NULL) 1365 + continue; 1366 + 1365 1367 if (!atomic_inc_not_zero(&brk_op->refcount)) 1366 1368 continue; 1367 1369 ··· 1500 1496 /** 1501 1497 * parse_lease_state() - parse lease context containted in file open request 1502 1498 * @open_req: buffer containing smb2 file open(create) request 1503 - * @is_dir: whether leasing file is directory 1504 1499 * 1505 1500 * Return: oplock state, -ENOENT if create lease context not found 1506 1501 */ 1507 - struct lease_ctx_info *parse_lease_state(void *open_req, bool is_dir) 1502 + struct lease_ctx_info *parse_lease_state(void *open_req) 1508 1503 { 1509 1504 struct create_context *cc; 1510 1505 struct smb2_create_req *req = (struct smb2_create_req *)open_req; ··· 1521 1518 struct create_lease_v2 *lc = (struct create_lease_v2 *)cc; 1522 1519 1523 1520 memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE); 1524 - if (is_dir) { 1525 - lreq->req_state = lc->lcontext.LeaseState & 1526 - ~SMB2_LEASE_WRITE_CACHING_LE; 1527 - lreq->is_dir = true; 1528 - } else 1529 - lreq->req_state = lc->lcontext.LeaseState; 1521 + lreq->req_state = lc->lcontext.LeaseState; 1530 1522 lreq->flags = lc->lcontext.LeaseFlags; 1531 1523 lreq->epoch = lc->lcontext.Epoch; 1532 1524 lreq->duration = lc->lcontext.LeaseDuration; ··· 1644 1646 buf->Name[3] = 'Q'; 1645 1647 1646 1648 buf->Timeout = cpu_to_le32(fp->durable_timeout); 1649 + if (fp->is_persistent) 1650 + buf->Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT); 1647 1651 } 1648 1652 1649 1653 /** ··· 1812 1812 out: 1813 1813 read_unlock(&lease_list_lock); 1814 1814 return ret_op; 1815 + } 1816 + 1817 + int smb2_check_durable_oplock(struct ksmbd_conn *conn, 1818 + struct ksmbd_share_config *share, 1819 + struct ksmbd_file *fp, 1820 + struct lease_ctx_info *lctx, 1821 + char *name) 1822 + { 1823 + struct oplock_info *opinfo = opinfo_get(fp); 1824 + int ret = 0; 1825 + 1826 + if (!opinfo) 1827 + return 0; 1828 + 1829 + if (opinfo->is_lease == false) { 1830 + if (lctx) { 1831 + pr_err("create context include lease\n"); 1832 + ret = -EBADF; 1833 + goto out; 1834 + } 1835 + 1836 + if (opinfo->level != SMB2_OPLOCK_LEVEL_BATCH) { 1837 + pr_err("oplock level is not equal to SMB2_OPLOCK_LEVEL_BATCH\n"); 1838 + ret = -EBADF; 1839 + } 1840 + 1841 + goto out; 1842 + } 1843 + 1844 + if (memcmp(conn->ClientGUID, fp->client_guid, 1845 + SMB2_CLIENT_GUID_SIZE)) { 1846 + ksmbd_debug(SMB, "Client guid of fp is not equal to the one of connection\n"); 1847 + ret = -EBADF; 1848 + goto out; 1849 + } 1850 + 1851 + if (!lctx) { 1852 + ksmbd_debug(SMB, "create context does not include lease\n"); 1853 + ret = -EBADF; 1854 + goto out; 1855 + } 1856 + 1857 + if (memcmp(opinfo->o_lease->lease_key, lctx->lease_key, 1858 + SMB2_LEASE_KEY_SIZE)) { 1859 + ksmbd_debug(SMB, 1860 + "lease key of fp does not match lease key in create context\n"); 1861 + ret = -EBADF; 1862 + goto out; 1863 + } 1864 + 1865 + if (!(opinfo->o_lease->state & SMB2_LEASE_HANDLE_CACHING_LE)) { 1866 + ksmbd_debug(SMB, "lease state does not contain SMB2_LEASE_HANDLE_CACHING\n"); 1867 + ret = -EBADF; 1868 + goto out; 1869 + } 1870 + 1871 + if (opinfo->o_lease->version != lctx->version) { 1872 + ksmbd_debug(SMB, 1873 + "lease version of fp does not match the one in create context\n"); 1874 + ret = -EBADF; 1875 + goto out; 1876 + } 1877 + 1878 + if (!ksmbd_inode_pending_delete(fp)) 1879 + ret = ksmbd_validate_name_reconnect(share, fp, name); 1880 + out: 1881 + opinfo_put(opinfo); 1882 + return ret; 1815 1883 }
+6 -1
fs/smb/server/oplock.h
··· 111 111 112 112 /* Lease related functions */ 113 113 void create_lease_buf(u8 *rbuf, struct lease *lease); 114 - struct lease_ctx_info *parse_lease_state(void *open_req, bool is_dir); 114 + struct lease_ctx_info *parse_lease_state(void *open_req); 115 115 __u8 smb2_map_lease_to_oplock(__le32 lease_state); 116 116 int lease_read_to_write(struct oplock_info *opinfo); 117 117 ··· 130 130 void smb_send_parent_lease_break_noti(struct ksmbd_file *fp, 131 131 struct lease_ctx_info *lctx); 132 132 void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp); 133 + int smb2_check_durable_oplock(struct ksmbd_conn *conn, 134 + struct ksmbd_share_config *share, 135 + struct ksmbd_file *fp, 136 + struct lease_ctx_info *lctx, 137 + char *name); 133 138 #endif /* __KSMBD_OPLOCK_H */
-1
fs/smb/server/server.c
··· 625 625 } 626 626 627 627 MODULE_AUTHOR("Namjae Jeon <linkinjeon@kernel.org>"); 628 - MODULE_VERSION(KSMBD_VERSION); 629 628 MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER"); 630 629 MODULE_LICENSE("GPL"); 631 630 MODULE_SOFTDEP("pre: ecb");
+19 -7
fs/smb/server/smb2misc.c
··· 101 101 *len = le16_to_cpu(((struct smb2_sess_setup_req *)hdr)->SecurityBufferLength); 102 102 break; 103 103 case SMB2_TREE_CONNECT: 104 - *off = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset); 104 + *off = max_t(unsigned short int, 105 + le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathOffset), 106 + offsetof(struct smb2_tree_connect_req, Buffer)); 105 107 *len = le16_to_cpu(((struct smb2_tree_connect_req *)hdr)->PathLength); 106 108 break; 107 109 case SMB2_CREATE: 108 110 { 109 111 unsigned short int name_off = 110 - le16_to_cpu(((struct smb2_create_req *)hdr)->NameOffset); 112 + max_t(unsigned short int, 113 + le16_to_cpu(((struct smb2_create_req *)hdr)->NameOffset), 114 + offsetof(struct smb2_create_req, Buffer)); 111 115 unsigned short int name_len = 112 116 le16_to_cpu(((struct smb2_create_req *)hdr)->NameLength); 113 117 ··· 132 128 break; 133 129 } 134 130 case SMB2_QUERY_INFO: 135 - *off = le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset); 131 + *off = max_t(unsigned int, 132 + le16_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferOffset), 133 + offsetof(struct smb2_query_info_req, Buffer)); 136 134 *len = le32_to_cpu(((struct smb2_query_info_req *)hdr)->InputBufferLength); 137 135 break; 138 136 case SMB2_SET_INFO: 139 - *off = le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset); 137 + *off = max_t(unsigned int, 138 + le16_to_cpu(((struct smb2_set_info_req *)hdr)->BufferOffset), 139 + offsetof(struct smb2_set_info_req, Buffer)); 140 140 *len = le32_to_cpu(((struct smb2_set_info_req *)hdr)->BufferLength); 141 141 break; 142 142 case SMB2_READ: ··· 150 142 case SMB2_WRITE: 151 143 if (((struct smb2_write_req *)hdr)->DataOffset || 152 144 ((struct smb2_write_req *)hdr)->Length) { 153 - *off = max_t(unsigned int, 145 + *off = max_t(unsigned short int, 154 146 le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset), 155 147 offsetof(struct smb2_write_req, Buffer)); 156 148 *len = le32_to_cpu(((struct smb2_write_req *)hdr)->Length); ··· 161 153 *len = le16_to_cpu(((struct smb2_write_req *)hdr)->WriteChannelInfoLength); 162 154 break; 163 155 case SMB2_QUERY_DIRECTORY: 164 - *off = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset); 156 + *off = max_t(unsigned short int, 157 + le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameOffset), 158 + offsetof(struct smb2_query_directory_req, Buffer)); 165 159 *len = le16_to_cpu(((struct smb2_query_directory_req *)hdr)->FileNameLength); 166 160 break; 167 161 case SMB2_LOCK: ··· 178 168 break; 179 169 } 180 170 case SMB2_IOCTL: 181 - *off = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset); 171 + *off = max_t(unsigned int, 172 + le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputOffset), 173 + offsetof(struct smb2_ioctl_req, Buffer)); 182 174 *len = le32_to_cpu(((struct smb2_ioctl_req *)hdr)->InputCount); 183 175 break; 184 176 default:
+6
fs/smb/server/smb2ops.c
··· 256 256 257 257 if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) 258 258 conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; 259 + 260 + if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE) 261 + conn->vals->capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES; 259 262 } 260 263 261 264 /** ··· 285 282 286 283 if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) 287 284 conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; 285 + 286 + if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE) 287 + conn->vals->capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES; 288 288 289 289 INIT_LIST_HEAD(&conn->preauth_sess_table); 290 290 return 0;
+397 -112
fs/smb/server/smb2pdu.c
··· 607 607 return -ENOENT; 608 608 } 609 609 610 - static void destroy_previous_session(struct ksmbd_conn *conn, 611 - struct ksmbd_user *user, u64 id) 612 - { 613 - struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id); 614 - struct ksmbd_user *prev_user; 615 - struct channel *chann; 616 - long index; 617 - 618 - if (!prev_sess) 619 - return; 620 - 621 - prev_user = prev_sess->user; 622 - 623 - if (!prev_user || 624 - strcmp(user->name, prev_user->name) || 625 - user->passkey_sz != prev_user->passkey_sz || 626 - memcmp(user->passkey, prev_user->passkey, user->passkey_sz)) 627 - return; 628 - 629 - prev_sess->state = SMB2_SESSION_EXPIRED; 630 - xa_for_each(&prev_sess->ksmbd_chann_list, index, chann) 631 - ksmbd_conn_set_exiting(chann->conn); 632 - } 633 - 634 610 /** 635 611 * smb2_get_name() - get filename string from on the wire smb format 636 612 * @src: source buffer ··· 1927 1951 1928 1952 WORK_BUFFERS(work, req, rsp); 1929 1953 1930 - treename = smb_strndup_from_utf16(req->Buffer, 1954 + treename = smb_strndup_from_utf16((char *)req + le16_to_cpu(req->PathOffset), 1931 1955 le16_to_cpu(req->PathLength), true, 1932 1956 conn->local_nls); 1933 1957 if (IS_ERR(treename)) { ··· 2618 2642 } 2619 2643 } 2620 2644 2645 + enum { 2646 + DURABLE_RECONN_V2 = 1, 2647 + DURABLE_RECONN, 2648 + DURABLE_REQ_V2, 2649 + DURABLE_REQ, 2650 + }; 2651 + 2652 + struct durable_info { 2653 + struct ksmbd_file *fp; 2654 + unsigned short int type; 2655 + bool persistent; 2656 + bool reconnected; 2657 + unsigned int timeout; 2658 + char *CreateGuid; 2659 + }; 2660 + 2661 + static int parse_durable_handle_context(struct ksmbd_work *work, 2662 + struct smb2_create_req *req, 2663 + struct lease_ctx_info *lc, 2664 + struct durable_info *dh_info) 2665 + { 2666 + struct ksmbd_conn *conn = work->conn; 2667 + struct create_context *context; 2668 + int dh_idx, err = 0; 2669 + u64 persistent_id = 0; 2670 + int req_op_level; 2671 + static const char * const durable_arr[] = {"DH2C", "DHnC", "DH2Q", "DHnQ"}; 2672 + 2673 + req_op_level = req->RequestedOplockLevel; 2674 + for (dh_idx = DURABLE_RECONN_V2; dh_idx <= ARRAY_SIZE(durable_arr); 2675 + dh_idx++) { 2676 + context = smb2_find_context_vals(req, durable_arr[dh_idx - 1], 4); 2677 + if (IS_ERR(context)) { 2678 + err = PTR_ERR(context); 2679 + goto out; 2680 + } 2681 + if (!context) 2682 + continue; 2683 + 2684 + switch (dh_idx) { 2685 + case DURABLE_RECONN_V2: 2686 + { 2687 + struct create_durable_reconn_v2_req *recon_v2; 2688 + 2689 + if (dh_info->type == DURABLE_RECONN || 2690 + dh_info->type == DURABLE_REQ_V2) { 2691 + err = -EINVAL; 2692 + goto out; 2693 + } 2694 + 2695 + recon_v2 = (struct create_durable_reconn_v2_req *)context; 2696 + persistent_id = recon_v2->Fid.PersistentFileId; 2697 + dh_info->fp = ksmbd_lookup_durable_fd(persistent_id); 2698 + if (!dh_info->fp) { 2699 + ksmbd_debug(SMB, "Failed to get durable handle state\n"); 2700 + err = -EBADF; 2701 + goto out; 2702 + } 2703 + 2704 + if (memcmp(dh_info->fp->create_guid, recon_v2->CreateGuid, 2705 + SMB2_CREATE_GUID_SIZE)) { 2706 + err = -EBADF; 2707 + ksmbd_put_durable_fd(dh_info->fp); 2708 + goto out; 2709 + } 2710 + 2711 + dh_info->type = dh_idx; 2712 + dh_info->reconnected = true; 2713 + ksmbd_debug(SMB, 2714 + "reconnect v2 Persistent-id from reconnect = %llu\n", 2715 + persistent_id); 2716 + break; 2717 + } 2718 + case DURABLE_RECONN: 2719 + { 2720 + struct create_durable_reconn_req *recon; 2721 + 2722 + if (dh_info->type == DURABLE_RECONN_V2 || 2723 + dh_info->type == DURABLE_REQ_V2) { 2724 + err = -EINVAL; 2725 + goto out; 2726 + } 2727 + 2728 + recon = (struct create_durable_reconn_req *)context; 2729 + persistent_id = recon->Data.Fid.PersistentFileId; 2730 + dh_info->fp = ksmbd_lookup_durable_fd(persistent_id); 2731 + if (!dh_info->fp) { 2732 + ksmbd_debug(SMB, "Failed to get durable handle state\n"); 2733 + err = -EBADF; 2734 + goto out; 2735 + } 2736 + 2737 + dh_info->type = dh_idx; 2738 + dh_info->reconnected = true; 2739 + ksmbd_debug(SMB, "reconnect Persistent-id from reconnect = %llu\n", 2740 + persistent_id); 2741 + break; 2742 + } 2743 + case DURABLE_REQ_V2: 2744 + { 2745 + struct create_durable_req_v2 *durable_v2_blob; 2746 + 2747 + if (dh_info->type == DURABLE_RECONN || 2748 + dh_info->type == DURABLE_RECONN_V2) { 2749 + err = -EINVAL; 2750 + goto out; 2751 + } 2752 + 2753 + durable_v2_blob = 2754 + (struct create_durable_req_v2 *)context; 2755 + ksmbd_debug(SMB, "Request for durable v2 open\n"); 2756 + dh_info->fp = ksmbd_lookup_fd_cguid(durable_v2_blob->CreateGuid); 2757 + if (dh_info->fp) { 2758 + if (!memcmp(conn->ClientGUID, dh_info->fp->client_guid, 2759 + SMB2_CLIENT_GUID_SIZE)) { 2760 + if (!(req->hdr.Flags & SMB2_FLAGS_REPLAY_OPERATION)) { 2761 + err = -ENOEXEC; 2762 + goto out; 2763 + } 2764 + 2765 + dh_info->fp->conn = conn; 2766 + dh_info->reconnected = true; 2767 + goto out; 2768 + } 2769 + } 2770 + 2771 + if (((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) || 2772 + req_op_level == SMB2_OPLOCK_LEVEL_BATCH)) { 2773 + dh_info->CreateGuid = 2774 + durable_v2_blob->CreateGuid; 2775 + dh_info->persistent = 2776 + le32_to_cpu(durable_v2_blob->Flags); 2777 + dh_info->timeout = 2778 + le32_to_cpu(durable_v2_blob->Timeout); 2779 + dh_info->type = dh_idx; 2780 + } 2781 + break; 2782 + } 2783 + case DURABLE_REQ: 2784 + if (dh_info->type == DURABLE_RECONN) 2785 + goto out; 2786 + if (dh_info->type == DURABLE_RECONN_V2 || 2787 + dh_info->type == DURABLE_REQ_V2) { 2788 + err = -EINVAL; 2789 + goto out; 2790 + } 2791 + 2792 + if (((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) || 2793 + req_op_level == SMB2_OPLOCK_LEVEL_BATCH)) { 2794 + ksmbd_debug(SMB, "Request for durable open\n"); 2795 + dh_info->type = dh_idx; 2796 + } 2797 + } 2798 + } 2799 + 2800 + out: 2801 + return err; 2802 + } 2803 + 2621 2804 /** 2622 2805 * smb2_open() - handler for smb file open request 2623 2806 * @work: smb work containing request buffer ··· 2800 2665 struct lease_ctx_info *lc = NULL; 2801 2666 struct create_ea_buf_req *ea_buf = NULL; 2802 2667 struct oplock_info *opinfo; 2668 + struct durable_info dh_info = {0}; 2803 2669 __le32 *next_ptr = NULL; 2804 2670 int req_op_level = 0, open_flags = 0, may_flags = 0, file_info = 0; 2805 2671 int rc = 0; ··· 2840 2704 goto err_out2; 2841 2705 } 2842 2706 2843 - name = smb2_get_name(req->Buffer, 2707 + name = smb2_get_name((char *)req + le16_to_cpu(req->NameOffset), 2844 2708 le16_to_cpu(req->NameLength), 2845 2709 work->conn->local_nls); 2846 2710 if (IS_ERR(name)) { ··· 2880 2744 goto err_out2; 2881 2745 } 2882 2746 } 2747 + 2748 + req_op_level = req->RequestedOplockLevel; 2749 + 2750 + if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE && 2751 + req->CreateContextsOffset) { 2752 + lc = parse_lease_state(req); 2753 + rc = parse_durable_handle_context(work, req, lc, &dh_info); 2754 + if (rc) { 2755 + ksmbd_debug(SMB, "error parsing durable handle context\n"); 2756 + goto err_out2; 2757 + } 2758 + 2759 + if (dh_info.reconnected == true) { 2760 + rc = smb2_check_durable_oplock(conn, share, dh_info.fp, lc, name); 2761 + if (rc) { 2762 + ksmbd_put_durable_fd(dh_info.fp); 2763 + goto err_out2; 2764 + } 2765 + 2766 + rc = ksmbd_reopen_durable_fd(work, dh_info.fp); 2767 + if (rc) { 2768 + ksmbd_put_durable_fd(dh_info.fp); 2769 + goto err_out2; 2770 + } 2771 + 2772 + if (ksmbd_override_fsids(work)) { 2773 + rc = -ENOMEM; 2774 + ksmbd_put_durable_fd(dh_info.fp); 2775 + goto err_out2; 2776 + } 2777 + 2778 + fp = dh_info.fp; 2779 + file_info = FILE_OPENED; 2780 + 2781 + rc = ksmbd_vfs_getattr(&fp->filp->f_path, &stat); 2782 + if (rc) 2783 + goto err_out2; 2784 + 2785 + ksmbd_put_durable_fd(fp); 2786 + goto reconnected_fp; 2787 + } 2788 + } else if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) 2789 + lc = parse_lease_state(req); 2883 2790 2884 2791 if (le32_to_cpu(req->ImpersonationLevel) > le32_to_cpu(IL_DELEGATE)) { 2885 2792 pr_err("Invalid impersonationlevel : 0x%x\n", ··· 3386 3207 need_truncate = 1; 3387 3208 } 3388 3209 3389 - req_op_level = req->RequestedOplockLevel; 3390 - if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) 3391 - lc = parse_lease_state(req, S_ISDIR(file_inode(filp)->i_mode)); 3392 - 3393 3210 share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp); 3394 3211 if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) || 3395 3212 (req_op_level == SMB2_OPLOCK_LEVEL_LEASE && ··· 3396 3221 } 3397 3222 } else { 3398 3223 if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) { 3224 + if (S_ISDIR(file_inode(filp)->i_mode)) { 3225 + lc->req_state &= ~SMB2_LEASE_WRITE_CACHING_LE; 3226 + lc->is_dir = true; 3227 + } 3228 + 3399 3229 /* 3400 3230 * Compare parent lease using parent key. If there is no 3401 3231 * a lease that has same parent key, Send lease break ··· 3497 3317 3498 3318 memcpy(fp->client_guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE); 3499 3319 3320 + if (dh_info.type == DURABLE_REQ_V2 || dh_info.type == DURABLE_REQ) { 3321 + if (dh_info.type == DURABLE_REQ_V2 && dh_info.persistent) 3322 + fp->is_persistent = true; 3323 + else 3324 + fp->is_durable = true; 3325 + 3326 + if (dh_info.type == DURABLE_REQ_V2) { 3327 + memcpy(fp->create_guid, dh_info.CreateGuid, 3328 + SMB2_CREATE_GUID_SIZE); 3329 + if (dh_info.timeout) 3330 + fp->durable_timeout = min(dh_info.timeout, 3331 + 300000); 3332 + else 3333 + fp->durable_timeout = 60; 3334 + } 3335 + } 3336 + 3337 + reconnected_fp: 3500 3338 rsp->StructureSize = cpu_to_le16(89); 3501 3339 rcu_read_lock(); 3502 3340 opinfo = rcu_dereference(fp->f_opinfo); ··· 3599 3401 *next_ptr = cpu_to_le32(next_off); 3600 3402 next_ptr = &disk_id_ccontext->Next; 3601 3403 next_off = conn->vals->create_disk_id_size; 3404 + } 3405 + 3406 + if (dh_info.type == DURABLE_REQ || dh_info.type == DURABLE_REQ_V2) { 3407 + struct create_context *durable_ccontext; 3408 + 3409 + durable_ccontext = (struct create_context *)(rsp->Buffer + 3410 + le32_to_cpu(rsp->CreateContextsLength)); 3411 + contxt_cnt++; 3412 + if (dh_info.type == DURABLE_REQ) { 3413 + create_durable_rsp_buf(rsp->Buffer + 3414 + le32_to_cpu(rsp->CreateContextsLength)); 3415 + le32_add_cpu(&rsp->CreateContextsLength, 3416 + conn->vals->create_durable_size); 3417 + iov_len += conn->vals->create_durable_size; 3418 + } else { 3419 + create_durable_v2_rsp_buf(rsp->Buffer + 3420 + le32_to_cpu(rsp->CreateContextsLength), 3421 + fp); 3422 + le32_add_cpu(&rsp->CreateContextsLength, 3423 + conn->vals->create_durable_v2_size); 3424 + iov_len += conn->vals->create_durable_v2_size; 3425 + } 3426 + 3427 + if (next_ptr) 3428 + *next_ptr = cpu_to_le32(next_off); 3429 + next_ptr = &durable_ccontext->Next; 3430 + next_off = conn->vals->create_durable_size; 3602 3431 } 3603 3432 3604 3433 if (posix_ctxt) { ··· 4053 3828 } 4054 3829 4055 3830 ksmbd_kstat.kstat = &kstat; 4056 - if (priv->info_level != FILE_NAMES_INFORMATION) 4057 - ksmbd_vfs_fill_dentry_attrs(priv->work, 4058 - idmap, 4059 - dent, 4060 - &ksmbd_kstat); 3831 + if (priv->info_level != FILE_NAMES_INFORMATION) { 3832 + rc = ksmbd_vfs_fill_dentry_attrs(priv->work, 3833 + idmap, 3834 + dent, 3835 + &ksmbd_kstat); 3836 + if (rc) { 3837 + dput(dent); 3838 + continue; 3839 + } 3840 + } 4061 3841 4062 3842 rc = smb2_populate_readdir_entry(priv->work->conn, 4063 3843 priv->info_level, ··· 4305 4075 } 4306 4076 4307 4077 srch_flag = req->Flags; 4308 - srch_ptr = smb_strndup_from_utf16(req->Buffer, 4078 + srch_ptr = smb_strndup_from_utf16((char *)req + le16_to_cpu(req->FileNameOffset), 4309 4079 le16_to_cpu(req->FileNameLength), 1, 4310 4080 conn->local_nls); 4311 4081 if (IS_ERR(srch_ptr)) { ··· 4565 4335 sizeof(struct smb2_ea_info_req)) 4566 4336 return -EINVAL; 4567 4337 4568 - ea_req = (struct smb2_ea_info_req *)req->Buffer; 4338 + ea_req = (struct smb2_ea_info_req *)((char *)req + 4339 + le16_to_cpu(req->InputBufferOffset)); 4569 4340 } else { 4570 4341 /* need to send all EAs, if no specific EA is requested*/ 4571 4342 if (le32_to_cpu(req->Flags) & SL_RETURN_SINGLE_ENTRY) ··· 4711 4480 struct smb2_file_basic_info *basic_info; 4712 4481 struct kstat stat; 4713 4482 u64 time; 4483 + int ret; 4714 4484 4715 4485 if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) { 4716 4486 pr_err("no right to read the attributes : 0x%x\n", ··· 4719 4487 return -EACCES; 4720 4488 } 4721 4489 4490 + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, 4491 + AT_STATX_SYNC_AS_STAT); 4492 + if (ret) 4493 + return ret; 4494 + 4722 4495 basic_info = (struct smb2_file_basic_info *)rsp->Buffer; 4723 - generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, 4724 - file_inode(fp->filp), &stat); 4725 4496 basic_info->CreationTime = cpu_to_le64(fp->create_time); 4726 4497 time = ksmbd_UnixTimeToNT(stat.atime); 4727 4498 basic_info->LastAccessTime = cpu_to_le64(time); ··· 4739 4504 return 0; 4740 4505 } 4741 4506 4742 - static void get_file_standard_info(struct smb2_query_info_rsp *rsp, 4743 - struct ksmbd_file *fp, void *rsp_org) 4507 + static int get_file_standard_info(struct smb2_query_info_rsp *rsp, 4508 + struct ksmbd_file *fp, void *rsp_org) 4744 4509 { 4745 4510 struct smb2_file_standard_info *sinfo; 4746 4511 unsigned int delete_pending; 4747 - struct inode *inode; 4748 4512 struct kstat stat; 4513 + int ret; 4749 4514 4750 - inode = file_inode(fp->filp); 4751 - generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat); 4515 + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, 4516 + AT_STATX_SYNC_AS_STAT); 4517 + if (ret) 4518 + return ret; 4752 4519 4753 4520 sinfo = (struct smb2_file_standard_info *)rsp->Buffer; 4754 4521 delete_pending = ksmbd_inode_pending_delete(fp); 4755 4522 4756 - sinfo->AllocationSize = cpu_to_le64(inode->i_blocks << 9); 4523 + sinfo->AllocationSize = cpu_to_le64(stat.blocks << 9); 4757 4524 sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); 4758 4525 sinfo->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending); 4759 4526 sinfo->DeletePending = delete_pending; 4760 4527 sinfo->Directory = S_ISDIR(stat.mode) ? 1 : 0; 4761 4528 rsp->OutputBufferLength = 4762 4529 cpu_to_le32(sizeof(struct smb2_file_standard_info)); 4530 + 4531 + return 0; 4763 4532 } 4764 4533 4765 4534 static void get_file_alignment_info(struct smb2_query_info_rsp *rsp, ··· 4785 4546 struct ksmbd_conn *conn = work->conn; 4786 4547 struct smb2_file_all_info *file_info; 4787 4548 unsigned int delete_pending; 4788 - struct inode *inode; 4789 4549 struct kstat stat; 4790 4550 int conv_len; 4791 4551 char *filename; 4792 4552 u64 time; 4553 + int ret; 4793 4554 4794 4555 if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) { 4795 4556 ksmbd_debug(SMB, "no right to read the attributes : 0x%x\n", ··· 4801 4562 if (IS_ERR(filename)) 4802 4563 return PTR_ERR(filename); 4803 4564 4804 - inode = file_inode(fp->filp); 4805 - generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat); 4565 + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, 4566 + AT_STATX_SYNC_AS_STAT); 4567 + if (ret) 4568 + return ret; 4806 4569 4807 4570 ksmbd_debug(SMB, "filename = %s\n", filename); 4808 4571 delete_pending = ksmbd_inode_pending_delete(fp); ··· 4820 4579 file_info->Attributes = fp->f_ci->m_fattr; 4821 4580 file_info->Pad1 = 0; 4822 4581 file_info->AllocationSize = 4823 - cpu_to_le64(inode->i_blocks << 9); 4582 + cpu_to_le64(stat.blocks << 9); 4824 4583 file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); 4825 4584 file_info->NumberOfLinks = 4826 4585 cpu_to_le32(get_nlink(&stat) - delete_pending); ··· 4864 4623 cpu_to_le32(sizeof(struct smb2_file_alt_name_info) + conv_len); 4865 4624 } 4866 4625 4867 - static void get_file_stream_info(struct ksmbd_work *work, 4868 - struct smb2_query_info_rsp *rsp, 4869 - struct ksmbd_file *fp, 4870 - void *rsp_org) 4626 + static int get_file_stream_info(struct ksmbd_work *work, 4627 + struct smb2_query_info_rsp *rsp, 4628 + struct ksmbd_file *fp, 4629 + void *rsp_org) 4871 4630 { 4872 4631 struct ksmbd_conn *conn = work->conn; 4873 4632 struct smb2_file_stream_info *file_info; ··· 4878 4637 int nbytes = 0, streamlen, stream_name_len, next, idx = 0; 4879 4638 int buf_free_len; 4880 4639 struct smb2_query_info_req *req = ksmbd_req_buf_next(work); 4640 + int ret; 4881 4641 4882 - generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, 4883 - file_inode(fp->filp), &stat); 4642 + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, 4643 + AT_STATX_SYNC_AS_STAT); 4644 + if (ret) 4645 + return ret; 4646 + 4884 4647 file_info = (struct smb2_file_stream_info *)rsp->Buffer; 4885 4648 4886 4649 buf_free_len = ··· 4965 4720 kvfree(xattr_list); 4966 4721 4967 4722 rsp->OutputBufferLength = cpu_to_le32(nbytes); 4723 + 4724 + return 0; 4968 4725 } 4969 4726 4970 - static void get_file_internal_info(struct smb2_query_info_rsp *rsp, 4971 - struct ksmbd_file *fp, void *rsp_org) 4727 + static int get_file_internal_info(struct smb2_query_info_rsp *rsp, 4728 + struct ksmbd_file *fp, void *rsp_org) 4972 4729 { 4973 4730 struct smb2_file_internal_info *file_info; 4974 4731 struct kstat stat; 4732 + int ret; 4975 4733 4976 - generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, 4977 - file_inode(fp->filp), &stat); 4734 + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, 4735 + AT_STATX_SYNC_AS_STAT); 4736 + if (ret) 4737 + return ret; 4738 + 4978 4739 file_info = (struct smb2_file_internal_info *)rsp->Buffer; 4979 4740 file_info->IndexNumber = cpu_to_le64(stat.ino); 4980 4741 rsp->OutputBufferLength = 4981 4742 cpu_to_le32(sizeof(struct smb2_file_internal_info)); 4743 + 4744 + return 0; 4982 4745 } 4983 4746 4984 4747 static int get_file_network_open_info(struct smb2_query_info_rsp *rsp, 4985 4748 struct ksmbd_file *fp, void *rsp_org) 4986 4749 { 4987 4750 struct smb2_file_ntwrk_info *file_info; 4988 - struct inode *inode; 4989 4751 struct kstat stat; 4990 4752 u64 time; 4753 + int ret; 4991 4754 4992 4755 if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) { 4993 4756 pr_err("no right to read the attributes : 0x%x\n", ··· 5003 4750 return -EACCES; 5004 4751 } 5005 4752 5006 - file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer; 4753 + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, 4754 + AT_STATX_SYNC_AS_STAT); 4755 + if (ret) 4756 + return ret; 5007 4757 5008 - inode = file_inode(fp->filp); 5009 - generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, inode, &stat); 4758 + file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer; 5010 4759 5011 4760 file_info->CreationTime = cpu_to_le64(fp->create_time); 5012 4761 time = ksmbd_UnixTimeToNT(stat.atime); ··· 5018 4763 time = ksmbd_UnixTimeToNT(stat.ctime); 5019 4764 file_info->ChangeTime = cpu_to_le64(time); 5020 4765 file_info->Attributes = fp->f_ci->m_fattr; 5021 - file_info->AllocationSize = 5022 - cpu_to_le64(inode->i_blocks << 9); 4766 + file_info->AllocationSize = cpu_to_le64(stat.blocks << 9); 5023 4767 file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); 5024 4768 file_info->Reserved = cpu_to_le32(0); 5025 4769 rsp->OutputBufferLength = ··· 5058 4804 cpu_to_le32(sizeof(struct smb2_file_mode_info)); 5059 4805 } 5060 4806 5061 - static void get_file_compression_info(struct smb2_query_info_rsp *rsp, 5062 - struct ksmbd_file *fp, void *rsp_org) 4807 + static int get_file_compression_info(struct smb2_query_info_rsp *rsp, 4808 + struct ksmbd_file *fp, void *rsp_org) 5063 4809 { 5064 4810 struct smb2_file_comp_info *file_info; 5065 4811 struct kstat stat; 4812 + int ret; 5066 4813 5067 - generic_fillattr(file_mnt_idmap(fp->filp), STATX_BASIC_STATS, 5068 - file_inode(fp->filp), &stat); 4814 + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, 4815 + AT_STATX_SYNC_AS_STAT); 4816 + if (ret) 4817 + return ret; 5069 4818 5070 4819 file_info = (struct smb2_file_comp_info *)rsp->Buffer; 5071 4820 file_info->CompressedFileSize = cpu_to_le64(stat.blocks << 9); ··· 5080 4823 5081 4824 rsp->OutputBufferLength = 5082 4825 cpu_to_le32(sizeof(struct smb2_file_comp_info)); 4826 + 4827 + return 0; 5083 4828 } 5084 4829 5085 4830 static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp, ··· 5103 4844 return 0; 5104 4845 } 5105 4846 5106 - static void find_file_posix_info(struct smb2_query_info_rsp *rsp, 4847 + static int find_file_posix_info(struct smb2_query_info_rsp *rsp, 5107 4848 struct ksmbd_file *fp, void *rsp_org) 5108 4849 { 5109 4850 struct smb311_posix_qinfo *file_info; ··· 5111 4852 struct mnt_idmap *idmap = file_mnt_idmap(fp->filp); 5112 4853 vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode); 5113 4854 vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode); 4855 + struct kstat stat; 5114 4856 u64 time; 5115 4857 int out_buf_len = sizeof(struct smb311_posix_qinfo) + 32; 4858 + int ret; 4859 + 4860 + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, 4861 + AT_STATX_SYNC_AS_STAT); 4862 + if (ret) 4863 + return ret; 5116 4864 5117 4865 file_info = (struct smb311_posix_qinfo *)rsp->Buffer; 5118 4866 file_info->CreationTime = cpu_to_le64(fp->create_time); 5119 - time = ksmbd_UnixTimeToNT(inode_get_atime(inode)); 4867 + time = ksmbd_UnixTimeToNT(stat.atime); 5120 4868 file_info->LastAccessTime = cpu_to_le64(time); 5121 - time = ksmbd_UnixTimeToNT(inode_get_mtime(inode)); 4869 + time = ksmbd_UnixTimeToNT(stat.mtime); 5122 4870 file_info->LastWriteTime = cpu_to_le64(time); 5123 - time = ksmbd_UnixTimeToNT(inode_get_ctime(inode)); 4871 + time = ksmbd_UnixTimeToNT(stat.ctime); 5124 4872 file_info->ChangeTime = cpu_to_le64(time); 5125 4873 file_info->DosAttributes = fp->f_ci->m_fattr; 5126 - file_info->Inode = cpu_to_le64(inode->i_ino); 5127 - file_info->EndOfFile = cpu_to_le64(inode->i_size); 5128 - file_info->AllocationSize = cpu_to_le64(inode->i_blocks << 9); 5129 - file_info->HardLinks = cpu_to_le32(inode->i_nlink); 5130 - file_info->Mode = cpu_to_le32(inode->i_mode & 0777); 5131 - file_info->DeviceId = cpu_to_le32(inode->i_rdev); 4874 + file_info->Inode = cpu_to_le64(stat.ino); 4875 + file_info->EndOfFile = cpu_to_le64(stat.size); 4876 + file_info->AllocationSize = cpu_to_le64(stat.blocks << 9); 4877 + file_info->HardLinks = cpu_to_le32(stat.nlink); 4878 + file_info->Mode = cpu_to_le32(stat.mode & 0777); 4879 + file_info->DeviceId = cpu_to_le32(stat.rdev); 5132 4880 5133 4881 /* 5134 4882 * Sids(32) contain two sids(Domain sid(16), UNIX group sid(16)). ··· 5148 4882 SIDUNIX_GROUP, (struct smb_sid *)&file_info->Sids[16]); 5149 4883 5150 4884 rsp->OutputBufferLength = cpu_to_le32(out_buf_len); 4885 + 4886 + return 0; 5151 4887 } 5152 4888 5153 4889 static int smb2_get_info_file(struct ksmbd_work *work, ··· 5198 4930 break; 5199 4931 5200 4932 case FILE_STANDARD_INFORMATION: 5201 - get_file_standard_info(rsp, fp, work->response_buf); 4933 + rc = get_file_standard_info(rsp, fp, work->response_buf); 5202 4934 break; 5203 4935 5204 4936 case FILE_ALIGNMENT_INFORMATION: ··· 5214 4946 break; 5215 4947 5216 4948 case FILE_STREAM_INFORMATION: 5217 - get_file_stream_info(work, rsp, fp, work->response_buf); 4949 + rc = get_file_stream_info(work, rsp, fp, work->response_buf); 5218 4950 break; 5219 4951 5220 4952 case FILE_INTERNAL_INFORMATION: 5221 - get_file_internal_info(rsp, fp, work->response_buf); 4953 + rc = get_file_internal_info(rsp, fp, work->response_buf); 5222 4954 break; 5223 4955 5224 4956 case FILE_NETWORK_OPEN_INFORMATION: ··· 5242 4974 break; 5243 4975 5244 4976 case FILE_COMPRESSION_INFORMATION: 5245 - get_file_compression_info(rsp, fp, work->response_buf); 4977 + rc = get_file_compression_info(rsp, fp, work->response_buf); 5246 4978 break; 5247 4979 5248 4980 case FILE_ATTRIBUTE_TAG_INFORMATION: ··· 5253 4985 pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n"); 5254 4986 rc = -EOPNOTSUPP; 5255 4987 } else { 5256 - find_file_posix_info(rsp, fp, work->response_buf); 4988 + rc = find_file_posix_info(rsp, fp, work->response_buf); 5257 4989 } 5258 4990 break; 5259 4991 default: ··· 5666 5398 struct smb2_close_rsp *rsp; 5667 5399 struct ksmbd_conn *conn = work->conn; 5668 5400 struct ksmbd_file *fp; 5669 - struct inode *inode; 5670 5401 u64 time; 5671 5402 int err = 0; 5672 5403 ··· 5720 5453 rsp->Reserved = 0; 5721 5454 5722 5455 if (req->Flags == SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB) { 5456 + struct kstat stat; 5457 + int ret; 5458 + 5723 5459 fp = ksmbd_lookup_fd_fast(work, volatile_id); 5724 5460 if (!fp) { 5725 5461 err = -ENOENT; 5726 5462 goto out; 5727 5463 } 5728 5464 5729 - inode = file_inode(fp->filp); 5465 + ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, 5466 + AT_STATX_SYNC_AS_STAT); 5467 + if (ret) { 5468 + ksmbd_fd_put(work, fp); 5469 + goto out; 5470 + } 5471 + 5730 5472 rsp->Flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; 5731 - rsp->AllocationSize = S_ISDIR(inode->i_mode) ? 0 : 5732 - cpu_to_le64(inode->i_blocks << 9); 5733 - rsp->EndOfFile = cpu_to_le64(inode->i_size); 5473 + rsp->AllocationSize = S_ISDIR(stat.mode) ? 0 : 5474 + cpu_to_le64(stat.blocks << 9); 5475 + rsp->EndOfFile = cpu_to_le64(stat.size); 5734 5476 rsp->Attributes = fp->f_ci->m_fattr; 5735 5477 rsp->CreationTime = cpu_to_le64(fp->create_time); 5736 - time = ksmbd_UnixTimeToNT(inode_get_atime(inode)); 5478 + time = ksmbd_UnixTimeToNT(stat.atime); 5737 5479 rsp->LastAccessTime = cpu_to_le64(time); 5738 - time = ksmbd_UnixTimeToNT(inode_get_mtime(inode)); 5480 + time = ksmbd_UnixTimeToNT(stat.mtime); 5739 5481 rsp->LastWriteTime = cpu_to_le64(time); 5740 - time = ksmbd_UnixTimeToNT(inode_get_ctime(inode)); 5482 + time = ksmbd_UnixTimeToNT(stat.ctime); 5741 5483 rsp->ChangeTime = cpu_to_le64(time); 5742 5484 ksmbd_fd_put(work, fp); 5743 5485 } else { ··· 6035 5759 6036 5760 loff_t alloc_blks; 6037 5761 struct inode *inode; 5762 + struct kstat stat; 6038 5763 int rc; 6039 5764 6040 5765 if (!(fp->daccess & FILE_WRITE_DATA_LE)) 6041 5766 return -EACCES; 6042 5767 5768 + rc = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, 5769 + AT_STATX_SYNC_AS_STAT); 5770 + if (rc) 5771 + return rc; 5772 + 6043 5773 alloc_blks = (le64_to_cpu(file_alloc_info->AllocationSize) + 511) >> 9; 6044 5774 inode = file_inode(fp->filp); 6045 5775 6046 - if (alloc_blks > inode->i_blocks) { 5776 + if (alloc_blks > stat.blocks) { 6047 5777 smb_break_all_levII_oplock(work, fp, 1); 6048 5778 rc = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0, 6049 5779 alloc_blks * 512); ··· 6057 5775 pr_err("vfs_fallocate is failed : %d\n", rc); 6058 5776 return rc; 6059 5777 } 6060 - } else if (alloc_blks < inode->i_blocks) { 5778 + } else if (alloc_blks < stat.blocks) { 6061 5779 loff_t size; 6062 5780 6063 5781 /* ··· 6212 5930 struct ksmbd_share_config *share) 6213 5931 { 6214 5932 unsigned int buf_len = le32_to_cpu(req->BufferLength); 5933 + char *buffer = (char *)req + le16_to_cpu(req->BufferOffset); 6215 5934 6216 5935 switch (req->FileInfoClass) { 6217 5936 case FILE_BASIC_INFORMATION: ··· 6220 5937 if (buf_len < sizeof(struct smb2_file_basic_info)) 6221 5938 return -EINVAL; 6222 5939 6223 - return set_file_basic_info(fp, (struct smb2_file_basic_info *)req->Buffer, share); 5940 + return set_file_basic_info(fp, (struct smb2_file_basic_info *)buffer, share); 6224 5941 } 6225 5942 case FILE_ALLOCATION_INFORMATION: 6226 5943 { ··· 6228 5945 return -EINVAL; 6229 5946 6230 5947 return set_file_allocation_info(work, fp, 6231 - (struct smb2_file_alloc_info *)req->Buffer); 5948 + (struct smb2_file_alloc_info *)buffer); 6232 5949 } 6233 5950 case FILE_END_OF_FILE_INFORMATION: 6234 5951 { ··· 6236 5953 return -EINVAL; 6237 5954 6238 5955 return set_end_of_file_info(work, fp, 6239 - (struct smb2_file_eof_info *)req->Buffer); 5956 + (struct smb2_file_eof_info *)buffer); 6240 5957 } 6241 5958 case FILE_RENAME_INFORMATION: 6242 5959 { ··· 6244 5961 return -EINVAL; 6245 5962 6246 5963 return set_rename_info(work, fp, 6247 - (struct smb2_file_rename_info *)req->Buffer, 5964 + (struct smb2_file_rename_info *)buffer, 6248 5965 buf_len); 6249 5966 } 6250 5967 case FILE_LINK_INFORMATION: ··· 6253 5970 return -EINVAL; 6254 5971 6255 5972 return smb2_create_link(work, work->tcon->share_conf, 6256 - (struct smb2_file_link_info *)req->Buffer, 5973 + (struct smb2_file_link_info *)buffer, 6257 5974 buf_len, fp->filp, 6258 5975 work->conn->local_nls); 6259 5976 } ··· 6263 5980 return -EINVAL; 6264 5981 6265 5982 return set_file_disposition_info(fp, 6266 - (struct smb2_file_disposition_info *)req->Buffer); 5983 + (struct smb2_file_disposition_info *)buffer); 6267 5984 } 6268 5985 case FILE_FULL_EA_INFORMATION: 6269 5986 { ··· 6276 5993 if (buf_len < sizeof(struct smb2_ea_info)) 6277 5994 return -EINVAL; 6278 5995 6279 - return smb2_set_ea((struct smb2_ea_info *)req->Buffer, 5996 + return smb2_set_ea((struct smb2_ea_info *)buffer, 6280 5997 buf_len, &fp->filp->f_path, true); 6281 5998 } 6282 5999 case FILE_POSITION_INFORMATION: ··· 6284 6001 if (buf_len < sizeof(struct smb2_file_pos_info)) 6285 6002 return -EINVAL; 6286 6003 6287 - return set_file_position_info(fp, (struct smb2_file_pos_info *)req->Buffer); 6004 + return set_file_position_info(fp, (struct smb2_file_pos_info *)buffer); 6288 6005 } 6289 6006 case FILE_MODE_INFORMATION: 6290 6007 { 6291 6008 if (buf_len < sizeof(struct smb2_file_mode_info)) 6292 6009 return -EINVAL; 6293 6010 6294 - return set_file_mode_info(fp, (struct smb2_file_mode_info *)req->Buffer); 6011 + return set_file_mode_info(fp, (struct smb2_file_mode_info *)buffer); 6295 6012 } 6296 6013 } 6297 6014 ··· 6372 6089 } 6373 6090 rc = smb2_set_info_sec(fp, 6374 6091 le32_to_cpu(req->AdditionalInformation), 6375 - req->Buffer, 6092 + (char *)req + le16_to_cpu(req->BufferOffset), 6376 6093 le32_to_cpu(req->BufferLength)); 6377 6094 ksmbd_revert_fsids(work); 6378 6095 break; ··· 7818 7535 struct smb2_ioctl_rsp *rsp) 7819 7536 { 7820 7537 struct ksmbd_rpc_command *rpc_resp; 7821 - char *data_buf = (char *)&req->Buffer[0]; 7538 + char *data_buf = (char *)req + le32_to_cpu(req->InputOffset); 7822 7539 int nbytes = 0; 7823 7540 7824 7541 rpc_resp = ksmbd_rpc_ioctl(work->sess, id, data_buf, ··· 7931 7648 u64 id = KSMBD_NO_FID; 7932 7649 struct ksmbd_conn *conn = work->conn; 7933 7650 int ret = 0; 7651 + char *buffer; 7934 7652 7935 7653 if (work->next_smb2_rcv_hdr_off) { 7936 7654 req = ksmbd_req_buf_next(work); ··· 7953 7669 rsp->hdr.Status = STATUS_NOT_SUPPORTED; 7954 7670 goto out; 7955 7671 } 7672 + 7673 + buffer = (char *)req + le32_to_cpu(req->InputOffset); 7956 7674 7957 7675 cnt_code = le32_to_cpu(req->CtlCode); 7958 7676 ret = smb2_calc_max_out_buf_len(work, 48, ··· 8013 7727 } 8014 7728 8015 7729 ret = fsctl_validate_negotiate_info(conn, 8016 - (struct validate_negotiate_info_req *)&req->Buffer[0], 7730 + (struct validate_negotiate_info_req *)buffer, 8017 7731 (struct validate_negotiate_info_rsp *)&rsp->Buffer[0], 8018 7732 in_buf_len); 8019 7733 if (ret < 0) ··· 8066 7780 rsp->VolatileFileId = req->VolatileFileId; 8067 7781 rsp->PersistentFileId = req->PersistentFileId; 8068 7782 fsctl_copychunk(work, 8069 - (struct copychunk_ioctl_req *)&req->Buffer[0], 7783 + (struct copychunk_ioctl_req *)buffer, 8070 7784 le32_to_cpu(req->CtlCode), 8071 7785 le32_to_cpu(req->InputCount), 8072 7786 req->VolatileFileId, ··· 8079 7793 goto out; 8080 7794 } 8081 7795 8082 - ret = fsctl_set_sparse(work, id, 8083 - (struct file_sparse *)&req->Buffer[0]); 7796 + ret = fsctl_set_sparse(work, id, (struct file_sparse *)buffer); 8084 7797 if (ret < 0) 8085 7798 goto out; 8086 7799 break; ··· 8102 7817 } 8103 7818 8104 7819 zero_data = 8105 - (struct file_zero_data_information *)&req->Buffer[0]; 7820 + (struct file_zero_data_information *)buffer; 8106 7821 8107 7822 off = le64_to_cpu(zero_data->FileOffset); 8108 7823 bfz = le64_to_cpu(zero_data->BeyondFinalZero); ··· 8133 7848 } 8134 7849 8135 7850 ret = fsctl_query_allocated_ranges(work, id, 8136 - (struct file_allocated_range_buffer *)&req->Buffer[0], 7851 + (struct file_allocated_range_buffer *)buffer, 8137 7852 (struct file_allocated_range_buffer *)&rsp->Buffer[0], 8138 7853 out_buf_len / 8139 7854 sizeof(struct file_allocated_range_buffer), &nbytes); ··· 8177 7892 goto out; 8178 7893 } 8179 7894 8180 - dup_ext = (struct duplicate_extents_to_file *)&req->Buffer[0]; 7895 + dup_ext = (struct duplicate_extents_to_file *)buffer; 8181 7896 8182 7897 fp_in = ksmbd_lookup_fd_slow(work, dup_ext->VolatileFileHandle, 8183 7898 dup_ext->PersistentFileHandle);
+15
fs/smb/server/smb2pdu.h
··· 72 72 __u8 CreateGuid[16]; 73 73 } __packed; 74 74 75 + struct create_durable_reconn_req { 76 + struct create_context ccontext; 77 + __u8 Name[8]; 78 + union { 79 + __u8 Reserved[16]; 80 + struct { 81 + __u64 PersistentFileId; 82 + __u64 VolatileFileId; 83 + } Fid; 84 + } Data; 85 + } __packed; 86 + 75 87 struct create_durable_reconn_v2_req { 76 88 struct create_context ccontext; 77 89 __u8 Name[8]; ··· 110 98 } Data; 111 99 } __packed; 112 100 101 + /* See MS-SMB2 2.2.13.2.11 */ 102 + /* Flags */ 103 + #define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002 113 104 struct create_durable_v2_rsp { 114 105 struct create_context ccontext; 115 106 __u8 Name[8];
+7 -4
fs/smb/server/smb_common.c
··· 457 457 } 458 458 459 459 ksmbd_kstat.kstat = &kstat; 460 - ksmbd_vfs_fill_dentry_attrs(work, 461 - idmap, 462 - dentry, 463 - &ksmbd_kstat); 460 + rc = ksmbd_vfs_fill_dentry_attrs(work, 461 + idmap, 462 + dentry, 463 + &ksmbd_kstat); 464 + if (rc) 465 + break; 466 + 464 467 rc = fn(conn, info_level, d_info, &ksmbd_kstat); 465 468 if (rc) 466 469 break;
+10 -2
fs/smb/server/vfs.c
··· 1682 1682 struct dentry *dentry, 1683 1683 struct ksmbd_kstat *ksmbd_kstat) 1684 1684 { 1685 + struct ksmbd_share_config *share_conf = work->tcon->share_conf; 1685 1686 u64 time; 1686 1687 int rc; 1688 + struct path path = { 1689 + .mnt = share_conf->vfs_path.mnt, 1690 + .dentry = dentry, 1691 + }; 1687 1692 1688 - generic_fillattr(idmap, STATX_BASIC_STATS, d_inode(dentry), 1689 - ksmbd_kstat->kstat); 1693 + rc = vfs_getattr(&path, ksmbd_kstat->kstat, 1694 + STATX_BASIC_STATS | STATX_BTIME, 1695 + AT_STATX_SYNC_AS_STAT); 1696 + if (rc) 1697 + return rc; 1690 1698 1691 1699 time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->ctime); 1692 1700 ksmbd_kstat->create_time = time;
+134 -3
fs/smb/server/vfs_cache.c
··· 305 305 306 306 fd_limit_close(); 307 307 __ksmbd_remove_durable_fd(fp); 308 - __ksmbd_remove_fd(ft, fp); 308 + if (ft) 309 + __ksmbd_remove_fd(ft, fp); 309 310 310 311 close_id_del_oplock(fp); 311 312 filp = fp->filp; ··· 466 465 return fp; 467 466 } 468 467 469 - struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id) 468 + struct ksmbd_file *ksmbd_lookup_global_fd(unsigned long long id) 470 469 { 471 470 return __ksmbd_lookup_fd(&global_ft, id); 471 + } 472 + 473 + struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id) 474 + { 475 + struct ksmbd_file *fp; 476 + 477 + fp = __ksmbd_lookup_fd(&global_ft, id); 478 + if (fp && fp->conn) { 479 + ksmbd_put_durable_fd(fp); 480 + fp = NULL; 481 + } 482 + 483 + return fp; 484 + } 485 + 486 + void ksmbd_put_durable_fd(struct ksmbd_file *fp) 487 + { 488 + if (!atomic_dec_and_test(&fp->refcount)) 489 + return; 490 + 491 + __ksmbd_close_fd(NULL, fp); 472 492 } 473 493 474 494 struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid) ··· 661 639 return num; 662 640 } 663 641 642 + static inline bool is_reconnectable(struct ksmbd_file *fp) 643 + { 644 + struct oplock_info *opinfo = opinfo_get(fp); 645 + bool reconn = false; 646 + 647 + if (!opinfo) 648 + return false; 649 + 650 + if (opinfo->op_state != OPLOCK_STATE_NONE) { 651 + opinfo_put(opinfo); 652 + return false; 653 + } 654 + 655 + if (fp->is_resilient || fp->is_persistent) 656 + reconn = true; 657 + else if (fp->is_durable && opinfo->is_lease && 658 + opinfo->o_lease->state & SMB2_LEASE_HANDLE_CACHING_LE) 659 + reconn = true; 660 + 661 + else if (fp->is_durable && opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) 662 + reconn = true; 663 + 664 + opinfo_put(opinfo); 665 + return reconn; 666 + } 667 + 664 668 static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon, 665 669 struct ksmbd_file *fp) 666 670 { ··· 696 648 static bool session_fd_check(struct ksmbd_tree_connect *tcon, 697 649 struct ksmbd_file *fp) 698 650 { 699 - return false; 651 + struct ksmbd_inode *ci; 652 + struct oplock_info *op; 653 + struct ksmbd_conn *conn; 654 + 655 + if (!is_reconnectable(fp)) 656 + return false; 657 + 658 + conn = fp->conn; 659 + ci = fp->f_ci; 660 + write_lock(&ci->m_lock); 661 + list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) { 662 + if (op->conn != conn) 663 + continue; 664 + op->conn = NULL; 665 + } 666 + write_unlock(&ci->m_lock); 667 + 668 + fp->conn = NULL; 669 + fp->tcon = NULL; 670 + fp->volatile_id = KSMBD_NO_FID; 671 + 672 + return true; 700 673 } 701 674 702 675 void ksmbd_close_tree_conn_fds(struct ksmbd_work *work) ··· 754 685 } 755 686 756 687 ksmbd_destroy_file_table(&global_ft); 688 + } 689 + 690 + int ksmbd_validate_name_reconnect(struct ksmbd_share_config *share, 691 + struct ksmbd_file *fp, char *name) 692 + { 693 + char *pathname, *ab_pathname; 694 + int ret = 0; 695 + 696 + pathname = kmalloc(PATH_MAX, GFP_KERNEL); 697 + if (!pathname) 698 + return -EACCES; 699 + 700 + ab_pathname = d_path(&fp->filp->f_path, pathname, PATH_MAX); 701 + if (IS_ERR(ab_pathname)) { 702 + kfree(pathname); 703 + return -EACCES; 704 + } 705 + 706 + if (name && strcmp(&ab_pathname[share->path_sz + 1], name)) { 707 + ksmbd_debug(SMB, "invalid name reconnect %s\n", name); 708 + ret = -EINVAL; 709 + } 710 + 711 + kfree(pathname); 712 + 713 + return ret; 714 + } 715 + 716 + int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp) 717 + { 718 + struct ksmbd_inode *ci; 719 + struct oplock_info *op; 720 + 721 + if (!fp->is_durable || fp->conn || fp->tcon) { 722 + pr_err("Invalid durable fd [%p:%p]\n", fp->conn, fp->tcon); 723 + return -EBADF; 724 + } 725 + 726 + if (has_file_id(fp->volatile_id)) { 727 + pr_err("Still in use durable fd: %llu\n", fp->volatile_id); 728 + return -EBADF; 729 + } 730 + 731 + fp->conn = work->conn; 732 + fp->tcon = work->tcon; 733 + 734 + ci = fp->f_ci; 735 + write_lock(&ci->m_lock); 736 + list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) { 737 + if (op->conn) 738 + continue; 739 + op->conn = fp->conn; 740 + } 741 + write_unlock(&ci->m_lock); 742 + 743 + __open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID); 744 + if (!has_file_id(fp->volatile_id)) { 745 + fp->conn = NULL; 746 + fp->tcon = NULL; 747 + return -EBADF; 748 + } 749 + return 0; 757 750 } 758 751 759 752 int ksmbd_init_file_table(struct ksmbd_file_table *ft)
+9
fs/smb/server/vfs_cache.h
··· 14 14 #include <linux/workqueue.h> 15 15 16 16 #include "vfs.h" 17 + #include "mgmt/share_config.h" 17 18 18 19 /* Windows style file permissions for extended response */ 19 20 #define FILE_GENERIC_ALL 0x1F01FF ··· 107 106 int dot_dotdot[2]; 108 107 unsigned int f_state; 109 108 bool reserve_lease_break; 109 + bool is_durable; 110 + bool is_persistent; 111 + bool is_resilient; 110 112 }; 111 113 112 114 static inline void set_ctx_actor(struct dir_context *ctx, ··· 145 141 void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp); 146 142 struct ksmbd_inode *ksmbd_inode_lookup_lock(struct dentry *d); 147 143 void ksmbd_inode_put(struct ksmbd_inode *ci); 144 + struct ksmbd_file *ksmbd_lookup_global_fd(unsigned long long id); 148 145 struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id); 146 + void ksmbd_put_durable_fd(struct ksmbd_file *fp); 149 147 struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid); 150 148 struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry); 151 149 unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp); ··· 179 173 void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp); 180 174 void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp, 181 175 int file_info); 176 + int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp); 177 + int ksmbd_validate_name_reconnect(struct ksmbd_share_config *share, 178 + struct ksmbd_file *fp, char *name); 182 179 int ksmbd_init_file_cache(void); 183 180 void ksmbd_exit_file_cache(void); 184 181 #endif /* __VFS_CACHE_H__ */