diff --git a/fs/smb/client/smb1pdu.h b/fs/smb/client/smb1pdu.h index 97f7e1244a8b..7584e94d9b2b 100644 --- a/fs/smb/client/smb1pdu.h +++ b/fs/smb/client/smb1pdu.h @@ -2061,15 +2061,6 @@ typedef struct { __le32 EASize; } __packed FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */ -typedef struct { - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le32 Attributes; - __u32 Pad; -} __packed FILE_BASIC_INFO; /* size info, level 0x101 */ - struct file_allocation_info { __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ } __packed; /* size used on disk, for level 0x103 for set, 0x105 for query */ diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 5188218c25be..59d7418cc480 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -6147,8 +6147,8 @@ replay_again: max_len = sizeof(struct smb3_fs_ss_info); min_len = sizeof(struct smb3_fs_ss_info); } else if (level == FS_VOLUME_INFORMATION) { - max_len = sizeof(struct smb3_fs_vol_info) + MAX_VOL_LABEL_LEN; - min_len = sizeof(struct smb3_fs_vol_info); + max_len = sizeof(struct filesystem_vol_info) + MAX_VOL_LABEL_LEN; + min_len = sizeof(struct filesystem_vol_info); } else { cifs_dbg(FYI, "Invalid qfsinfo level %d\n", level); return -EINVAL; @@ -6203,9 +6203,9 @@ replay_again: tcon->perf_sector_size = le32_to_cpu(ss_info->PhysicalBytesPerSectorForPerf); } else if (level == FS_VOLUME_INFORMATION) { - struct smb3_fs_vol_info *vol_info = (struct smb3_fs_vol_info *) + struct filesystem_vol_info *vol_info = (struct filesystem_vol_info *) (offset + (char *)rsp); - tcon->vol_serial_number = vol_info->VolumeSerialNumber; + tcon->vol_serial_number = le32_to_cpu(vol_info->VolumeSerialNumber); tcon->vol_create_time = vol_info->VolumeCreationTime; } diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index c79304012b08..461658105013 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -1551,17 +1551,25 @@ static int smbd_post_send_iter(struct smbdirect_socket *sc, rc = smbd_post_send(sc, batch, request); if (!rc) { + /* + * From here request is moved to batch + * and we should not free it explicitly. + */ + if (batch != &_batch) return 0; rc = smbd_send_batch_flush(sc, batch, true); if (!rc) return 0; + + goto err_flush; } err_dma: smbd_free_send_io(request); +err_flush: err_alloc: atomic_inc(&sc->send_io.credits.count); wake_up(&sc->send_io.credits.wait_queue); diff --git a/fs/smb/common/fscc.h b/fs/smb/common/fscc.h index 0123f34db1e8..b4ccddca9256 100644 --- a/fs/smb/common/fscc.h +++ b/fs/smb/common/fscc.h @@ -12,6 +12,220 @@ #ifndef _COMMON_SMB_FSCC_H #define _COMMON_SMB_FSCC_H +/* Reparse structures - see MS-FSCC 2.1.2 */ + +/* struct fsctl_reparse_info_req is empty, only response structs (see below) */ +struct reparse_data_buffer { + __le32 ReparseTag; + __le16 ReparseDataLength; + __u16 Reserved; + __u8 DataBuffer[]; /* Variable Length */ +} __packed; + +struct reparse_guid_data_buffer { + __le32 ReparseTag; + __le16 ReparseDataLength; + __u16 Reserved; + __u8 ReparseGuid[16]; + __u8 DataBuffer[]; /* Variable Length */ +} __packed; + +struct reparse_mount_point_data_buffer { + __le32 ReparseTag; + __le16 ReparseDataLength; + __u16 Reserved; + __le16 SubstituteNameOffset; + __le16 SubstituteNameLength; + __le16 PrintNameOffset; + __le16 PrintNameLength; + __u8 PathBuffer[]; /* Variable Length */ +} __packed; + +#define SYMLINK_FLAG_RELATIVE 0x00000001 + +struct reparse_symlink_data_buffer { + __le32 ReparseTag; + __le16 ReparseDataLength; + __u16 Reserved; + __le16 SubstituteNameOffset; + __le16 SubstituteNameLength; + __le16 PrintNameOffset; + __le16 PrintNameLength; + __le32 Flags; + __u8 PathBuffer[]; /* Variable Length */ +} __packed; + +/* For IO_REPARSE_TAG_NFS - see MS-FSCC 2.1.2.6 */ +#define NFS_SPECFILE_LNK 0x00000000014B4E4C +#define NFS_SPECFILE_CHR 0x0000000000524843 +#define NFS_SPECFILE_BLK 0x00000000004B4C42 +#define NFS_SPECFILE_FIFO 0x000000004F464946 +#define NFS_SPECFILE_SOCK 0x000000004B434F53 +struct reparse_nfs_data_buffer { + __le32 ReparseTag; + __le16 ReparseDataLength; + __u16 Reserved; + __le64 InodeType; /* NFS_SPECFILE_* */ + __u8 DataBuffer[]; +} __packed; + +/* For IO_REPARSE_TAG_LX_SYMLINK - see MS-FSCC 2.1.2.7 */ +struct reparse_wsl_symlink_data_buffer { + __le32 ReparseTag; + __le16 ReparseDataLength; + __u16 Reserved; + __le32 Version; /* Always 2 */ + __u8 Target[]; /* Variable Length UTF-8 string without nul-term */ +} __packed; + +/* See MS-FSCC 2.3.7 */ +struct duplicate_extents_to_file { + __u64 PersistentFileHandle; /* source file handle, opaque endianness */ + __u64 VolatileFileHandle; + __le64 SourceFileOffset; + __le64 TargetFileOffset; + __le64 ByteCount; /* Bytes to be copied */ +} __packed; + +/* See MS-FSCC 2.3.9 */ +#define DUPLICATE_EXTENTS_DATA_EX_SOURCE_ATOMIC 0x00000001 +struct duplicate_extents_to_file_ex { + __le64 StructureSize; /* MUST be set to 0x30 */ + __u64 PersistentFileHandle; /* source file handle, opaque endianness */ + __u64 VolatileFileHandle; + __le64 SourceFileOffset; + __le64 TargetFileOffset; + __le64 ByteCount; /* Bytes to be copied */ + __le32 Flags; + __le32 Reserved; +} __packed; + +/* See MS-FSCC 2.3.20 */ +struct fsctl_get_integrity_information_rsp { + __le16 ChecksumAlgorithm; + __le16 Reserved; + __le32 Flags; + __le32 ChecksumChunkSizeInBytes; + __le32 ClusterSizeInBytes; +} __packed; + +/* See MS-FSCC 2.3.52 */ +struct file_allocated_range_buffer { + __le64 file_offset; + __le64 length; +} __packed; + +/* See MS-FSCC 2.3.55 */ +struct fsctl_query_file_regions_req { + __le64 FileOffset; + __le64 Length; + __le32 DesiredUsage; + __le32 Reserved; +} __packed; + +/* DesiredUsage flags see MS-FSCC 2.3.56.1 */ +#define FILE_USAGE_INVALID_RANGE 0x00000000 +#define FILE_USAGE_VALID_CACHED_DATA 0x00000001 +#define FILE_USAGE_NONCACHED_DATA 0x00000002 +struct file_region_info { + __le64 FileOffset; + __le64 Length; + __le32 DesiredUsage; + __le32 Reserved; +} __packed; + +/* See MS-FSCC 2.3.56 */ +struct fsctl_query_file_region_rsp { + __le32 Flags; + __le32 TotalRegionEntryCount; + __le32 RegionEntryCount; + __u32 Reserved; + struct file_region_info Regions[]; +} __packed; + +/* See MS-FSCC 2.3.58 */ +struct fsctl_query_on_disk_vol_info_rsp { + __le64 DirectoryCount; + __le64 FileCount; + __le16 FsFormatMajVersion; + __le16 FsFormatMinVersion; + __u8 FsFormatName[24]; + __le64 FormatTime; + __le64 LastUpdateTime; + __u8 CopyrightInfo[68]; + __u8 AbstractInfo[68]; + __u8 FormatImplInfo[68]; + __u8 LastModifyImplInfo[68]; +} __packed; + +/* See MS-FSCC 2.3.73 */ +struct fsctl_set_integrity_information_req { + __le16 ChecksumAlgorithm; + __le16 Reserved; + __le32 Flags; +} __packed; + +/* See MS-FSCC 2.3.75 */ +struct fsctl_set_integrity_info_ex_req { + __u8 EnableIntegrity; + __u8 KeepState; + __u16 Reserved; + __le32 Flags; + __u8 Version; + __u8 Reserved2[7]; +} __packed; + +/* + * this goes in the ioctl buffer when doing FSCTL_SET_ZERO_DATA + * See MS-FSCC 2.3.85 + */ +struct file_zero_data_information { + __le64 FileOffset; + __le64 BeyondFinalZero; +} __packed; + +/* + * This level 18, although with struct with same name is different from cifs + * level 0x107. Level 0x107 has an extra u64 between AccessFlags and + * CurrentByteOffset. + * See MS-FSCC 2.4.2 + */ +struct smb2_file_all_info { /* data block encoding of response to level 18 */ + __le64 CreationTime; /* Beginning of FILE_BASIC_INFO equivalent */ + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le32 Attributes; + __u32 Pad1; /* End of FILE_BASIC_INFO_INFO equivalent */ + __le64 AllocationSize; /* Beginning of FILE_STANDARD_INFO equivalent */ + __le64 EndOfFile; /* size ie offset to first free byte in file */ + __le32 NumberOfLinks; /* hard links */ + __u8 DeletePending; + __u8 Directory; + __u16 Pad2; /* End of FILE_STANDARD_INFO equivalent */ + __le64 IndexNumber; + __le32 EASize; + __le32 AccessFlags; + __le64 CurrentByteOffset; + __le32 Mode; + __le32 AlignmentRequirement; + __le32 FileNameLength; + union { + char __pad; /* Legacy structure padding */ + DECLARE_FLEX_ARRAY(char, FileName); + }; +} __packed; /* level 18 Query */ + +/* See MS-FSCC 2.4.7 */ +typedef struct file_basic_info { /* data block encoding of response to level 18 */ + __le64 CreationTime; + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le32 Attributes; + __u32 Pad; +} __packed FILE_BASIC_INFO; /* size info, level 0x101 */ + /* See MS-FSCC 2.4.8 */ typedef struct { __le32 NextEntryOffset; @@ -46,6 +260,11 @@ typedef struct { char FileName[]; } __packed FILE_DIRECTORY_INFO; /* level 0x101 FF resp data */ +/* See MS-FSCC 2.4.13 */ +struct smb2_file_eof_info { /* encoding of request for level 10 */ + __le64 EndOfFile; /* new end of file value */ +} __packed; /* level 20 Set */ + /* See MS-FSCC 2.4.14 */ typedef struct { __le32 NextEntryOffset; @@ -80,6 +299,26 @@ typedef struct { char FileName[]; } __packed FILE_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */ +/* See MS-FSCC 2.4.27 */ +struct smb2_file_internal_info { + __le64 IndexNumber; +} __packed; /* level 6 Query */ + +/* See MS-FSCC 2.4.28.2 */ +struct smb2_file_link_info { /* encoding of request for level 11 */ + /* New members MUST be added within the struct_group() macro below. */ + __struct_group(smb2_file_link_info_hdr, __hdr, __packed, + __u8 ReplaceIfExists; /* 1 = replace existing link with new */ + /* 0 = fail if link already exists */ + __u8 Reserved[7]; + __u64 RootDirectory; /* MBZ for network operations (why says spec?) */ + __le32 FileNameLength; + ); + char FileName[]; /* Name to be assigned to new link */ +} __packed; /* level 11 Set */ +static_assert(offsetof(struct smb2_file_link_info, FileName) == sizeof(struct smb2_file_link_info_hdr), + "struct member likely outside of __struct_group()"); + /* See MS-FSCC 2.4.34 */ struct smb2_file_network_open_info { struct_group_attr(network_open_info, __packed, @@ -94,6 +333,37 @@ struct smb2_file_network_open_info { __le32 Reserved; } __packed; /* level 34 Query also similar returned in close rsp and open rsp */ +/* See MS-FSCC 2.4.42.2 */ +struct smb2_file_rename_info { /* encoding of request for level 10 */ + /* New members MUST be added within the struct_group() macro below. */ + __struct_group(smb2_file_rename_info_hdr, __hdr, __packed, + __u8 ReplaceIfExists; /* 1 = replace existing target with new */ + /* 0 = fail if target already exists */ + __u8 Reserved[7]; + __u64 RootDirectory; /* MBZ for network operations (why says spec?) */ + __le32 FileNameLength; + ); + char FileName[]; /* New name to be assigned */ + /* padding - overall struct size must be >= 24 so filename + pad >= 6 */ +} __packed; /* level 10 Set */ +static_assert(offsetof(struct smb2_file_rename_info, FileName) == sizeof(struct smb2_file_rename_info_hdr), + "struct member likely outside of __struct_group()"); + +/* File System Information Classes */ +/* See MS-FSCC 2.5 */ +#define FS_VOLUME_INFORMATION 1 /* Query */ +#define FS_LABEL_INFORMATION 2 /* Set */ +#define FS_SIZE_INFORMATION 3 /* Query */ +#define FS_DEVICE_INFORMATION 4 /* Query */ +#define FS_ATTRIBUTE_INFORMATION 5 /* Query */ +#define FS_CONTROL_INFORMATION 6 /* Query, Set */ +#define FS_FULL_SIZE_INFORMATION 7 /* Query */ +#define FS_OBJECT_ID_INFORMATION 8 /* Query, Set */ +#define FS_DRIVER_PATH_INFORMATION 9 /* Query */ +#define FS_SECTOR_SIZE_INFORMATION 11 /* SMB3 or later. Query */ +/* See POSIX Extensions to MS-FSCC 2.3.1.1 */ +#define FS_POSIX_INFORMATION 100 /* SMB3.1.1 POSIX. Query */ + /* See MS-FSCC 2.5.1 */ #define MAX_FS_NAME_LEN 52 typedef struct { @@ -130,6 +400,45 @@ typedef struct { #define FILE_CASE_PRESERVED_NAMES 0x00000002 #define FILE_CASE_SENSITIVE_SEARCH 0x00000001 +/* + * File System Control Information + * See MS-FSCC 2.5.2 + */ +struct smb2_fs_control_info { + __le64 FreeSpaceStartFiltering; + __le64 FreeSpaceThreshold; + __le64 FreeSpaceStopFiltering; + __le64 DefaultQuotaThreshold; + __le64 DefaultQuotaLimit; + __le32 FileSystemControlFlags; + __le32 Padding; +} __packed; + +/* See MS-FSCC 2.5.4 */ +struct smb2_fs_full_size_info { + __le64 TotalAllocationUnits; + __le64 CallerAvailableAllocationUnits; + __le64 ActualAvailableAllocationUnits; + __le32 SectorsPerAllocationUnit; + __le32 BytesPerSector; +} __packed; + +/* See MS-FSCC 2.5.7 */ +#define SSINFO_FLAGS_ALIGNED_DEVICE 0x00000001 +#define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE 0x00000002 +#define SSINFO_FLAGS_NO_SEEK_PENALTY 0x00000004 +#define SSINFO_FLAGS_TRIM_ENABLED 0x00000008 +/* sector size info struct */ +struct smb3_fs_ss_info { + __le32 LogicalBytesPerSector; + __le32 PhysicalBytesPerSectorForAtomicity; + __le32 PhysicalBytesPerSectorForPerf; + __le32 FSEffPhysicalBytesPerSectorForAtomicity; + __le32 Flags; + __le32 ByteOffsetForSectorAlignment; + __le32 ByteOffsetForPartitionAlignment; +} __packed; + /* See MS-FSCC 2.5.8 */ typedef struct { __le64 TotalAllocationUnits; @@ -138,6 +447,17 @@ typedef struct { __le32 BytesPerSector; } __packed FILE_SYSTEM_SIZE_INFO; /* size info, level 0x103 */ +/* volume info struct - see MS-FSCC 2.5.9 */ +#define MAX_VOL_LABEL_LEN 32 +struct filesystem_vol_info { + __le64 VolumeCreationTime; + __le32 VolumeSerialNumber; + __le32 VolumeLabelLength; /* includes trailing null */ + __u8 SupportsObjects; /* True if eg like NTFS, supports objects */ + __u8 Reserved; + __u8 VolumeLabel[]; /* variable len */ +} __packed; + /* See MS-FSCC 2.5.10 */ typedef struct { __le32 DeviceType; @@ -189,6 +509,22 @@ typedef struct { #define FILE_ATTRIBUTE_NO_SCRUB_DATA_LE cpu_to_le32(FILE_ATTRIBUTE_NO_SCRUB_DATA) #define FILE_ATTRIBUTE_MASK_LE cpu_to_le32(FILE_ATTRIBUTE_MASK) +/* + * SMB2 Notify Action Flags + * See MS-FSCC 2.7.1 + */ +#define FILE_ACTION_ADDED 0x00000001 +#define FILE_ACTION_REMOVED 0x00000002 +#define FILE_ACTION_MODIFIED 0x00000003 +#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004 +#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005 +#define FILE_ACTION_ADDED_STREAM 0x00000006 +#define FILE_ACTION_REMOVED_STREAM 0x00000007 +#define FILE_ACTION_MODIFIED_STREAM 0x00000008 +#define FILE_ACTION_REMOVED_BY_DELETE 0x00000009 +#define FILE_ACTION_ID_NOT_TUNNELLED 0x0000000A +#define FILE_ACTION_TUNNELLED_ID_COLLISION 0x0000000B + /* * Response contains array of the following structures * See MS-FSCC 2.7.1 diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h index e482c86ceb00..85a4248d4f29 100644 --- a/fs/smb/common/smb2pdu.h +++ b/fs/smb/common/smb2pdu.h @@ -1006,22 +1006,6 @@ struct smb2_set_info_rsp { #define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400 #define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800 -/* - * SMB2 Notify Action Flags - * See MS-FSCC 2.7.1 - */ -#define FILE_ACTION_ADDED 0x00000001 -#define FILE_ACTION_REMOVED 0x00000002 -#define FILE_ACTION_MODIFIED 0x00000003 -#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004 -#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005 -#define FILE_ACTION_ADDED_STREAM 0x00000006 -#define FILE_ACTION_REMOVED_STREAM 0x00000007 -#define FILE_ACTION_MODIFIED_STREAM 0x00000008 -#define FILE_ACTION_REMOVED_BY_DELETE 0x00000009 -#define FILE_ACTION_ID_NOT_TUNNELLED 0x0000000A -#define FILE_ACTION_TUNNELLED_ID_COLLISION 0x0000000B - /* See MS-SMB2 2.2.35 */ struct smb2_change_notify_req { struct smb2_hdr hdr; @@ -1499,105 +1483,6 @@ struct network_interface_info_ioctl_rsp { }; } __packed; -/* this goes in the ioctl buffer when doing FSCTL_SET_ZERO_DATA */ -struct file_zero_data_information { - __le64 FileOffset; - __le64 BeyondFinalZero; -} __packed; - -/* See MS-FSCC 2.3.7 */ -struct duplicate_extents_to_file { - __u64 PersistentFileHandle; /* source file handle, opaque endianness */ - __u64 VolatileFileHandle; - __le64 SourceFileOffset; - __le64 TargetFileOffset; - __le64 ByteCount; /* Bytes to be copied */ -} __packed; - -/* See MS-FSCC 2.3.9 */ -#define DUPLICATE_EXTENTS_DATA_EX_SOURCE_ATOMIC 0x00000001 -struct duplicate_extents_to_file_ex { - __le64 StructureSize; /* MUST be set to 0x30 */ - __u64 PersistentFileHandle; /* source file handle, opaque endianness */ - __u64 VolatileFileHandle; - __le64 SourceFileOffset; - __le64 TargetFileOffset; - __le64 ByteCount; /* Bytes to be copied */ - __le32 Flags; - __le32 Reserved; -} __packed; - - -/* See MS-FSCC 2.3.20 */ -struct fsctl_get_integrity_information_rsp { - __le16 ChecksumAlgorithm; - __le16 Reserved; - __le32 Flags; - __le32 ChecksumChunkSizeInBytes; - __le32 ClusterSizeInBytes; -} __packed; - -/* See MS-FSCC 2.3.55 */ -struct fsctl_query_file_regions_req { - __le64 FileOffset; - __le64 Length; - __le32 DesiredUsage; - __le32 Reserved; -} __packed; - -/* DesiredUsage flags see MS-FSCC 2.3.56.1 */ -#define FILE_USAGE_INVALID_RANGE 0x00000000 -#define FILE_USAGE_VALID_CACHED_DATA 0x00000001 -#define FILE_USAGE_NONCACHED_DATA 0x00000002 - -struct file_region_info { - __le64 FileOffset; - __le64 Length; - __le32 DesiredUsage; - __le32 Reserved; -} __packed; - -/* See MS-FSCC 2.3.56 */ -struct fsctl_query_file_region_rsp { - __le32 Flags; - __le32 TotalRegionEntryCount; - __le32 RegionEntryCount; - __u32 Reserved; - struct file_region_info Regions[]; -} __packed; - -/* See MS-FSCC 2.3.58 */ -struct fsctl_query_on_disk_vol_info_rsp { - __le64 DirectoryCount; - __le64 FileCount; - __le16 FsFormatMajVersion; - __le16 FsFormatMinVersion; - __u8 FsFormatName[24]; - __le64 FormatTime; - __le64 LastUpdateTime; - __u8 CopyrightInfo[68]; - __u8 AbstractInfo[68]; - __u8 FormatImplInfo[68]; - __u8 LastModifyImplInfo[68]; -} __packed; - -/* See MS-FSCC 2.3.73 */ -struct fsctl_set_integrity_information_req { - __le16 ChecksumAlgorithm; - __le16 Reserved; - __le32 Flags; -} __packed; - -/* See MS-FSCC 2.3.75 */ -struct fsctl_set_integrity_info_ex_req { - __u8 EnableIntegrity; - __u8 KeepState; - __u16 Reserved; - __le32 Flags; - __u8 Version; - __u8 Reserved2[7]; -} __packed; - /* Integrity ChecksumAlgorithm choices for above */ #define CHECKSUM_TYPE_NONE 0x0000 #define CHECKSUM_TYPE_CRC64 0x0002 @@ -1606,72 +1491,6 @@ struct fsctl_set_integrity_info_ex_req { /* Integrity flags for above */ #define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF 0x00000001 -/* Reparse structures - see MS-FSCC 2.1.2 */ - -/* struct fsctl_reparse_info_req is empty, only response structs (see below) */ -struct reparse_data_buffer { - __le32 ReparseTag; - __le16 ReparseDataLength; - __u16 Reserved; - __u8 DataBuffer[]; /* Variable Length */ -} __packed; - -struct reparse_guid_data_buffer { - __le32 ReparseTag; - __le16 ReparseDataLength; - __u16 Reserved; - __u8 ReparseGuid[16]; - __u8 DataBuffer[]; /* Variable Length */ -} __packed; - -struct reparse_mount_point_data_buffer { - __le32 ReparseTag; - __le16 ReparseDataLength; - __u16 Reserved; - __le16 SubstituteNameOffset; - __le16 SubstituteNameLength; - __le16 PrintNameOffset; - __le16 PrintNameLength; - __u8 PathBuffer[]; /* Variable Length */ -} __packed; - -#define SYMLINK_FLAG_RELATIVE 0x00000001 - -struct reparse_symlink_data_buffer { - __le32 ReparseTag; - __le16 ReparseDataLength; - __u16 Reserved; - __le16 SubstituteNameOffset; - __le16 SubstituteNameLength; - __le16 PrintNameOffset; - __le16 PrintNameLength; - __le32 Flags; - __u8 PathBuffer[]; /* Variable Length */ -} __packed; - -/* For IO_REPARSE_TAG_NFS - see MS-FSCC 2.1.2.6 */ -#define NFS_SPECFILE_LNK 0x00000000014B4E4C -#define NFS_SPECFILE_CHR 0x0000000000524843 -#define NFS_SPECFILE_BLK 0x00000000004B4C42 -#define NFS_SPECFILE_FIFO 0x000000004F464946 -#define NFS_SPECFILE_SOCK 0x000000004B434F53 -struct reparse_nfs_data_buffer { - __le32 ReparseTag; - __le16 ReparseDataLength; - __u16 Reserved; - __le64 InodeType; /* NFS_SPECFILE_* */ - __u8 DataBuffer[]; -} __packed; - -/* For IO_REPARSE_TAG_LX_SYMLINK - see MS-FSCC 2.1.2.7 */ -struct reparse_wsl_symlink_data_buffer { - __le32 ReparseTag; - __le16 ReparseDataLength; - __u16 Reserved; - __le32 Version; /* Always 2 */ - __u8 Target[]; /* Variable Length UTF-8 string without nul-term */ -} __packed; - struct validate_negotiate_info_req { __le32 Capabilities; __u8 Guid[SMB2_CLIENT_GUID_SIZE]; @@ -1791,84 +1610,6 @@ struct smb2_query_info_rsp { __u8 Buffer[]; } __packed; -/* - * PDU query infolevel structure definitions - */ - -/* See MS-FSCC 2.3.52 */ -struct file_allocated_range_buffer { - __le64 file_offset; - __le64 length; -} __packed; - -struct smb2_file_internal_info { - __le64 IndexNumber; -} __packed; /* level 6 Query */ - -struct smb2_file_rename_info { /* encoding of request for level 10 */ - /* New members MUST be added within the struct_group() macro below. */ - __struct_group(smb2_file_rename_info_hdr, __hdr, __packed, - __u8 ReplaceIfExists; /* 1 = replace existing target with new */ - /* 0 = fail if target already exists */ - __u8 Reserved[7]; - __u64 RootDirectory; /* MBZ for network operations (why says spec?) */ - __le32 FileNameLength; - ); - char FileName[]; /* New name to be assigned */ - /* padding - overall struct size must be >= 24 so filename + pad >= 6 */ -} __packed; /* level 10 Set */ -static_assert(offsetof(struct smb2_file_rename_info, FileName) == sizeof(struct smb2_file_rename_info_hdr), - "struct member likely outside of __struct_group()"); - -struct smb2_file_link_info { /* encoding of request for level 11 */ - /* New members MUST be added within the struct_group() macro below. */ - __struct_group(smb2_file_link_info_hdr, __hdr, __packed, - __u8 ReplaceIfExists; /* 1 = replace existing link with new */ - /* 0 = fail if link already exists */ - __u8 Reserved[7]; - __u64 RootDirectory; /* MBZ for network operations (why says spec?) */ - __le32 FileNameLength; - ); - char FileName[]; /* Name to be assigned to new link */ -} __packed; /* level 11 Set */ -static_assert(offsetof(struct smb2_file_link_info, FileName) == sizeof(struct smb2_file_link_info_hdr), - "struct member likely outside of __struct_group()"); - -/* - * This level 18, although with struct with same name is different from cifs - * level 0x107. Level 0x107 has an extra u64 between AccessFlags and - * CurrentByteOffset. - */ -struct smb2_file_all_info { /* data block encoding of response to level 18 */ - __le64 CreationTime; /* Beginning of FILE_BASIC_INFO equivalent */ - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le32 Attributes; - __u32 Pad1; /* End of FILE_BASIC_INFO_INFO equivalent */ - __le64 AllocationSize; /* Beginning of FILE_STANDARD_INFO equivalent */ - __le64 EndOfFile; /* size ie offset to first free byte in file */ - __le32 NumberOfLinks; /* hard links */ - __u8 DeletePending; - __u8 Directory; - __u16 Pad2; /* End of FILE_STANDARD_INFO equivalent */ - __le64 IndexNumber; - __le32 EASize; - __le32 AccessFlags; - __le64 CurrentByteOffset; - __le32 Mode; - __le32 AlignmentRequirement; - __le32 FileNameLength; - union { - char __pad; /* Legacy structure padding */ - DECLARE_FLEX_ARRAY(char, FileName); - }; -} __packed; /* level 18 Query */ - -struct smb2_file_eof_info { /* encoding of request for level 10 */ - __le64 EndOfFile; /* new end of file value */ -} __packed; /* level 20 Set */ - /* Level 100 query info */ struct smb311_posix_qinfo { __le64 CreationTime; @@ -1894,65 +1635,6 @@ struct smb311_posix_qinfo { */ } __packed; -/* File System Information Classes */ -#define FS_VOLUME_INFORMATION 1 /* Query */ -#define FS_LABEL_INFORMATION 2 /* Set */ -#define FS_SIZE_INFORMATION 3 /* Query */ -#define FS_DEVICE_INFORMATION 4 /* Query */ -#define FS_ATTRIBUTE_INFORMATION 5 /* Query */ -#define FS_CONTROL_INFORMATION 6 /* Query, Set */ -#define FS_FULL_SIZE_INFORMATION 7 /* Query */ -#define FS_OBJECT_ID_INFORMATION 8 /* Query, Set */ -#define FS_DRIVER_PATH_INFORMATION 9 /* Query */ -#define FS_SECTOR_SIZE_INFORMATION 11 /* SMB3 or later. Query */ -#define FS_POSIX_INFORMATION 100 /* SMB3.1.1 POSIX. Query */ - -struct smb2_fs_full_size_info { - __le64 TotalAllocationUnits; - __le64 CallerAvailableAllocationUnits; - __le64 ActualAvailableAllocationUnits; - __le32 SectorsPerAllocationUnit; - __le32 BytesPerSector; -} __packed; - -#define SSINFO_FLAGS_ALIGNED_DEVICE 0x00000001 -#define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE 0x00000002 -#define SSINFO_FLAGS_NO_SEEK_PENALTY 0x00000004 -#define SSINFO_FLAGS_TRIM_ENABLED 0x00000008 - -/* sector size info struct */ -struct smb3_fs_ss_info { - __le32 LogicalBytesPerSector; - __le32 PhysicalBytesPerSectorForAtomicity; - __le32 PhysicalBytesPerSectorForPerf; - __le32 FSEffPhysicalBytesPerSectorForAtomicity; - __le32 Flags; - __le32 ByteOffsetForSectorAlignment; - __le32 ByteOffsetForPartitionAlignment; -} __packed; - -/* File System Control Information */ -struct smb2_fs_control_info { - __le64 FreeSpaceStartFiltering; - __le64 FreeSpaceThreshold; - __le64 FreeSpaceStopFiltering; - __le64 DefaultQuotaThreshold; - __le64 DefaultQuotaLimit; - __le32 FileSystemControlFlags; - __le32 Padding; -} __packed; - -/* volume info struct - see MS-FSCC 2.5.9 */ -#define MAX_VOL_LABEL_LEN 32 -struct smb3_fs_vol_info { - __le64 VolumeCreationTime; - __u32 VolumeSerialNumber; - __le32 VolumeLabelLength; /* includes trailing null */ - __u8 SupportsObjects; /* True if eg like NTFS, supports objects */ - __u8 Reserved; - __u8 VolumeLabel[]; /* variable len */ -} __packed; - /* See MS-SMB2 2.2.23 through 2.2.25 */ struct smb2_oplock_break { struct smb2_hdr hdr; diff --git a/fs/smb/common/smbdirect/smbdirect.h b/fs/smb/common/smbdirect/smbdirect.h index 05cc6a9d0ccd..821a34c4cc47 100644 --- a/fs/smb/common/smbdirect/smbdirect.h +++ b/fs/smb/common/smbdirect/smbdirect.h @@ -7,6 +7,8 @@ #ifndef __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_H__ #define __FS_SMB_COMMON_SMBDIRECT_SMBDIRECT_H__ +#include + /* SMB-DIRECT buffer descriptor V1 structure [MS-SMBD] 2.2.3.1 */ struct smbdirect_buffer_descriptor_v1 { __le64 offset; diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 95265192bb01..22184e53d445 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -350,6 +350,35 @@ struct smbdirect_socket { u64 dequeue_reassembly_queue; u64 send_empty; } statistics; + + struct { +#define SMBDIRECT_LOG_ERR 0x0 +#define SMBDIRECT_LOG_INFO 0x1 + +#define SMBDIRECT_LOG_OUTGOING 0x1 +#define SMBDIRECT_LOG_INCOMING 0x2 +#define SMBDIRECT_LOG_READ 0x4 +#define SMBDIRECT_LOG_WRITE 0x8 +#define SMBDIRECT_LOG_RDMA_SEND 0x10 +#define SMBDIRECT_LOG_RDMA_RECV 0x20 +#define SMBDIRECT_LOG_KEEP_ALIVE 0x40 +#define SMBDIRECT_LOG_RDMA_EVENT 0x80 +#define SMBDIRECT_LOG_RDMA_MR 0x100 +#define SMBDIRECT_LOG_RDMA_RW 0x200 +#define SMBDIRECT_LOG_NEGOTIATE 0x400 + void *private_ptr; + bool (*needed)(struct smbdirect_socket *sc, + void *private_ptr, + unsigned int lvl, + unsigned int cls); + void (*vaprintf)(struct smbdirect_socket *sc, + const char *func, + unsigned int line, + void *private_ptr, + unsigned int lvl, + unsigned int cls, + struct va_format *vaf); + } logging; }; static void __smbdirect_socket_disabled_work(struct work_struct *work) @@ -360,6 +389,100 @@ static void __smbdirect_socket_disabled_work(struct work_struct *work) WARN_ON_ONCE(1); } +static bool __smbdirect_log_needed(struct smbdirect_socket *sc, + void *private_ptr, + unsigned int lvl, + unsigned int cls) +{ + /* + * Should never be called, the caller should + * set it's own functions. + */ + WARN_ON_ONCE(1); + return false; +} + +static void __smbdirect_log_vaprintf(struct smbdirect_socket *sc, + const char *func, + unsigned int line, + void *private_ptr, + unsigned int lvl, + unsigned int cls, + struct va_format *vaf) +{ + /* + * Should never be called, the caller should + * set it's own functions. + */ + WARN_ON_ONCE(1); +} + +__printf(6, 7) +static void __smbdirect_log_printf(struct smbdirect_socket *sc, + const char *func, + unsigned int line, + unsigned int lvl, + unsigned int cls, + const char *fmt, + ...); +__maybe_unused +static void __smbdirect_log_printf(struct smbdirect_socket *sc, + const char *func, + unsigned int line, + unsigned int lvl, + unsigned int cls, + const char *fmt, + ...) +{ + struct va_format vaf; + va_list args; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + sc->logging.vaprintf(sc, + func, + line, + sc->logging.private_ptr, + lvl, + cls, + &vaf); + va_end(args); +} + +#define ___smbdirect_log_generic(sc, func, line, lvl, cls, fmt, args...) do { \ + if (sc->logging.needed(sc, sc->logging.private_ptr, lvl, cls)) { \ + __smbdirect_log_printf(sc, func, line, lvl, cls, fmt, ##args); \ + } \ +} while (0) +#define __smbdirect_log_generic(sc, lvl, cls, fmt, args...) \ + ___smbdirect_log_generic(sc, __func__, __LINE__, lvl, cls, fmt, ##args) + +#define smbdirect_log_outgoing(sc, lvl, fmt, args...) \ + __smbdirect_log_generic(sc, lvl, SMBDIRECT_LOG_OUTGOING, fmt, ##args) +#define smbdirect_log_incoming(sc, lvl, fmt, args...) \ + __smbdirect_log_generic(sc, lvl, SMBDIRECT_LOG_INCOMING, fmt, ##args) +#define smbdirect_log_read(sc, lvl, fmt, args...) \ + __smbdirect_log_generic(sc, lvl, SMBDIRECT_LOG_READ, fmt, ##args) +#define smbdirect_log_write(sc, lvl, fmt, args...) \ + __smbdirect_log_generic(sc, lvl, SMBDIRECT_LOG_WRITE, fmt, ##args) +#define smbdirect_log_rdma_send(sc, lvl, fmt, args...) \ + __smbdirect_log_generic(sc, lvl, SMBDIRECT_LOG_RDMA_SEND, fmt, ##args) +#define smbdirect_log_rdma_recv(sc, lvl, fmt, args...) \ + __smbdirect_log_generic(sc, lvl, SMBDIRECT_LOG_RDMA_RECV, fmt, ##args) +#define smbdirect_log_keep_alive(sc, lvl, fmt, args...) \ + __smbdirect_log_generic(sc, lvl, SMBDIRECT_LOG_KEEP_ALIVE, fmt, ##args) +#define smbdirect_log_rdma_event(sc, lvl, fmt, args...) \ + __smbdirect_log_generic(sc, lvl, SMBDIRECT_LOG_RDMA_EVENT, fmt, ##args) +#define smbdirect_log_rdma_mr(sc, lvl, fmt, args...) \ + __smbdirect_log_generic(sc, lvl, SMBDIRECT_LOG_RDMA_MR, fmt, ##args) +#define smbdirect_log_rdma_rw(sc, lvl, fmt, args...) \ + __smbdirect_log_generic(sc, lvl, SMBDIRECT_LOG_RDMA_RW, fmt, ##args) +#define smbdirect_log_negotiate(sc, lvl, fmt, args...) \ + __smbdirect_log_generic(sc, lvl, SMBDIRECT_LOG_NEGOTIATE, fmt, ##args) + static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) { /* @@ -420,6 +543,10 @@ static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) INIT_WORK(&sc->mr_io.recovery_work, __smbdirect_socket_disabled_work); disable_work_sync(&sc->mr_io.recovery_work); init_waitqueue_head(&sc->mr_io.cleanup.wait_queue); + + sc->logging.private_ptr = NULL; + sc->logging.needed = __smbdirect_log_needed; + sc->logging.vaprintf = __smbdirect_log_vaprintf; } #define __SMBDIRECT_CHECK_STATUS_FAILED(__sc, __expected_status, __error_cmd, __unexpected_cmd) ({ \ @@ -436,7 +563,6 @@ static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) #define __SMBDIRECT_CHECK_STATUS_WARN(__sc, __expected_status, __unexpected_cmd) \ __SMBDIRECT_CHECK_STATUS_FAILED(__sc, __expected_status, \ - , \ { \ const struct sockaddr_storage *__src = NULL; \ const struct sockaddr_storage *__dst = NULL; \ @@ -444,6 +570,26 @@ static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) __src = &(__sc)->rdma.cm_id->route.addr.src_addr; \ __dst = &(__sc)->rdma.cm_id->route.addr.dst_addr; \ } \ + smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_INFO, \ + "expected[%s] != %s first_error=%1pe local=%pISpsfc remote=%pISpsfc\n", \ + smbdirect_socket_status_string(__expected_status), \ + smbdirect_socket_status_string((__sc)->status), \ + SMBDIRECT_DEBUG_ERR_PTR((__sc)->first_error), \ + __src, __dst); \ + }, \ + { \ + const struct sockaddr_storage *__src = NULL; \ + const struct sockaddr_storage *__dst = NULL; \ + if ((__sc)->rdma.cm_id) { \ + __src = &(__sc)->rdma.cm_id->route.addr.src_addr; \ + __dst = &(__sc)->rdma.cm_id->route.addr.dst_addr; \ + } \ + smbdirect_log_rdma_event(sc, SMBDIRECT_LOG_ERR, \ + "expected[%s] != %s first_error=%1pe local=%pISpsfc remote=%pISpsfc\n", \ + smbdirect_socket_status_string(__expected_status), \ + smbdirect_socket_status_string((__sc)->status), \ + SMBDIRECT_DEBUG_ERR_PTR((__sc)->first_error), \ + __src, __dst); \ WARN_ONCE(1, \ "expected[%s] != %s first_error=%1pe local=%pISpsfc remote=%pISpsfc\n", \ smbdirect_socket_status_string(__expected_status), \ diff --git a/fs/smb/server/Kconfig b/fs/smb/server/Kconfig index 12594879cb64..96aa8e2a8770 100644 --- a/fs/smb/server/Kconfig +++ b/fs/smb/server/Kconfig @@ -7,7 +7,6 @@ config SMB_SERVER select NLS_UTF8 select NLS_UCS2_UTILS select CRYPTO - select CRYPTO_ECB select CRYPTO_LIB_ARC4 select CRYPTO_LIB_DES select CRYPTO_LIB_MD5 diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c index af5f40304331..7d0691f7263f 100644 --- a/fs/smb/server/auth.c +++ b/fs/smb/server/auth.c @@ -827,6 +827,7 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, struct smb2_transform_hdr *tr_hdr = smb_get_msg(iov[0].iov_base); unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20; int rc; + DECLARE_CRYPTO_WAIT(wait); struct scatterlist *sg; u8 sign[SMB2_SIGNATURE_SIZE] = {}; u8 key[SMB3_ENC_DEC_KEY_SIZE]; @@ -913,12 +914,12 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov, aead_request_set_crypt(req, sg, sg, crypt_len, iv); aead_request_set_ad(req, assoc_data_len); - aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); + aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | + CRYPTO_TFM_REQ_MAY_SLEEP, + crypto_req_done, &wait); - if (enc) - rc = crypto_aead_encrypt(req); - else - rc = crypto_aead_decrypt(req); + rc = crypto_wait_req(enc ? crypto_aead_encrypt(req) : + crypto_aead_decrypt(req), &wait); if (rc) goto free_iv; diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c index 1bb2081c492c..26cfce344861 100644 --- a/fs/smb/server/connection.c +++ b/fs/smb/server/connection.c @@ -96,6 +96,7 @@ void ksmbd_conn_free(struct ksmbd_conn *conn) xa_destroy(&conn->sessions); kvfree(conn->request_buf); kfree(conn->preauth_info); + kfree(conn->mechToken); if (atomic_dec_and_test(&conn->refcnt)) { conn->transport->ops->free_transport(conn->transport); kfree(conn); diff --git a/fs/smb/server/crypto_ctx.h b/fs/smb/server/crypto_ctx.h index b9476ed520ae..27fd553d10aa 100644 --- a/fs/smb/server/crypto_ctx.h +++ b/fs/smb/server/crypto_ctx.h @@ -20,11 +20,6 @@ enum { CRYPTO_AEAD_MAX, }; -enum { - CRYPTO_BLK_ECBDES = 32, - CRYPTO_BLK_MAX, -}; - struct ksmbd_crypto_ctx { struct list_head list; diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c index 39be2d2be86c..a86589408835 100644 --- a/fs/smb/server/mgmt/user_session.c +++ b/fs/smb/server/mgmt/user_session.c @@ -382,12 +382,10 @@ void ksmbd_session_destroy(struct ksmbd_session *sess) return; delete_proc_session(sess); - + ksmbd_tree_conn_session_logoff(sess); + ksmbd_destroy_file_table(sess); if (sess->user) ksmbd_free_user(sess->user); - - ksmbd_tree_conn_session_logoff(sess); - ksmbd_destroy_file_table(&sess->file_table); ksmbd_launch_ksmbd_durable_scavenger(); ksmbd_session_rpc_clear_list(sess); free_channel_list(sess); @@ -618,7 +616,7 @@ void destroy_previous_session(struct ksmbd_conn *conn, goto out; } - ksmbd_destroy_file_table(&prev_sess->file_table); + ksmbd_destroy_file_table(prev_sess); prev_sess->state = SMB2_SESSION_EXPIRED; ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP); ksmbd_launch_ksmbd_durable_scavenger(); diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c index 9b2bb8764a80..cd3f28b0e7cb 100644 --- a/fs/smb/server/oplock.c +++ b/fs/smb/server/oplock.c @@ -1841,6 +1841,7 @@ int smb2_check_durable_oplock(struct ksmbd_conn *conn, struct ksmbd_share_config *share, struct ksmbd_file *fp, struct lease_ctx_info *lctx, + struct ksmbd_user *user, char *name) { struct oplock_info *opinfo = opinfo_get(fp); @@ -1849,6 +1850,12 @@ int smb2_check_durable_oplock(struct ksmbd_conn *conn, if (!opinfo) return 0; + if (ksmbd_vfs_compare_durable_owner(fp, user) == false) { + ksmbd_debug(SMB, "Durable handle reconnect failed: owner mismatch\n"); + ret = -EBADF; + goto out; + } + if (opinfo->is_lease == false) { if (lctx) { pr_err("create context include lease\n"); diff --git a/fs/smb/server/oplock.h b/fs/smb/server/oplock.h index 921e3199e4df..d91a8266e065 100644 --- a/fs/smb/server/oplock.h +++ b/fs/smb/server/oplock.h @@ -126,5 +126,6 @@ int smb2_check_durable_oplock(struct ksmbd_conn *conn, struct ksmbd_share_config *share, struct ksmbd_file *fp, struct lease_ctx_info *lctx, + struct ksmbd_user *user, char *name); #endif /* __KSMBD_OPLOCK_H */ diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c index 422d9d978285..d8893079abdb 100644 --- a/fs/smb/server/server.c +++ b/fs/smb/server/server.c @@ -629,7 +629,6 @@ static void __exit ksmbd_server_exit(void) MODULE_AUTHOR("Namjae Jeon "); MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER"); MODULE_LICENSE("GPL"); -MODULE_SOFTDEP("pre: ecb"); MODULE_SOFTDEP("pre: nls"); MODULE_SOFTDEP("pre: aes"); MODULE_SOFTDEP("pre: cmac"); diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 8e4cfdc0ba02..10ae77dae5a1 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -1915,7 +1915,7 @@ out_err: else if (rc) rsp->hdr.Status = STATUS_LOGON_FAILURE; - if (conn->use_spnego && conn->mechToken) { + if (conn->mechToken) { kfree(conn->mechToken); conn->mechToken = NULL; } @@ -3013,7 +3013,8 @@ int smb2_open(struct ksmbd_work *work) } if (dh_info.reconnected == true) { - rc = smb2_check_durable_oplock(conn, share, dh_info.fp, lc, name); + rc = smb2_check_durable_oplock(conn, share, dh_info.fp, + lc, sess->user, name); if (rc) { ksmbd_put_durable_fd(dh_info.fp); goto err_out2; @@ -4716,6 +4717,11 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp, ea_req = (struct smb2_ea_info_req *)((char *)req + le16_to_cpu(req->InputBufferOffset)); + + if (le32_to_cpu(req->InputBufferLength) < + offsetof(struct smb2_ea_info_req, name) + + ea_req->EaNameLength) + return -EINVAL; } else { /* need to send all EAs, if no specific EA is requested*/ if (le32_to_cpu(req->Flags) & SL_RETURN_SINGLE_ENTRY) @@ -4858,7 +4864,7 @@ static void get_file_access_info(struct smb2_query_info_rsp *rsp, static int get_file_basic_info(struct smb2_query_info_rsp *rsp, struct ksmbd_file *fp, void *rsp_org) { - struct smb2_file_basic_info *basic_info; + struct file_basic_info *basic_info; struct kstat stat; u64 time; int ret; @@ -4874,7 +4880,7 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp, if (ret) return ret; - basic_info = (struct smb2_file_basic_info *)rsp->Buffer; + basic_info = (struct file_basic_info *)rsp->Buffer; basic_info->CreationTime = cpu_to_le64(fp->create_time); time = ksmbd_UnixTimeToNT(stat.atime); basic_info->LastAccessTime = cpu_to_le64(time); @@ -4883,9 +4889,9 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp, time = ksmbd_UnixTimeToNT(stat.ctime); basic_info->ChangeTime = cpu_to_le64(time); basic_info->Attributes = fp->f_ci->m_fattr; - basic_info->Pad1 = 0; + basic_info->Pad = 0; rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_basic_info)); + cpu_to_le32(sizeof(struct file_basic_info)); return 0; } @@ -5583,13 +5589,14 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, serial_crc = crc32_le(serial_crc, ksmbd_netbios_name(), strlen(ksmbd_netbios_name())); /* Taking dummy value of serial number*/ - info->SerialNumber = cpu_to_le32(serial_crc); + info->VolumeSerialNumber = cpu_to_le32(serial_crc); len = smbConvertToUTF16((__le16 *)info->VolumeLabel, share->name, PATH_MAX, conn->local_nls, 0); len = len * 2; - info->VolumeLabelSize = cpu_to_le32(len); + info->VolumeLabelLength = cpu_to_le32(len); info->Reserved = 0; + info->SupportsObjects = 0; sz = sizeof(struct filesystem_vol_info) + len; rsp->OutputBufferLength = cpu_to_le32(sz); break; @@ -6222,7 +6229,7 @@ out: } static int set_file_basic_info(struct ksmbd_file *fp, - struct smb2_file_basic_info *file_info, + struct file_basic_info *file_info, struct ksmbd_share_config *share) { struct iattr attrs; @@ -6504,10 +6511,10 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, switch (req->FileInfoClass) { case FILE_BASIC_INFORMATION: { - if (buf_len < sizeof(struct smb2_file_basic_info)) + if (buf_len < sizeof(struct file_basic_info)) return -EMSGSIZE; - return set_file_basic_info(fp, (struct smb2_file_basic_info *)buffer, share); + return set_file_basic_info(fp, (struct file_basic_info *)buffer, share); } case FILE_ALLOCATION_INFORMATION: { diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h index 8b6eafb70dca..e7cf573e59f0 100644 --- a/fs/smb/server/smb2pdu.h +++ b/fs/smb/server/smb2pdu.h @@ -186,15 +186,6 @@ struct smb2_file_alignment_info { __le32 AlignmentRequirement; } __packed; -struct smb2_file_basic_info { /* data block encoding of response to level 18 */ - __le64 CreationTime; /* Beginning of FILE_BASIC_INFO equivalent */ - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le32 Attributes; - __u32 Pad1; /* End of FILE_BASIC_INFO_INFO equivalent */ -} __packed; - struct smb2_file_alt_name_info { __le32 FileNameLength; char FileName[]; diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h index ca7e3610d074..b090b56743c4 100644 --- a/fs/smb/server/smb_common.h +++ b/fs/smb/server/smb_common.h @@ -90,14 +90,6 @@ struct smb_negotiate_rsp { __le16 ByteCount; } __packed; -struct filesystem_vol_info { - __le64 VolumeCreationTime; - __le32 SerialNumber; - __le32 VolumeLabelSize; - __le16 Reserved; - __le16 VolumeLabel[]; -} __packed; - #define EXTENDED_INFO_MAGIC 0x43667364 /* Cfsd */ #define STRING_LENGTH 28 diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c index c30d01877c41..061a305bf9c8 100644 --- a/fs/smb/server/smbacl.c +++ b/fs/smb/server/smbacl.c @@ -451,7 +451,8 @@ static void parse_dacl(struct mnt_idmap *idmap, ppace[i]->access_req = smb_map_generic_desired_access(ppace[i]->access_req); - if (!(compare_sids(&ppace[i]->sid, &sid_unix_NFS_mode))) { + if (ppace[i]->sid.num_subauth >= 3 && + !(compare_sids(&ppace[i]->sid, &sid_unix_NFS_mode))) { fattr->cf_mode = le32_to_cpu(ppace[i]->sid.sub_auth[2]); break; diff --git a/fs/smb/server/transport_ipc.c b/fs/smb/server/transport_ipc.c index 2dbabe2d8005..f7aa427a06fe 100644 --- a/fs/smb/server/transport_ipc.c +++ b/fs/smb/server/transport_ipc.c @@ -55,7 +55,7 @@ static bool ksmbd_ipc_validate_version(struct genl_info *m) struct ksmbd_ipc_msg { unsigned int type; unsigned int sz; - unsigned char payload[]; + unsigned char payload[] __counted_by(sz); }; struct ipc_msg_table_entry { @@ -242,9 +242,8 @@ static void ipc_update_last_active(void) static struct ksmbd_ipc_msg *ipc_msg_alloc(size_t sz) { struct ksmbd_ipc_msg *msg; - size_t msg_sz = sz + sizeof(struct ksmbd_ipc_msg); - msg = kvzalloc(msg_sz, KSMBD_DEFAULT_GFP); + msg = kvzalloc_flex(*msg, payload, sz, KSMBD_DEFAULT_GFP); if (msg) msg->sz = sz; return msg; diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 188572491d53..dbc8dedb85dc 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -1588,15 +1588,21 @@ static int smb_direct_post_send_data(struct smbdirect_socket *sc, if (ret) goto err; + /* + * From here msg is moved to send_ctx + * and we should not free it explicitly. + */ + if (send_ctx == &_send_ctx) { ret = smb_direct_flush_send_list(sc, send_ctx, true); if (ret) - goto err; + goto flush_failed; } return 0; err: smb_direct_free_sendmsg(sc, msg); +flush_failed: header_failed: atomic_inc(&sc->send_io.credits.count); credit_failed: diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c index 168f2dd7e200..3551f01a3fa0 100644 --- a/fs/smb/server/vfs_cache.c +++ b/fs/smb/server/vfs_cache.c @@ -19,6 +19,7 @@ #include "misc.h" #include "mgmt/tree_connect.h" #include "mgmt/user_session.h" +#include "mgmt/user_config.h" #include "smb_common.h" #include "server.h" #include "smb2pdu.h" @@ -463,9 +464,11 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp) * there are not accesses to fp->lock_list. */ list_for_each_entry_safe(smb_lock, tmp_lock, &fp->lock_list, flist) { - spin_lock(&fp->conn->llist_lock); - list_del(&smb_lock->clist); - spin_unlock(&fp->conn->llist_lock); + if (!list_empty(&smb_lock->clist) && fp->conn) { + spin_lock(&fp->conn->llist_lock); + list_del(&smb_lock->clist); + spin_unlock(&fp->conn->llist_lock); + } list_del(&smb_lock->flist); locks_free_lock(smb_lock->fl); @@ -474,6 +477,8 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp) if (ksmbd_stream_fd(fp)) kfree(fp->stream.name); + kfree(fp->owner.name); + kmem_cache_free(filp_cache, fp); } @@ -785,11 +790,13 @@ void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp, } static int -__close_file_table_ids(struct ksmbd_file_table *ft, +__close_file_table_ids(struct ksmbd_session *sess, struct ksmbd_tree_connect *tcon, bool (*skip)(struct ksmbd_tree_connect *tcon, - struct ksmbd_file *fp)) + struct ksmbd_file *fp, + struct ksmbd_user *user)) { + struct ksmbd_file_table *ft = &sess->file_table; struct ksmbd_file *fp; unsigned int id = 0; int num = 0; @@ -802,7 +809,7 @@ __close_file_table_ids(struct ksmbd_file_table *ft, break; } - if (skip(tcon, fp) || + if (skip(tcon, fp, sess->user) || !atomic_dec_and_test(&fp->refcount)) { id++; write_unlock(&ft->lock); @@ -854,7 +861,8 @@ static inline bool is_reconnectable(struct ksmbd_file *fp) } static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon, - struct ksmbd_file *fp) + struct ksmbd_file *fp, + struct ksmbd_user *user) { return fp->tcon != tcon; } @@ -989,16 +997,74 @@ void ksmbd_stop_durable_scavenger(void) kthread_stop(server_conf.dh_task); } +/* + * ksmbd_vfs_copy_durable_owner - Copy owner info for durable reconnect + * @fp: ksmbd file pointer to store owner info + * @user: user pointer to copy from + * + * This function binds the current user's identity to the file handle + * to satisfy MS-SMB2 Step 8 (SecurityContext matching) during reconnect. + * + * Return: 0 on success, or negative error code on failure + */ +static int ksmbd_vfs_copy_durable_owner(struct ksmbd_file *fp, + struct ksmbd_user *user) +{ + if (!user) + return -EINVAL; + + /* Duplicate the user name to ensure identity persistence */ + fp->owner.name = kstrdup(user->name, GFP_KERNEL); + if (!fp->owner.name) + return -ENOMEM; + + fp->owner.uid = user->uid; + fp->owner.gid = user->gid; + + return 0; +} + +/** + * ksmbd_vfs_compare_durable_owner - Verify if the requester is original owner + * @fp: existing ksmbd file pointer + * @user: user pointer of the reconnect requester + * + * Compares the UID, GID, and name of the current requester against the + * original owner stored in the file handle. + * + * Return: true if the user matches, false otherwise + */ +bool ksmbd_vfs_compare_durable_owner(struct ksmbd_file *fp, + struct ksmbd_user *user) +{ + if (!user || !fp->owner.name) + return false; + + /* Check if the UID and GID match first (fast path) */ + if (fp->owner.uid != user->uid || fp->owner.gid != user->gid) + return false; + + /* Validate the account name to ensure the same SecurityContext */ + if (strcmp(fp->owner.name, user->name)) + return false; + + return true; +} + static bool session_fd_check(struct ksmbd_tree_connect *tcon, - struct ksmbd_file *fp) + struct ksmbd_file *fp, struct ksmbd_user *user) { struct ksmbd_inode *ci; struct oplock_info *op; struct ksmbd_conn *conn; + struct ksmbd_lock *smb_lock, *tmp_lock; if (!is_reconnectable(fp)) return false; + if (ksmbd_vfs_copy_durable_owner(fp, user)) + return false; + conn = fp->conn; ci = fp->f_ci; down_write(&ci->m_lock); @@ -1011,6 +1077,12 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon, } up_write(&ci->m_lock); + list_for_each_entry_safe(smb_lock, tmp_lock, &fp->lock_list, flist) { + spin_lock(&fp->conn->llist_lock); + list_del_init(&smb_lock->clist); + spin_unlock(&fp->conn->llist_lock); + } + fp->conn = NULL; fp->tcon = NULL; fp->volatile_id = KSMBD_NO_FID; @@ -1024,7 +1096,7 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon, void ksmbd_close_tree_conn_fds(struct ksmbd_work *work) { - int num = __close_file_table_ids(&work->sess->file_table, + int num = __close_file_table_ids(work->sess, work->tcon, tree_conn_fd_check); @@ -1033,7 +1105,7 @@ void ksmbd_close_tree_conn_fds(struct ksmbd_work *work) void ksmbd_close_session_fds(struct ksmbd_work *work) { - int num = __close_file_table_ids(&work->sess->file_table, + int num = __close_file_table_ids(work->sess, work->tcon, session_fd_check); @@ -1090,6 +1162,9 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp) { struct ksmbd_inode *ci; struct oplock_info *op; + struct ksmbd_conn *conn = work->conn; + struct ksmbd_lock *smb_lock; + unsigned int old_f_state; if (!fp->is_durable || fp->conn || fp->tcon) { pr_err("Invalid durable fd [%p:%p]\n", fp->conn, fp->tcon); @@ -1101,9 +1176,23 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp) return -EBADF; } - fp->conn = work->conn; + old_f_state = fp->f_state; + fp->f_state = FP_NEW; + __open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID); + if (!has_file_id(fp->volatile_id)) { + fp->f_state = old_f_state; + return -EBADF; + } + + fp->conn = conn; fp->tcon = work->tcon; + list_for_each_entry(smb_lock, &fp->lock_list, flist) { + spin_lock(&conn->llist_lock); + list_add_tail(&smb_lock->clist, &conn->lock_list); + spin_unlock(&conn->llist_lock); + } + ci = fp->f_ci; down_write(&ci->m_lock); list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) { @@ -1114,13 +1203,10 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp) } up_write(&ci->m_lock); - fp->f_state = FP_NEW; - __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; - } + fp->owner.uid = fp->owner.gid = 0; + kfree(fp->owner.name); + fp->owner.name = NULL; + return 0; } @@ -1135,12 +1221,14 @@ int ksmbd_init_file_table(struct ksmbd_file_table *ft) return 0; } -void ksmbd_destroy_file_table(struct ksmbd_file_table *ft) +void ksmbd_destroy_file_table(struct ksmbd_session *sess) { + struct ksmbd_file_table *ft = &sess->file_table; + if (!ft->idr) return; - __close_file_table_ids(ft, NULL, session_fd_check); + __close_file_table_ids(sess, NULL, session_fd_check); idr_destroy(ft->idr); kfree(ft->idr); ft->idr = NULL; diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h index 78b506c5ef03..866f32c10d4d 100644 --- a/fs/smb/server/vfs_cache.h +++ b/fs/smb/server/vfs_cache.h @@ -68,6 +68,13 @@ enum { FP_CLOSED }; +/* Owner information for durable handle reconnect */ +struct durable_owner { + unsigned int uid; + unsigned int gid; + char *name; +}; + struct ksmbd_file { struct file *filp; u64 persistent_id; @@ -114,6 +121,7 @@ struct ksmbd_file { bool is_resilient; bool is_posix_ctxt; + struct durable_owner owner; }; static inline void set_ctx_actor(struct dir_context *ctx, @@ -140,7 +148,7 @@ static inline bool ksmbd_stream_fd(struct ksmbd_file *fp) } int ksmbd_init_file_table(struct ksmbd_file_table *ft); -void ksmbd_destroy_file_table(struct ksmbd_file_table *ft); +void ksmbd_destroy_file_table(struct ksmbd_session *sess); int ksmbd_close_fd(struct ksmbd_work *work, u64 id); struct ksmbd_file *ksmbd_lookup_fd_fast(struct ksmbd_work *work, u64 id); struct ksmbd_file *ksmbd_lookup_foreign_fd(struct ksmbd_work *work, u64 id); @@ -166,6 +174,8 @@ void ksmbd_free_global_file_table(void); void ksmbd_set_fd_limit(unsigned long limit); void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp, unsigned int state); +bool ksmbd_vfs_compare_durable_owner(struct ksmbd_file *fp, + struct ksmbd_user *user); /* * INODE hash