smb: client: fix "df: Resource temporarily unavailable" on 5.15 stable kernel
Subsystems (3)
cover smb: client: fix "df: Resource temporarily unavailable" on 5.15 stable kernel
ATTENTION!
Before applying this patch a conflict patch in the queue needs to be removed:
https://git.kernel.org/pub/scm/linux/kernel/git/stable/stable-queue.git/tree/queue-5.15/cifs-fix-off-by-one-in-smb2_query_info_init.patch
Describe bug:
After mounting a remote cifs resource, it becomes unavailable:
df: /mnt/sambashare: Resource temporarily unavailable It was tested on the following Linux kernel:
Linux altlinux 5.15.148
The error appeared starting from kernel 5.15.147 after adding the commit [1] "smb: client: fix OOB in SMB2_query_info_init()", in which the buffer length increases by 1 as a result of changes:
.
- iov[0].iov_len = total_len - 1 + input_len;
+ iov[0].iov_len = len;
.
[1] https://patchwork.kernel.org/project/cifs-client/patch/[email protected]/
Error fixed by backported commit in next patch adapted for the 5.15 kernel:
[PATCH 5.15.y 1/1] smb3: Replace smb2pdu 1-element arrays with flex-arrays
P.S.
I have already backported similar changes for the 5.10.y kernel [2], but I did not know that there was the same error on 5.15,
since I only deal with kernels 5.10 and 6.1.
Therefore, this patch is to follow the rules of backport to stable branches.
[2] https://lore.kernel.org/all/2024012613-woozy-exhume-7b9d@gregkh/T/
PATCH 1/1 smb3: Replace smb2pdu 1-element arrays with flex-arrays
From: Kees Cook <[email protected]>
commit eb3e28c1e89b4984308777231887e41aa8a0151f upstream.
The kernel is globally removing the ambiguous 0-length and 1-element arrays in favor of flexible arrays, so that we can gain both compile-time and run-time array bounds checking[1].
Replace the trailing 1-element array with a flexible array in the following structures:
struct smb2_err_rsp
struct smb2_tree_connect_req
struct smb2_negotiate_rsp
struct smb2_sess_setup_req
struct smb2_sess_setup_rsp
struct smb2_read_req
struct smb2_read_rsp
struct smb2_write_req
struct smb2_write_rsp
struct smb2_query_directory_req
struct smb2_query_directory_rsp
struct smb2_set_info_req
struct smb2_change_notify_rsp
struct smb2_create_rsp
struct smb2_query_info_req
struct smb2_query_info_rsp
Replace the trailing 1-element array with a flexible array, but leave the existing structure padding:
struct smb2_file_all_info
struct smb2_lock_req
Adjust all related size calculations to match the changes to sizeof().
No machine code output or .data section differences are produced after these changes.
[1] For lots of details, see both:
https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays
https://people.kernel.org/kees/bounded-flexible-arrays-in-c
--- fs/cifs/smb2misc.c | 2 +- fs/cifs/smb2ops.c | 14 +++++++------- fs/cifs/smb2pdu.c | 13 ++++++------- fs/cifs/smb2pdu.h | 42 ++++++++++++++++++++++++------------------ 4 files changed, 38 insertions(+), 33 deletions(-)
fs/cifs/smb2misc.c +1 -1
@@ -113,7 +113,7 @@ static __u32 get_neg_ctxt_len(struct smb2_sync_hdr *hdr, __u32 len, }else if (nc_offset +1 == non_ctxlen) {cifs_dbg (FYI ,"no SPNEGO security blob in negprot rsp\n" ); size_of_pad_before_neg_ctxts =0 ; - }else if (non_ctxlen ==SMB311_NEGPROT_BASE_SIZE ) + }else if (non_ctxlen ==SMB311_NEGPROT_BASE_SIZE +1 )/* has padding, but no SPNEGO blob */ size_of_pad_before_neg_ctxts = nc_offset - non_ctxlen +1 ;else
fs/cifs/smb2ops.c +7 -7
@@ -5826,7 +5826,7 @@ struct smb_version_values smb20_values = { .header_size = sizeof(struct smb2_sync_hdr), .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, - .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, + .read_rsp_size = sizeof(struct smb2_read_rsp), .lock_cmd = SMB2_LOCK, .cap_unix = 0, .cap_nt_find = SMB2_NT_FIND,
@@ -5848,7 +5848,7 @@ struct smb_version_values smb21_values = { .header_size = sizeof(struct smb2_sync_hdr), .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, - .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, + .read_rsp_size = sizeof(struct smb2_read_rsp), .lock_cmd = SMB2_LOCK, .cap_unix = 0, .cap_nt_find = SMB2_NT_FIND,
@@ -5869,7 +5869,7 @@ struct smb_version_values smb3any_values = { .header_size = sizeof(struct smb2_sync_hdr), .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, - .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, + .read_rsp_size = sizeof(struct smb2_read_rsp), .lock_cmd = SMB2_LOCK, .cap_unix = 0, .cap_nt_find = SMB2_NT_FIND,
@@ -5890,7 +5890,7 @@ struct smb_version_values smbdefault_values = { .header_size = sizeof(struct smb2_sync_hdr), .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, - .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, + .read_rsp_size = sizeof(struct smb2_read_rsp), .lock_cmd = SMB2_LOCK, .cap_unix = 0, .cap_nt_find = SMB2_NT_FIND,
@@ -5911,7 +5911,7 @@ struct smb_version_values smb30_values = { .header_size = sizeof(struct smb2_sync_hdr), .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, - .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, + .read_rsp_size = sizeof(struct smb2_read_rsp), .lock_cmd = SMB2_LOCK, .cap_unix = 0, .cap_nt_find = SMB2_NT_FIND,
@@ -5932,7 +5932,7 @@ struct smb_version_values smb302_values = { .header_size = sizeof(struct smb2_sync_hdr), .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, - .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, + .read_rsp_size = sizeof(struct smb2_read_rsp), .lock_cmd = SMB2_LOCK, .cap_unix = 0, .cap_nt_find = SMB2_NT_FIND,
@@ -5953,7 +5953,7 @@ struct smb_version_values smb311_values = { .header_size = sizeof(struct smb2_sync_hdr), .header_preamble_size = 0, .max_header_size = MAX_SMB2_HDR_SIZE, - .read_rsp_size = sizeof(struct smb2_read_rsp) - 1, + .read_rsp_size = sizeof(struct smb2_read_rsp), .lock_cmd = SMB2_LOCK, .cap_unix = 0, .cap_nt_find = SMB2_NT_FIND,
fs/cifs/smb2pdu.c +6 -7
@@ -1327,7 +1327,7 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)/* Testing shows that buffer offset must be at location of Buffer[0] */ req->SecurityBufferOffset = -cpu_to_le16 (sizeof (struct smb2_sess_setup_req ) -1 /* pad */ ); +cpu_to_le16 (sizeof (struct smb2_sess_setup_req )); req->SecurityBufferLength =cpu_to_le16 (sess_data->iov[1 ].iov_len);memset (&rqst,0 ,sizeof (struct smb_rqst ));
@@ -1826,8 +1826,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, iov[0 ].iov_len = total_len -1 ;/* Testing shows that buffer offset must be at location of Buffer[0] */ - req->PathOffset =cpu_to_le16 (sizeof (struct smb2_tree_connect_req ) - -1 /* pad */ ); + req->PathOffset =cpu_to_le16 (sizeof (struct smb2_tree_connect_req )); req->PathLength =cpu_to_le16 (unc_path_len -2 ); iov[1 ].iov_base = unc_path; iov[1 ].iov_len = unc_path_len;
@@ -4748,7 +4747,7 @@ int SMB2_query_directory_init(const unsigned int xid,memcpy (bufptr, &asteriks, len); req->FileNameOffset = -cpu_to_le16 (sizeof (struct smb2_query_directory_req ) -1 ); +cpu_to_le16 (sizeof (struct smb2_query_directory_req )); req->FileNameLength =cpu_to_le16 (len);/* * BB could be 30 bytes or so longer if we used SMB2 specific
@@ -4945,7 +4944,7 @@ SMB2_set_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, req->AdditionalInformation =cpu_to_le32 (additional_info); req->BufferOffset = -cpu_to_le16 (sizeof (struct smb2_set_info_req ) -1 ); +cpu_to_le16 (sizeof (struct smb2_set_info_req )); req->BufferLength =cpu_to_le32 (*size);memcpy (req->Buffer, *data, *size);
@@ -5177,9 +5176,9 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, req->VolatileFileId = volatile_fid;/* 1 for pad */ req->InputBufferOffset = -cpu_to_le16 (sizeof (struct smb2_query_info_req ) -1 ); +cpu_to_le16 (sizeof (struct smb2_query_info_req )); req->OutputBufferLength =cpu_to_le32 ( - outbuf_len +sizeof (struct smb2_query_info_rsp ) -1 ); + outbuf_len +sizeof (struct smb2_query_info_rsp )); iov->iov_base = (char *)req; iov->iov_len = total_len;
fs/cifs/smb2pdu.h +24 -18
150 lines not on this page · raw message
Signature · 1 line
2.33.8