Loading fs/ksmbd/smb2pdu.c +62 −56 Original line number Diff line number Diff line Loading @@ -835,10 +835,10 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn, build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt, conn->cipher_type); rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt); ctxt_size += sizeof(struct smb2_encryption_neg_context); ctxt_size += sizeof(struct smb2_encryption_neg_context) + 2; /* Round to 8 byte boundary */ pneg_ctxt += round_up(sizeof(struct smb2_encryption_neg_context), round_up(sizeof(struct smb2_encryption_neg_context) + 2, 8); } Loading @@ -850,9 +850,10 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn, build_compression_ctxt((struct smb2_compression_ctx *)pneg_ctxt, conn->compress_algorithm); rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt); ctxt_size += sizeof(struct smb2_compression_ctx); ctxt_size += sizeof(struct smb2_compression_ctx) + 2; /* Round to 8 byte boundary */ pneg_ctxt += round_up(sizeof(struct smb2_compression_ctx), 8); pneg_ctxt += round_up(sizeof(struct smb2_compression_ctx) + 2, 8); } if (conn->posix_ext_supported) { Loading Loading @@ -881,16 +882,23 @@ static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn, return err; } static int decode_encrypt_ctxt(struct ksmbd_conn *conn, struct smb2_encryption_neg_context *pneg_ctxt) static void decode_encrypt_ctxt(struct ksmbd_conn *conn, struct smb2_encryption_neg_context *pneg_ctxt, int len_of_ctxts) { int i; int cph_cnt = le16_to_cpu(pneg_ctxt->CipherCount); int i, cphs_size = cph_cnt * sizeof(__le16); conn->cipher_type = 0; if (sizeof(struct smb2_encryption_neg_context) + cphs_size > len_of_ctxts) { pr_err("Invalid cipher count(%d)\n", cph_cnt); return; } if (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION)) goto out; return; for (i = 0; i < cph_cnt; i++) { if (pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES128_GCM || Loading @@ -903,90 +911,88 @@ static int decode_encrypt_ctxt(struct ksmbd_conn *conn, break; } } out: /* * Return encrypt context size in request. * So need to plus extra number of ciphers size. */ return sizeof(struct smb2_encryption_neg_context) + ((cph_cnt - 1) * 2); } static int decode_compress_ctxt(struct ksmbd_conn *conn, static void decode_compress_ctxt(struct ksmbd_conn *conn, struct smb2_compression_ctx *pneg_ctxt) { int algo_cnt = le16_to_cpu(pneg_ctxt->CompressionAlgorithmCount); conn->compress_algorithm = SMB3_COMPRESS_NONE; /* * Return compression context size in request. * So need to plus extra number of CompressionAlgorithms size. */ return sizeof(struct smb2_compression_ctx) + ((algo_cnt - 1) * 2); } static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn, struct smb2_negotiate_req *req) { int i = 0; __le32 status = 0; /* +4 is to account for the RFC1001 len field */ char *pneg_ctxt = (char *)req + le32_to_cpu(req->NegotiateContextOffset) + 4; __le16 *ContextType = (__le16 *)pneg_ctxt; struct smb2_neg_context *pctx = (struct smb2_neg_context *)((char *)req + 4); int i = 0, len_of_ctxts; int offset = le32_to_cpu(req->NegotiateContextOffset); int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount); int ctxt_size; int len_of_smb = be32_to_cpu(req->hdr.smb2_buf_length); __le32 status = STATUS_INVALID_PARAMETER; ksmbd_debug(SMB, "decoding %d negotiate contexts\n", neg_ctxt_cnt); if (len_of_smb <= offset) { ksmbd_debug(SMB, "Invalid response: negotiate context offset\n"); return status; } len_of_ctxts = len_of_smb - offset; ksmbd_debug(SMB, "negotiate context count = %d\n", neg_ctxt_cnt); status = STATUS_INVALID_PARAMETER; while (i++ < neg_ctxt_cnt) { if (*ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES) { int clen; /* check that offset is not beyond end of SMB */ if (len_of_ctxts == 0) break; if (len_of_ctxts < sizeof(struct smb2_neg_context)) break; pctx = (struct smb2_neg_context *)((char *)pctx + offset); clen = le16_to_cpu(pctx->DataLength); if (clen + sizeof(struct smb2_neg_context) > len_of_ctxts) break; if (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES) { ksmbd_debug(SMB, "deassemble SMB2_PREAUTH_INTEGRITY_CAPABILITIES context\n"); if (conn->preauth_info->Preauth_HashId) break; status = decode_preauth_ctxt(conn, (struct smb2_preauth_neg_context *)pneg_ctxt); pneg_ctxt += DIV_ROUND_UP(sizeof(struct smb2_preauth_neg_context), 8) * 8; } else if (*ContextType == SMB2_ENCRYPTION_CAPABILITIES) { (struct smb2_preauth_neg_context *)pctx); if (status != STATUS_SUCCESS) break; } else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES) { ksmbd_debug(SMB, "deassemble SMB2_ENCRYPTION_CAPABILITIES context\n"); if (conn->cipher_type) break; ctxt_size = decode_encrypt_ctxt(conn, (struct smb2_encryption_neg_context *)pneg_ctxt); pneg_ctxt += DIV_ROUND_UP(ctxt_size, 8) * 8; } else if (*ContextType == SMB2_COMPRESSION_CAPABILITIES) { decode_encrypt_ctxt(conn, (struct smb2_encryption_neg_context *)pctx, len_of_ctxts); } else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES) { ksmbd_debug(SMB, "deassemble SMB2_COMPRESSION_CAPABILITIES context\n"); if (conn->compress_algorithm) break; ctxt_size = decode_compress_ctxt(conn, (struct smb2_compression_ctx *)pneg_ctxt); pneg_ctxt += DIV_ROUND_UP(ctxt_size, 8) * 8; } else if (*ContextType == SMB2_NETNAME_NEGOTIATE_CONTEXT_ID) { decode_compress_ctxt(conn, (struct smb2_compression_ctx *)pctx); } else if (pctx->ContextType == SMB2_NETNAME_NEGOTIATE_CONTEXT_ID) { ksmbd_debug(SMB, "deassemble SMB2_NETNAME_NEGOTIATE_CONTEXT_ID context\n"); ctxt_size = sizeof(struct smb2_netname_neg_context); ctxt_size += DIV_ROUND_UP(le16_to_cpu(((struct smb2_netname_neg_context *) pneg_ctxt)->DataLength), 8) * 8; pneg_ctxt += ctxt_size; } else if (*ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE) { } else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE) { ksmbd_debug(SMB, "deassemble SMB2_POSIX_EXTENSIONS_AVAILABLE context\n"); conn->posix_ext_supported = true; pneg_ctxt += DIV_ROUND_UP(sizeof(struct smb2_posix_neg_context), 8) * 8; } ContextType = (__le16 *)pneg_ctxt; if (status != STATUS_SUCCESS) break; /* offsets must be 8 byte aligned */ clen = (clen + 7) & ~0x7; offset = clen + sizeof(struct smb2_neg_context); len_of_ctxts -= clen + sizeof(struct smb2_neg_context); } return status; } Loading fs/ksmbd/smb2pdu.h +3 −3 Original line number Diff line number Diff line Loading @@ -299,7 +299,7 @@ struct smb2_encryption_neg_context { __le32 Reserved; /* CipherCount usally 2, but can be 3 when AES256-GCM enabled */ __le16 CipherCount; /* AES-128-GCM and AES-128-CCM by default */ __le16 Ciphers[1]; __le16 Ciphers[]; } __packed; #define SMB3_COMPRESS_NONE cpu_to_le16(0x0000) Loading @@ -314,7 +314,7 @@ struct smb2_compression_ctx { __le16 CompressionAlgorithmCount; __u16 Padding; __le32 Reserved1; __le16 CompressionAlgorithms[1]; __le16 CompressionAlgorithms[]; } __packed; #define POSIX_CTXT_DATA_LEN 16 Loading @@ -329,7 +329,7 @@ struct smb2_netname_neg_context { __le16 ContextType; /* 0x100 */ __le16 DataLength; __le32 Reserved; __le16 NetName[0]; /* hostname of target converted to UCS-2 */ __le16 NetName[]; /* hostname of target converted to UCS-2 */ } __packed; struct smb2_negotiate_rsp { Loading Loading
fs/ksmbd/smb2pdu.c +62 −56 Original line number Diff line number Diff line Loading @@ -835,10 +835,10 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn, build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt, conn->cipher_type); rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt); ctxt_size += sizeof(struct smb2_encryption_neg_context); ctxt_size += sizeof(struct smb2_encryption_neg_context) + 2; /* Round to 8 byte boundary */ pneg_ctxt += round_up(sizeof(struct smb2_encryption_neg_context), round_up(sizeof(struct smb2_encryption_neg_context) + 2, 8); } Loading @@ -850,9 +850,10 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn, build_compression_ctxt((struct smb2_compression_ctx *)pneg_ctxt, conn->compress_algorithm); rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt); ctxt_size += sizeof(struct smb2_compression_ctx); ctxt_size += sizeof(struct smb2_compression_ctx) + 2; /* Round to 8 byte boundary */ pneg_ctxt += round_up(sizeof(struct smb2_compression_ctx), 8); pneg_ctxt += round_up(sizeof(struct smb2_compression_ctx) + 2, 8); } if (conn->posix_ext_supported) { Loading Loading @@ -881,16 +882,23 @@ static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn, return err; } static int decode_encrypt_ctxt(struct ksmbd_conn *conn, struct smb2_encryption_neg_context *pneg_ctxt) static void decode_encrypt_ctxt(struct ksmbd_conn *conn, struct smb2_encryption_neg_context *pneg_ctxt, int len_of_ctxts) { int i; int cph_cnt = le16_to_cpu(pneg_ctxt->CipherCount); int i, cphs_size = cph_cnt * sizeof(__le16); conn->cipher_type = 0; if (sizeof(struct smb2_encryption_neg_context) + cphs_size > len_of_ctxts) { pr_err("Invalid cipher count(%d)\n", cph_cnt); return; } if (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION)) goto out; return; for (i = 0; i < cph_cnt; i++) { if (pneg_ctxt->Ciphers[i] == SMB2_ENCRYPTION_AES128_GCM || Loading @@ -903,90 +911,88 @@ static int decode_encrypt_ctxt(struct ksmbd_conn *conn, break; } } out: /* * Return encrypt context size in request. * So need to plus extra number of ciphers size. */ return sizeof(struct smb2_encryption_neg_context) + ((cph_cnt - 1) * 2); } static int decode_compress_ctxt(struct ksmbd_conn *conn, static void decode_compress_ctxt(struct ksmbd_conn *conn, struct smb2_compression_ctx *pneg_ctxt) { int algo_cnt = le16_to_cpu(pneg_ctxt->CompressionAlgorithmCount); conn->compress_algorithm = SMB3_COMPRESS_NONE; /* * Return compression context size in request. * So need to plus extra number of CompressionAlgorithms size. */ return sizeof(struct smb2_compression_ctx) + ((algo_cnt - 1) * 2); } static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn, struct smb2_negotiate_req *req) { int i = 0; __le32 status = 0; /* +4 is to account for the RFC1001 len field */ char *pneg_ctxt = (char *)req + le32_to_cpu(req->NegotiateContextOffset) + 4; __le16 *ContextType = (__le16 *)pneg_ctxt; struct smb2_neg_context *pctx = (struct smb2_neg_context *)((char *)req + 4); int i = 0, len_of_ctxts; int offset = le32_to_cpu(req->NegotiateContextOffset); int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount); int ctxt_size; int len_of_smb = be32_to_cpu(req->hdr.smb2_buf_length); __le32 status = STATUS_INVALID_PARAMETER; ksmbd_debug(SMB, "decoding %d negotiate contexts\n", neg_ctxt_cnt); if (len_of_smb <= offset) { ksmbd_debug(SMB, "Invalid response: negotiate context offset\n"); return status; } len_of_ctxts = len_of_smb - offset; ksmbd_debug(SMB, "negotiate context count = %d\n", neg_ctxt_cnt); status = STATUS_INVALID_PARAMETER; while (i++ < neg_ctxt_cnt) { if (*ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES) { int clen; /* check that offset is not beyond end of SMB */ if (len_of_ctxts == 0) break; if (len_of_ctxts < sizeof(struct smb2_neg_context)) break; pctx = (struct smb2_neg_context *)((char *)pctx + offset); clen = le16_to_cpu(pctx->DataLength); if (clen + sizeof(struct smb2_neg_context) > len_of_ctxts) break; if (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES) { ksmbd_debug(SMB, "deassemble SMB2_PREAUTH_INTEGRITY_CAPABILITIES context\n"); if (conn->preauth_info->Preauth_HashId) break; status = decode_preauth_ctxt(conn, (struct smb2_preauth_neg_context *)pneg_ctxt); pneg_ctxt += DIV_ROUND_UP(sizeof(struct smb2_preauth_neg_context), 8) * 8; } else if (*ContextType == SMB2_ENCRYPTION_CAPABILITIES) { (struct smb2_preauth_neg_context *)pctx); if (status != STATUS_SUCCESS) break; } else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES) { ksmbd_debug(SMB, "deassemble SMB2_ENCRYPTION_CAPABILITIES context\n"); if (conn->cipher_type) break; ctxt_size = decode_encrypt_ctxt(conn, (struct smb2_encryption_neg_context *)pneg_ctxt); pneg_ctxt += DIV_ROUND_UP(ctxt_size, 8) * 8; } else if (*ContextType == SMB2_COMPRESSION_CAPABILITIES) { decode_encrypt_ctxt(conn, (struct smb2_encryption_neg_context *)pctx, len_of_ctxts); } else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES) { ksmbd_debug(SMB, "deassemble SMB2_COMPRESSION_CAPABILITIES context\n"); if (conn->compress_algorithm) break; ctxt_size = decode_compress_ctxt(conn, (struct smb2_compression_ctx *)pneg_ctxt); pneg_ctxt += DIV_ROUND_UP(ctxt_size, 8) * 8; } else if (*ContextType == SMB2_NETNAME_NEGOTIATE_CONTEXT_ID) { decode_compress_ctxt(conn, (struct smb2_compression_ctx *)pctx); } else if (pctx->ContextType == SMB2_NETNAME_NEGOTIATE_CONTEXT_ID) { ksmbd_debug(SMB, "deassemble SMB2_NETNAME_NEGOTIATE_CONTEXT_ID context\n"); ctxt_size = sizeof(struct smb2_netname_neg_context); ctxt_size += DIV_ROUND_UP(le16_to_cpu(((struct smb2_netname_neg_context *) pneg_ctxt)->DataLength), 8) * 8; pneg_ctxt += ctxt_size; } else if (*ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE) { } else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE) { ksmbd_debug(SMB, "deassemble SMB2_POSIX_EXTENSIONS_AVAILABLE context\n"); conn->posix_ext_supported = true; pneg_ctxt += DIV_ROUND_UP(sizeof(struct smb2_posix_neg_context), 8) * 8; } ContextType = (__le16 *)pneg_ctxt; if (status != STATUS_SUCCESS) break; /* offsets must be 8 byte aligned */ clen = (clen + 7) & ~0x7; offset = clen + sizeof(struct smb2_neg_context); len_of_ctxts -= clen + sizeof(struct smb2_neg_context); } return status; } Loading
fs/ksmbd/smb2pdu.h +3 −3 Original line number Diff line number Diff line Loading @@ -299,7 +299,7 @@ struct smb2_encryption_neg_context { __le32 Reserved; /* CipherCount usally 2, but can be 3 when AES256-GCM enabled */ __le16 CipherCount; /* AES-128-GCM and AES-128-CCM by default */ __le16 Ciphers[1]; __le16 Ciphers[]; } __packed; #define SMB3_COMPRESS_NONE cpu_to_le16(0x0000) Loading @@ -314,7 +314,7 @@ struct smb2_compression_ctx { __le16 CompressionAlgorithmCount; __u16 Padding; __le32 Reserved1; __le16 CompressionAlgorithms[1]; __le16 CompressionAlgorithms[]; } __packed; #define POSIX_CTXT_DATA_LEN 16 Loading @@ -329,7 +329,7 @@ struct smb2_netname_neg_context { __le16 ContextType; /* 0x100 */ __le16 DataLength; __le32 Reserved; __le16 NetName[0]; /* hostname of target converted to UCS-2 */ __le16 NetName[]; /* hostname of target converted to UCS-2 */ } __packed; struct smb2_negotiate_rsp { Loading