From e009cb1e3093977c5b96a1c6697a7dc9332222d5 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 14 Oct 2025 16:17:57 -0700 Subject: [PATCH 01/44] ksmbd: Use SHA-512 library for SMB3.1.1 preauth hash Convert ksmbd_gen_preauth_integrity_hash() to use the SHA-512 library instead of a "sha512" crypto_shash. This is simpler and faster. With the library there's no need to allocate memory, no need to handle errors, and the SHA-512 code is accessed directly without inefficient indirect calls and other unnecessary API overhead. Signed-off-by: Eric Biggers Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/Kconfig | 2 +- fs/smb/server/auth.c | 41 +++++++------------------------------- fs/smb/server/crypto_ctx.c | 8 -------- fs/smb/server/crypto_ctx.h | 4 ---- fs/smb/server/server.c | 1 - 5 files changed, 8 insertions(+), 48 deletions(-) diff --git a/fs/smb/server/Kconfig b/fs/smb/server/Kconfig index 098cac98d31e..d5f3a417246d 100644 --- a/fs/smb/server/Kconfig +++ b/fs/smb/server/Kconfig @@ -13,9 +13,9 @@ config SMB_SERVER select CRYPTO_LIB_ARC4 select CRYPTO_LIB_DES select CRYPTO_LIB_SHA256 + select CRYPTO_LIB_SHA512 select CRYPTO_SHA256 select CRYPTO_CMAC - select CRYPTO_SHA512 select CRYPTO_AEAD2 select CRYPTO_CCM select CRYPTO_GCM diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c index b4020bb55a26..b7f2feede221 100644 --- a/fs/smb/server/auth.c +++ b/fs/smb/server/auth.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -934,48 +935,20 @@ int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn, int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf, __u8 *pi_hash) { - int rc; struct smb2_hdr *rcv_hdr = smb2_get_msg(buf); char *all_bytes_msg = (char *)&rcv_hdr->ProtocolId; int msg_size = get_rfc1002_len(buf); - struct ksmbd_crypto_ctx *ctx = NULL; + struct sha512_ctx sha_ctx; if (conn->preauth_info->Preauth_HashId != SMB2_PREAUTH_INTEGRITY_SHA512) return -EINVAL; - ctx = ksmbd_crypto_ctx_find_sha512(); - if (!ctx) { - ksmbd_debug(AUTH, "could not alloc sha512\n"); - return -ENOMEM; - } - - rc = crypto_shash_init(CRYPTO_SHA512(ctx)); - if (rc) { - ksmbd_debug(AUTH, "could not init shashn"); - goto out; - } - - rc = crypto_shash_update(CRYPTO_SHA512(ctx), pi_hash, 64); - if (rc) { - ksmbd_debug(AUTH, "could not update with n\n"); - goto out; - } - - rc = crypto_shash_update(CRYPTO_SHA512(ctx), all_bytes_msg, msg_size); - if (rc) { - ksmbd_debug(AUTH, "could not update with n\n"); - goto out; - } - - rc = crypto_shash_final(CRYPTO_SHA512(ctx), pi_hash); - if (rc) { - ksmbd_debug(AUTH, "Could not generate hash err : %d\n", rc); - goto out; - } -out: - ksmbd_release_crypto_ctx(ctx); - return rc; + sha512_init(&sha_ctx); + sha512_update(&sha_ctx, pi_hash, 64); + sha512_update(&sha_ctx, all_bytes_msg, msg_size); + sha512_final(&sha_ctx, pi_hash); + return 0; } static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id, diff --git a/fs/smb/server/crypto_ctx.c b/fs/smb/server/crypto_ctx.c index 80bd68c8635e..1de41b10528b 100644 --- a/fs/smb/server/crypto_ctx.c +++ b/fs/smb/server/crypto_ctx.c @@ -75,9 +75,6 @@ static struct shash_desc *alloc_shash_desc(int id) case CRYPTO_SHASH_CMACAES: tfm = crypto_alloc_shash("cmac(aes)", 0, 0); break; - case CRYPTO_SHASH_SHA512: - tfm = crypto_alloc_shash("sha512", 0, 0); - break; default: return NULL; } @@ -195,11 +192,6 @@ struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void) return ____crypto_shash_ctx_find(CRYPTO_SHASH_CMACAES); } -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_sha512(void) -{ - return ____crypto_shash_ctx_find(CRYPTO_SHASH_SHA512); -} - static struct ksmbd_crypto_ctx *____crypto_aead_ctx_find(int id) { struct ksmbd_crypto_ctx *ctx; diff --git a/fs/smb/server/crypto_ctx.h b/fs/smb/server/crypto_ctx.h index ac64801d52d3..4e8954acd8b8 100644 --- a/fs/smb/server/crypto_ctx.h +++ b/fs/smb/server/crypto_ctx.h @@ -13,7 +13,6 @@ enum { CRYPTO_SHASH_HMACMD5 = 0, CRYPTO_SHASH_HMACSHA256, CRYPTO_SHASH_CMACAES, - CRYPTO_SHASH_SHA512, CRYPTO_SHASH_MAX, }; @@ -38,13 +37,11 @@ struct ksmbd_crypto_ctx { #define CRYPTO_HMACMD5(c) ((c)->desc[CRYPTO_SHASH_HMACMD5]) #define CRYPTO_HMACSHA256(c) ((c)->desc[CRYPTO_SHASH_HMACSHA256]) #define CRYPTO_CMACAES(c) ((c)->desc[CRYPTO_SHASH_CMACAES]) -#define CRYPTO_SHA512(c) ((c)->desc[CRYPTO_SHASH_SHA512]) #define CRYPTO_HMACMD5_TFM(c) ((c)->desc[CRYPTO_SHASH_HMACMD5]->tfm) #define CRYPTO_HMACSHA256_TFM(c)\ ((c)->desc[CRYPTO_SHASH_HMACSHA256]->tfm) #define CRYPTO_CMACAES_TFM(c) ((c)->desc[CRYPTO_SHASH_CMACAES]->tfm) -#define CRYPTO_SHA512_TFM(c) ((c)->desc[CRYPTO_SHASH_SHA512]->tfm) #define CRYPTO_GCM(c) ((c)->ccmaes[CRYPTO_AEAD_AES_GCM]) #define CRYPTO_CCM(c) ((c)->ccmaes[CRYPTO_AEAD_AES_CCM]) @@ -53,7 +50,6 @@ void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx); struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacmd5(void); struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacsha256(void); struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void); -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_sha512(void); struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_gcm(void); struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_ccm(void); void ksmbd_crypto_destroy(void); diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c index 40420544cc25..51e2aee2a698 100644 --- a/fs/smb/server/server.c +++ b/fs/smb/server/server.c @@ -628,7 +628,6 @@ MODULE_SOFTDEP("pre: nls"); MODULE_SOFTDEP("pre: aes"); MODULE_SOFTDEP("pre: cmac"); MODULE_SOFTDEP("pre: sha256"); -MODULE_SOFTDEP("pre: sha512"); MODULE_SOFTDEP("pre: aead2"); MODULE_SOFTDEP("pre: ccm"); MODULE_SOFTDEP("pre: gcm"); From 924067ef183bd17f39d790752190f99982524598 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 14 Oct 2025 16:17:58 -0700 Subject: [PATCH 02/44] ksmbd: Use HMAC-SHA256 library for message signing and key generation Convert ksmbd_sign_smb2_pdu() and generate_key() to use the HMAC-SHA256 library instead of a "hmac(sha256)" crypto_shash. This is simpler and faster. With the library there's no need to allocate memory, no need to handle errors, and the HMAC-SHA256 code is accessed directly without inefficient indirect calls and other unnecessary API overhead. Signed-off-by: Eric Biggers Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/Kconfig | 1 - fs/smb/server/auth.c | 176 ++++++++----------------------------- fs/smb/server/auth.h | 10 +-- fs/smb/server/crypto_ctx.c | 8 -- fs/smb/server/crypto_ctx.h | 5 -- fs/smb/server/server.c | 1 - fs/smb/server/smb2pdu.c | 25 ++---- fs/smb/server/smb_common.h | 2 +- 8 files changed, 52 insertions(+), 176 deletions(-) diff --git a/fs/smb/server/Kconfig b/fs/smb/server/Kconfig index d5f3a417246d..788104cfb082 100644 --- a/fs/smb/server/Kconfig +++ b/fs/smb/server/Kconfig @@ -14,7 +14,6 @@ config SMB_SERVER select CRYPTO_LIB_DES select CRYPTO_LIB_SHA256 select CRYPTO_LIB_SHA512 - select CRYPTO_SHA256 select CRYPTO_CMAC select CRYPTO_AEAD2 select CRYPTO_CCM diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c index b7f2feede221..54918f43d2c6 100644 --- a/fs/smb/server/auth.c +++ b/fs/smb/server/auth.c @@ -590,46 +590,16 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob, * @sig: signature value generated for client request packet * */ -int ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, - int n_vec, char *sig) +void ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, + int n_vec, char *sig) { - struct ksmbd_crypto_ctx *ctx; - int rc, i; + struct hmac_sha256_ctx ctx; + int i; - ctx = ksmbd_crypto_ctx_find_hmacsha256(); - if (!ctx) { - ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n"); - return -ENOMEM; - } - - rc = crypto_shash_setkey(CRYPTO_HMACSHA256_TFM(ctx), - key, - SMB2_NTLMV2_SESSKEY_SIZE); - if (rc) - goto out; - - rc = crypto_shash_init(CRYPTO_HMACSHA256(ctx)); - if (rc) { - ksmbd_debug(AUTH, "hmacsha256 init error %d\n", rc); - goto out; - } - - for (i = 0; i < n_vec; i++) { - rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), - iov[i].iov_base, - iov[i].iov_len); - if (rc) { - ksmbd_debug(AUTH, "hmacsha256 update error %d\n", rc); - goto out; - } - } - - rc = crypto_shash_final(CRYPTO_HMACSHA256(ctx), sig); - if (rc) - ksmbd_debug(AUTH, "hmacsha256 generation error %d\n", rc); -out: - ksmbd_release_crypto_ctx(ctx); - return rc; + hmac_sha256_init_usingrawkey(&ctx, key, SMB2_NTLMV2_SESSKEY_SIZE); + for (i = 0; i < n_vec; i++) + hmac_sha256_update(&ctx, iov[i].iov_base, iov[i].iov_len); + hmac_sha256_final(&ctx, sig); } /** @@ -689,98 +659,39 @@ struct derivation { bool binding; }; -static int generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess, - struct kvec label, struct kvec context, __u8 *key, - unsigned int key_size) +static void generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess, + struct kvec label, struct kvec context, __u8 *key, + unsigned int key_size) { unsigned char zero = 0x0; __u8 i[4] = {0, 0, 0, 1}; __u8 L128[4] = {0, 0, 0, 128}; __u8 L256[4] = {0, 0, 1, 0}; - int rc; unsigned char prfhash[SMB2_HMACSHA256_SIZE]; - unsigned char *hashptr = prfhash; - struct ksmbd_crypto_ctx *ctx; + struct hmac_sha256_ctx ctx; - memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); - memset(key, 0x0, key_size); - - ctx = ksmbd_crypto_ctx_find_hmacsha256(); - if (!ctx) { - ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n"); - return -ENOMEM; - } - - rc = crypto_shash_setkey(CRYPTO_HMACSHA256_TFM(ctx), - sess->sess_key, - SMB2_NTLMV2_SESSKEY_SIZE); - if (rc) - goto smb3signkey_ret; - - rc = crypto_shash_init(CRYPTO_HMACSHA256(ctx)); - if (rc) { - ksmbd_debug(AUTH, "hmacsha256 init error %d\n", rc); - goto smb3signkey_ret; - } - - rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), i, 4); - if (rc) { - ksmbd_debug(AUTH, "could not update with n\n"); - goto smb3signkey_ret; - } - - rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), - label.iov_base, - label.iov_len); - if (rc) { - ksmbd_debug(AUTH, "could not update with label\n"); - goto smb3signkey_ret; - } - - rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), &zero, 1); - if (rc) { - ksmbd_debug(AUTH, "could not update with zero\n"); - goto smb3signkey_ret; - } - - rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), - context.iov_base, - context.iov_len); - if (rc) { - ksmbd_debug(AUTH, "could not update with context\n"); - goto smb3signkey_ret; - } + hmac_sha256_init_usingrawkey(&ctx, sess->sess_key, + SMB2_NTLMV2_SESSKEY_SIZE); + hmac_sha256_update(&ctx, i, 4); + hmac_sha256_update(&ctx, label.iov_base, label.iov_len); + hmac_sha256_update(&ctx, &zero, 1); + hmac_sha256_update(&ctx, context.iov_base, context.iov_len); if (key_size == SMB3_ENC_DEC_KEY_SIZE && (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) - rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L256, 4); + hmac_sha256_update(&ctx, L256, 4); else - rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L128, 4); - if (rc) { - ksmbd_debug(AUTH, "could not update with L\n"); - goto smb3signkey_ret; - } + hmac_sha256_update(&ctx, L128, 4); - rc = crypto_shash_final(CRYPTO_HMACSHA256(ctx), hashptr); - if (rc) { - ksmbd_debug(AUTH, "Could not generate hmacmd5 hash error %d\n", - rc); - goto smb3signkey_ret; - } - - memcpy(key, hashptr, key_size); - -smb3signkey_ret: - ksmbd_release_crypto_ctx(ctx); - return rc; + hmac_sha256_final(&ctx, prfhash); + memcpy(key, prfhash, key_size); } static int generate_smb3signingkey(struct ksmbd_session *sess, struct ksmbd_conn *conn, const struct derivation *signing) { - int rc; struct channel *chann; char *key; @@ -793,10 +704,8 @@ static int generate_smb3signingkey(struct ksmbd_session *sess, else key = sess->smb3signingkey; - rc = generate_key(conn, sess, signing->label, signing->context, key, - SMB3_SIGN_KEY_SIZE); - if (rc) - return rc; + generate_key(conn, sess, signing->label, signing->context, key, + SMB3_SIGN_KEY_SIZE); if (!(conn->dialect >= SMB30_PROT_ID && signing->binding)) memcpy(chann->smb3signingkey, key, SMB3_SIGN_KEY_SIZE); @@ -852,23 +761,17 @@ struct derivation_twin { struct derivation decryption; }; -static int generate_smb3encryptionkey(struct ksmbd_conn *conn, - struct ksmbd_session *sess, - const struct derivation_twin *ptwin) +static void generate_smb3encryptionkey(struct ksmbd_conn *conn, + struct ksmbd_session *sess, + const struct derivation_twin *ptwin) { - int rc; + generate_key(conn, sess, ptwin->encryption.label, + ptwin->encryption.context, sess->smb3encryptionkey, + SMB3_ENC_DEC_KEY_SIZE); - rc = generate_key(conn, sess, ptwin->encryption.label, - ptwin->encryption.context, sess->smb3encryptionkey, - SMB3_ENC_DEC_KEY_SIZE); - if (rc) - return rc; - - rc = generate_key(conn, sess, ptwin->decryption.label, - ptwin->decryption.context, - sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE); - if (rc) - return rc; + generate_key(conn, sess, ptwin->decryption.label, + ptwin->decryption.context, + sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE); ksmbd_debug(AUTH, "dumping generated AES encryption keys\n"); ksmbd_debug(AUTH, "Cipher type %d\n", conn->cipher_type); @@ -887,11 +790,10 @@ static int generate_smb3encryptionkey(struct ksmbd_conn *conn, ksmbd_debug(AUTH, "ServerOut Key %*ph\n", SMB3_GCM128_CRYPTKEY_SIZE, sess->smb3decryptionkey); } - return 0; } -int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn, - struct ksmbd_session *sess) +void ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn, + struct ksmbd_session *sess) { struct derivation_twin twin; struct derivation *d; @@ -908,11 +810,11 @@ int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn, d->context.iov_base = "ServerIn "; d->context.iov_len = 10; - return generate_smb3encryptionkey(conn, sess, &twin); + generate_smb3encryptionkey(conn, sess, &twin); } -int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn, - struct ksmbd_session *sess) +void ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn, + struct ksmbd_session *sess) { struct derivation_twin twin; struct derivation *d; @@ -929,7 +831,7 @@ int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn, d->context.iov_base = sess->Preauth_HashValue; d->context.iov_len = 64; - return generate_smb3encryptionkey(conn, sess, &twin); + generate_smb3encryptionkey(conn, sess, &twin); } int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf, diff --git a/fs/smb/server/auth.h b/fs/smb/server/auth.h index 6879a1bd1b91..6d351d61b0e5 100644 --- a/fs/smb/server/auth.h +++ b/fs/smb/server/auth.h @@ -52,18 +52,18 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob, struct ksmbd_conn *conn); int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob, int in_len, char *out_blob, int *out_len); -int ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, - int n_vec, char *sig); +void ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, + int n_vec, char *sig); int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, int n_vec, char *sig); int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess, struct ksmbd_conn *conn); int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess, struct ksmbd_conn *conn); -int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn, - struct ksmbd_session *sess); -int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn, +void ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn, struct ksmbd_session *sess); +void ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn, + struct ksmbd_session *sess); int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf, __u8 *pi_hash); #endif diff --git a/fs/smb/server/crypto_ctx.c b/fs/smb/server/crypto_ctx.c index 1de41b10528b..a5ec22ba8ae3 100644 --- a/fs/smb/server/crypto_ctx.c +++ b/fs/smb/server/crypto_ctx.c @@ -69,9 +69,6 @@ static struct shash_desc *alloc_shash_desc(int id) case CRYPTO_SHASH_HMACMD5: tfm = crypto_alloc_shash("hmac(md5)", 0, 0); break; - case CRYPTO_SHASH_HMACSHA256: - tfm = crypto_alloc_shash("hmac(sha256)", 0, 0); - break; case CRYPTO_SHASH_CMACAES: tfm = crypto_alloc_shash("cmac(aes)", 0, 0); break; @@ -182,11 +179,6 @@ struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacmd5(void) return ____crypto_shash_ctx_find(CRYPTO_SHASH_HMACMD5); } -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacsha256(void) -{ - return ____crypto_shash_ctx_find(CRYPTO_SHASH_HMACSHA256); -} - struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void) { return ____crypto_shash_ctx_find(CRYPTO_SHASH_CMACAES); diff --git a/fs/smb/server/crypto_ctx.h b/fs/smb/server/crypto_ctx.h index 4e8954acd8b8..c571d65a16f3 100644 --- a/fs/smb/server/crypto_ctx.h +++ b/fs/smb/server/crypto_ctx.h @@ -11,7 +11,6 @@ enum { CRYPTO_SHASH_HMACMD5 = 0, - CRYPTO_SHASH_HMACSHA256, CRYPTO_SHASH_CMACAES, CRYPTO_SHASH_MAX, }; @@ -35,12 +34,9 @@ struct ksmbd_crypto_ctx { }; #define CRYPTO_HMACMD5(c) ((c)->desc[CRYPTO_SHASH_HMACMD5]) -#define CRYPTO_HMACSHA256(c) ((c)->desc[CRYPTO_SHASH_HMACSHA256]) #define CRYPTO_CMACAES(c) ((c)->desc[CRYPTO_SHASH_CMACAES]) #define CRYPTO_HMACMD5_TFM(c) ((c)->desc[CRYPTO_SHASH_HMACMD5]->tfm) -#define CRYPTO_HMACSHA256_TFM(c)\ - ((c)->desc[CRYPTO_SHASH_HMACSHA256]->tfm) #define CRYPTO_CMACAES_TFM(c) ((c)->desc[CRYPTO_SHASH_CMACAES]->tfm) #define CRYPTO_GCM(c) ((c)->ccmaes[CRYPTO_AEAD_AES_GCM]) @@ -48,7 +44,6 @@ struct ksmbd_crypto_ctx { void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx); struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacmd5(void); -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacsha256(void); struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void); struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_gcm(void); struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_ccm(void); diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c index 51e2aee2a698..8bce97633e01 100644 --- a/fs/smb/server/server.c +++ b/fs/smb/server/server.c @@ -627,7 +627,6 @@ MODULE_SOFTDEP("pre: md5"); MODULE_SOFTDEP("pre: nls"); MODULE_SOFTDEP("pre: aes"); MODULE_SOFTDEP("pre: cmac"); -MODULE_SOFTDEP("pre: sha256"); MODULE_SOFTDEP("pre: aead2"); MODULE_SOFTDEP("pre: ccm"); MODULE_SOFTDEP("pre: gcm"); diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index f901ae18e68a..17ce41fb9995 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -1538,12 +1538,7 @@ static int ntlm_authenticate(struct ksmbd_work *work, if (smb3_encryption_negotiated(conn) && !(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) { - rc = conn->ops->generate_encryptionkey(conn, sess); - if (rc) { - ksmbd_debug(SMB, - "SMB3 encryption key generation failed\n"); - return -EINVAL; - } + conn->ops->generate_encryptionkey(conn, sess); sess->enc = true; if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION) rsp->SessionFlags = SMB2_SESSION_FLAG_ENCRYPT_DATA_LE; @@ -1640,12 +1635,7 @@ static int krb5_authenticate(struct ksmbd_work *work, if (smb3_encryption_negotiated(conn) && !(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) { - retval = conn->ops->generate_encryptionkey(conn, sess); - if (retval) { - ksmbd_debug(SMB, - "SMB3 encryption key generation failed\n"); - return -EINVAL; - } + conn->ops->generate_encryptionkey(conn, sess); sess->enc = true; if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION) rsp->SessionFlags = SMB2_SESSION_FLAG_ENCRYPT_DATA_LE; @@ -8861,9 +8851,8 @@ int smb2_check_sign_req(struct ksmbd_work *work) iov[0].iov_base = (char *)&hdr->ProtocolId; iov[0].iov_len = len; - if (ksmbd_sign_smb2_pdu(work->conn, work->sess->sess_key, iov, 1, - signature)) - return 0; + ksmbd_sign_smb2_pdu(work->conn, work->sess->sess_key, iov, 1, + signature); if (memcmp(signature, signature_req, SMB2_SIGNATURE_SIZE)) { pr_err("bad smb2 signature\n"); @@ -8896,9 +8885,9 @@ void smb2_set_sign_rsp(struct ksmbd_work *work) iov = &work->iov[work->iov_idx]; } - if (!ksmbd_sign_smb2_pdu(work->conn, work->sess->sess_key, iov, n_vec, - signature)) - memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE); + ksmbd_sign_smb2_pdu(work->conn, work->sess->sess_key, iov, n_vec, + signature); + memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE); } /** diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h index 863716207a0d..9fa1da647d90 100644 --- a/fs/smb/server/smb_common.h +++ b/fs/smb/server/smb_common.h @@ -402,7 +402,7 @@ struct smb_version_ops { int (*check_sign_req)(struct ksmbd_work *work); void (*set_sign_rsp)(struct ksmbd_work *work); int (*generate_signingkey)(struct ksmbd_session *sess, struct ksmbd_conn *conn); - int (*generate_encryptionkey)(struct ksmbd_conn *conn, struct ksmbd_session *sess); + void (*generate_encryptionkey)(struct ksmbd_conn *conn, struct ksmbd_session *sess); bool (*is_transform_hdr)(void *buf); int (*decrypt_req)(struct ksmbd_work *work); int (*encrypt_resp)(struct ksmbd_work *work); From 3a597e6e9701eb7af04864ffdc0a6a91bc8c6496 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 14 Oct 2025 16:17:59 -0700 Subject: [PATCH 03/44] ksmbd: Use HMAC-MD5 library for NTLMv2 For the HMAC-MD5 computations in NTLMv2, use the HMAC-MD5 library instead of a "hmac(md5)" crypto_shash. This is simpler and faster. With the library there's no need to allocate memory, no need to handle errors, and the HMAC-MD5 code is accessed directly without inefficient indirect calls and other unnecessary API overhead. To preserve the existing behavior of NTLMv2 support being disabled when the kernel is booted with "fips=1", make ksmbd_auth_ntlmv2() check fips_enabled itself. Previously it relied on the error from crypto_alloc_shash("hmac(md5)") being bubbled up. I don't know for sure that this is actually needed, but this preserves the existing behavior. Signed-off-by: Eric Biggers Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/Kconfig | 3 +- fs/smb/server/auth.c | 173 ++++++------------------------------- fs/smb/server/crypto_ctx.c | 8 -- fs/smb/server/crypto_ctx.h | 6 +- fs/smb/server/server.c | 2 - 5 files changed, 27 insertions(+), 165 deletions(-) diff --git a/fs/smb/server/Kconfig b/fs/smb/server/Kconfig index 788104cfb082..2775162c535c 100644 --- a/fs/smb/server/Kconfig +++ b/fs/smb/server/Kconfig @@ -7,11 +7,10 @@ config SMB_SERVER select NLS_UTF8 select NLS_UCS2_UTILS select CRYPTO - select CRYPTO_MD5 - select CRYPTO_HMAC select CRYPTO_ECB select CRYPTO_LIB_ARC4 select CRYPTO_LIB_DES + select CRYPTO_LIB_MD5 select CRYPTO_LIB_SHA256 select CRYPTO_LIB_SHA512 select CRYPTO_CMAC diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c index 54918f43d2c6..f2767c4b5132 100644 --- a/fs/smb/server/auth.c +++ b/fs/smb/server/auth.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -70,85 +71,16 @@ void ksmbd_copy_gss_neg_header(void *buf) memcpy(buf, NEGOTIATE_GSS_HEADER, AUTH_GSS_LENGTH); } -/** - * ksmbd_gen_sess_key() - function to generate session key - * @sess: session of connection - * @hash: source hash value to be used for find session key - * @hmac: source hmac value to be used for finding session key - * - */ -static int ksmbd_gen_sess_key(struct ksmbd_session *sess, char *hash, - char *hmac) -{ - struct ksmbd_crypto_ctx *ctx; - int rc; - - ctx = ksmbd_crypto_ctx_find_hmacmd5(); - if (!ctx) { - ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n"); - return -ENOMEM; - } - - rc = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx), - hash, - CIFS_HMAC_MD5_HASH_SIZE); - if (rc) { - ksmbd_debug(AUTH, "hmacmd5 set key fail error %d\n", rc); - goto out; - } - - rc = crypto_shash_init(CRYPTO_HMACMD5(ctx)); - if (rc) { - ksmbd_debug(AUTH, "could not init hmacmd5 error %d\n", rc); - goto out; - } - - rc = crypto_shash_update(CRYPTO_HMACMD5(ctx), - hmac, - SMB2_NTLMV2_SESSKEY_SIZE); - if (rc) { - ksmbd_debug(AUTH, "Could not update with response error %d\n", rc); - goto out; - } - - rc = crypto_shash_final(CRYPTO_HMACMD5(ctx), sess->sess_key); - if (rc) { - ksmbd_debug(AUTH, "Could not generate hmacmd5 hash error %d\n", rc); - goto out; - } - -out: - ksmbd_release_crypto_ctx(ctx); - return rc; -} - static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess, char *ntlmv2_hash, char *dname) { int ret, len, conv_len; wchar_t *domain = NULL; __le16 *uniname = NULL; - struct ksmbd_crypto_ctx *ctx; + struct hmac_md5_ctx ctx; - ctx = ksmbd_crypto_ctx_find_hmacmd5(); - if (!ctx) { - ksmbd_debug(AUTH, "can't generate ntlmv2 hash\n"); - return -ENOMEM; - } - - ret = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx), - user_passkey(sess->user), + hmac_md5_init_usingrawkey(&ctx, user_passkey(sess->user), CIFS_ENCPWD_SIZE); - if (ret) { - ksmbd_debug(AUTH, "Could not set NT Hash as a key\n"); - goto out; - } - - ret = crypto_shash_init(CRYPTO_HMACMD5(ctx)); - if (ret) { - ksmbd_debug(AUTH, "could not init hmacmd5\n"); - goto out; - } /* convert user_name to unicode */ len = strlen(user_name(sess->user)); @@ -166,13 +98,7 @@ static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess, } UniStrupr(uniname); - ret = crypto_shash_update(CRYPTO_HMACMD5(ctx), - (char *)uniname, - UNICODE_LEN(conv_len)); - if (ret) { - ksmbd_debug(AUTH, "Could not update with user\n"); - goto out; - } + hmac_md5_update(&ctx, (const u8 *)uniname, UNICODE_LEN(conv_len)); /* Convert domain name or conn name to unicode and uppercase */ len = strlen(dname); @@ -189,21 +115,12 @@ static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess, goto out; } - ret = crypto_shash_update(CRYPTO_HMACMD5(ctx), - (char *)domain, - UNICODE_LEN(conv_len)); - if (ret) { - ksmbd_debug(AUTH, "Could not update with domain\n"); - goto out; - } - - ret = crypto_shash_final(CRYPTO_HMACMD5(ctx), ntlmv2_hash); - if (ret) - ksmbd_debug(AUTH, "Could not generate md5 hash\n"); + hmac_md5_update(&ctx, (const u8 *)domain, UNICODE_LEN(conv_len)); + hmac_md5_final(&ctx, ntlmv2_hash); + ret = 0; out: kfree(uniname); kfree(domain); - ksmbd_release_crypto_ctx(ctx); return ret; } @@ -224,73 +141,33 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, { char ntlmv2_hash[CIFS_ENCPWD_SIZE]; char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE]; - struct ksmbd_crypto_ctx *ctx = NULL; - char *construct = NULL; - int rc, len; + struct hmac_md5_ctx ctx; + int rc; + + if (fips_enabled) { + ksmbd_debug(AUTH, "NTLMv2 support is disabled due to FIPS\n"); + return -EOPNOTSUPP; + } rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name); if (rc) { ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc); - goto out; + return rc; } - ctx = ksmbd_crypto_ctx_find_hmacmd5(); - if (!ctx) { - ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n"); - return -ENOMEM; - } + hmac_md5_init_usingrawkey(&ctx, ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE); + hmac_md5_update(&ctx, cryptkey, CIFS_CRYPTO_KEY_SIZE); + hmac_md5_update(&ctx, (const u8 *)&ntlmv2->blob_signature, blen); + hmac_md5_final(&ctx, ntlmv2_rsp); - rc = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx), - ntlmv2_hash, - CIFS_HMAC_MD5_HASH_SIZE); - if (rc) { - ksmbd_debug(AUTH, "Could not set NTLMV2 Hash as a key\n"); - goto out; - } - - rc = crypto_shash_init(CRYPTO_HMACMD5(ctx)); - if (rc) { - ksmbd_debug(AUTH, "Could not init hmacmd5\n"); - goto out; - } - - len = CIFS_CRYPTO_KEY_SIZE + blen; - construct = kzalloc(len, KSMBD_DEFAULT_GFP); - if (!construct) { - rc = -ENOMEM; - goto out; - } - - memcpy(construct, cryptkey, CIFS_CRYPTO_KEY_SIZE); - memcpy(construct + CIFS_CRYPTO_KEY_SIZE, &ntlmv2->blob_signature, blen); - - rc = crypto_shash_update(CRYPTO_HMACMD5(ctx), construct, len); - if (rc) { - ksmbd_debug(AUTH, "Could not update with response\n"); - goto out; - } - - rc = crypto_shash_final(CRYPTO_HMACMD5(ctx), ntlmv2_rsp); - if (rc) { - ksmbd_debug(AUTH, "Could not generate md5 hash\n"); - goto out; - } - ksmbd_release_crypto_ctx(ctx); - ctx = NULL; - - rc = ksmbd_gen_sess_key(sess, ntlmv2_hash, ntlmv2_rsp); - if (rc) { - ksmbd_debug(AUTH, "Could not generate sess key\n"); - goto out; - } + /* Generate the session key */ + hmac_md5_usingrawkey(ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE, + ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE, + sess->sess_key); if (memcmp(ntlmv2->ntlmv2_hash, ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE) != 0) - rc = -EINVAL; -out: - if (ctx) - ksmbd_release_crypto_ctx(ctx); - kfree(construct); - return rc; + return -EINVAL; + return 0; } /** diff --git a/fs/smb/server/crypto_ctx.c b/fs/smb/server/crypto_ctx.c index a5ec22ba8ae3..fe29d186baf6 100644 --- a/fs/smb/server/crypto_ctx.c +++ b/fs/smb/server/crypto_ctx.c @@ -66,9 +66,6 @@ static struct shash_desc *alloc_shash_desc(int id) struct shash_desc *shash; switch (id) { - case CRYPTO_SHASH_HMACMD5: - tfm = crypto_alloc_shash("hmac(md5)", 0, 0); - break; case CRYPTO_SHASH_CMACAES: tfm = crypto_alloc_shash("cmac(aes)", 0, 0); break; @@ -174,11 +171,6 @@ static struct ksmbd_crypto_ctx *____crypto_shash_ctx_find(int id) return NULL; } -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacmd5(void) -{ - return ____crypto_shash_ctx_find(CRYPTO_SHASH_HMACMD5); -} - struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void) { return ____crypto_shash_ctx_find(CRYPTO_SHASH_CMACAES); diff --git a/fs/smb/server/crypto_ctx.h b/fs/smb/server/crypto_ctx.h index c571d65a16f3..b9476ed520ae 100644 --- a/fs/smb/server/crypto_ctx.h +++ b/fs/smb/server/crypto_ctx.h @@ -10,8 +10,7 @@ #include enum { - CRYPTO_SHASH_HMACMD5 = 0, - CRYPTO_SHASH_CMACAES, + CRYPTO_SHASH_CMACAES = 0, CRYPTO_SHASH_MAX, }; @@ -33,17 +32,14 @@ struct ksmbd_crypto_ctx { struct crypto_aead *ccmaes[CRYPTO_AEAD_MAX]; }; -#define CRYPTO_HMACMD5(c) ((c)->desc[CRYPTO_SHASH_HMACMD5]) #define CRYPTO_CMACAES(c) ((c)->desc[CRYPTO_SHASH_CMACAES]) -#define CRYPTO_HMACMD5_TFM(c) ((c)->desc[CRYPTO_SHASH_HMACMD5]->tfm) #define CRYPTO_CMACAES_TFM(c) ((c)->desc[CRYPTO_SHASH_CMACAES]->tfm) #define CRYPTO_GCM(c) ((c)->ccmaes[CRYPTO_AEAD_AES_GCM]) #define CRYPTO_CCM(c) ((c)->ccmaes[CRYPTO_AEAD_AES_CCM]) void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx); -struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_hmacmd5(void); struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void); struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_gcm(void); struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_ccm(void); diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c index 8bce97633e01..3cea16050e4f 100644 --- a/fs/smb/server/server.c +++ b/fs/smb/server/server.c @@ -622,8 +622,6 @@ MODULE_AUTHOR("Namjae Jeon "); MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER"); MODULE_LICENSE("GPL"); MODULE_SOFTDEP("pre: ecb"); -MODULE_SOFTDEP("pre: hmac"); -MODULE_SOFTDEP("pre: md5"); MODULE_SOFTDEP("pre: nls"); MODULE_SOFTDEP("pre: aes"); MODULE_SOFTDEP("pre: cmac"); From c5b462e35373a68a5a7954f5e00383998cc7fe92 Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Fri, 17 Oct 2025 18:46:07 +0800 Subject: [PATCH 04/44] smb/server: fix return value of smb2_read() STATUS_END_OF_FILE maps to the linux error -ENODATA. Perhaps in the future we can move client/smb2maperror.c into common/ and then call map_smb2_to_linux_error() to get the linux error. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 17ce41fb9995..6a482e4c1d62 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -6832,7 +6832,7 @@ int smb2_read(struct ksmbd_work *work) rsp->hdr.Status = STATUS_END_OF_FILE; smb2_set_err_rsp(work); ksmbd_fd_put(work, fp); - return 0; + return -ENODATA; } ksmbd_debug(SMB, "nbytes %zu, offset %lld mincount %zu\n", From d1a30b9ddc3d4c0e38666bd166d51863cb39f1c4 Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Fri, 17 Oct 2025 18:46:08 +0800 Subject: [PATCH 05/44] smb/server: fix return value of smb2_notify() smb2_notify() should return error code when an error occurs, __process_request() will print the error messages. I may implement the SMB2 CHANGE_NOTIFY response (see MS-SMB2 2.2.36) in the future. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 6a482e4c1d62..d676558f7bb6 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -8777,7 +8777,7 @@ int smb2_oplock_break(struct ksmbd_work *work) * smb2_notify() - handler for smb2 notify request * @work: smb work containing notify command buffer * - * Return: 0 + * Return: 0 on success, otherwise error */ int smb2_notify(struct ksmbd_work *work) { @@ -8791,12 +8791,12 @@ int smb2_notify(struct ksmbd_work *work) if (work->next_smb2_rcv_hdr_off && req->hdr.NextCommand) { rsp->hdr.Status = STATUS_INTERNAL_ERROR; smb2_set_err_rsp(work); - return 0; + return -EIO; } smb2_set_err_rsp(work); rsp->hdr.Status = STATUS_NOT_IMPLEMENTED; - return 0; + return -EOPNOTSUPP; } /** From dafe22bc676d4fcb1ccb193c8cc3dda57942509d Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Fri, 17 Oct 2025 18:46:09 +0800 Subject: [PATCH 06/44] smb/server: fix return value of smb2_query_dir() __process_request() will not print error messages if smb2_query_dir() always returns 0. Fix this by returning the correct value at the end of function. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index d676558f7bb6..a3b7b648227a 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -4550,7 +4550,7 @@ int smb2_query_dir(struct ksmbd_work *work) smb2_set_err_rsp(work); ksmbd_fd_put(work, dir_fp); ksmbd_revert_fsids(work); - return 0; + return rc; } /** From 269df046c1e15ab34fa26fd90db9381f022a0963 Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Fri, 17 Oct 2025 18:46:10 +0800 Subject: [PATCH 07/44] smb/server: fix return value of smb2_ioctl() __process_request() will not print error messages if smb2_ioctl() always returns 0. Fix this by returning the correct value at the end of function. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index a3b7b648227a..2e6f3d96d3e6 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -8154,7 +8154,7 @@ int smb2_ioctl(struct ksmbd_work *work) id = req->VolatileFileId; if (req->Flags != cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL)) { - rsp->hdr.Status = STATUS_NOT_SUPPORTED; + ret = -EOPNOTSUPP; goto out; } @@ -8174,8 +8174,9 @@ int smb2_ioctl(struct ksmbd_work *work) case FSCTL_DFS_GET_REFERRALS: case FSCTL_DFS_GET_REFERRALS_EX: /* Not support DFS yet */ + ret = -EOPNOTSUPP; rsp->hdr.Status = STATUS_FS_DRIVER_REQUIRED; - goto out; + goto out2; case FSCTL_CREATE_OR_GET_OBJECT_ID: { struct file_object_buf_type1_ioctl_rsp *obj_buf; @@ -8465,8 +8466,10 @@ int smb2_ioctl(struct ksmbd_work *work) rsp->hdr.Status = STATUS_BUFFER_TOO_SMALL; else if (ret < 0 || rsp->hdr.Status == 0) rsp->hdr.Status = STATUS_INVALID_PARAMETER; + +out2: smb2_set_err_rsp(work); - return 0; + return ret; } /** From a3c4445fdbbb83aa94ea1778717ef57006164814 Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Fri, 17 Oct 2025 18:46:11 +0800 Subject: [PATCH 08/44] smb/server: fix return value of smb2_oplock_break() smb2_oplock_break() should return error code when an error occurs, __process_request() will print the error messages. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 2e6f3d96d3e6..98d7f7259fe3 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -8748,7 +8748,7 @@ static void smb21_lease_break_ack(struct ksmbd_work *work) * smb2_oplock_break() - dispatcher for smb2.0 and 2.1 oplock/lease break * @work: smb work containing oplock/lease break command buffer * - * Return: 0 + * Return: 0 on success, otherwise error */ int smb2_oplock_break(struct ksmbd_work *work) { @@ -8771,6 +8771,7 @@ int smb2_oplock_break(struct ksmbd_work *work) le16_to_cpu(req->StructureSize)); rsp->hdr.Status = STATUS_INVALID_PARAMETER; smb2_set_err_rsp(work); + return -EINVAL; } return 0; From 7d9f51d36b6c24e02b8a379cbaf1a273511ed403 Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Fri, 17 Oct 2025 18:46:12 +0800 Subject: [PATCH 09/44] smb/server: update some misguided comment of smb2_0_server_cmds proc These functions return error code rather than always returning 0. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 98d7f7259fe3..09ac08c818df 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2158,7 +2158,7 @@ static int smb2_create_open_flags(bool file_present, __le32 access, * smb2_tree_disconnect() - handler for smb tree connect request * @work: smb work containing request buffer * - * Return: 0 + * Return: 0 on success, otherwise error */ int smb2_tree_disconnect(struct ksmbd_work *work) { @@ -2222,7 +2222,7 @@ int smb2_tree_disconnect(struct ksmbd_work *work) * smb2_session_logoff() - handler for session log off request * @work: smb work containing request buffer * - * Return: 0 + * Return: 0 on success, otherwise error */ int smb2_session_logoff(struct ksmbd_work *work) { @@ -5834,7 +5834,7 @@ static noinline int smb2_close_pipe(struct ksmbd_work *work) * smb2_close() - handler for smb2 close file command * @work: smb work containing close request buffer * - * Return: 0 + * Return: 0 on success, otherwise error */ int smb2_close(struct ksmbd_work *work) { @@ -5959,7 +5959,7 @@ int smb2_close(struct ksmbd_work *work) * smb2_echo() - handler for smb2 echo(ping) command * @work: smb work containing echo request buffer * - * Return: 0 + * Return: 0 on success, otherwise error */ int smb2_echo(struct ksmbd_work *work) { From 94b955167e3b11372e314f45f4b2fbf4f92493b9 Mon Sep 17 00:00:00 2001 From: ZhangGuoDong Date: Mon, 27 Oct 2025 15:12:53 +0800 Subject: [PATCH 10/44] smb: rename common/cifsglob.h to common/smbglob.h "cifs" is a legacy name, rename it to "smbglob.h" according to Namjae's suggestions. Co-developed-by: ChenXiaoSong Signed-off-by: ChenXiaoSong Signed-off-by: ZhangGuoDong Suggested-by: Namjae Jeon Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/cifsglob.h | 2 +- fs/smb/common/{cifsglob.h => smbglob.h} | 6 +++--- fs/smb/server/smb_common.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename fs/smb/common/{cifsglob.h => smbglob.h} (89%) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 203e2aaa3c25..8fd9aa7e2009 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -24,7 +24,7 @@ #include "cifsacl.h" #include #include -#include "../common/cifsglob.h" +#include "../common/smbglob.h" #include "../common/smb2pdu.h" #include "smb2pdu.h" #include diff --git a/fs/smb/common/cifsglob.h b/fs/smb/common/smbglob.h similarity index 89% rename from fs/smb/common/cifsglob.h rename to fs/smb/common/smbglob.h index 00fd215e3eb5..c51d227977c4 100644 --- a/fs/smb/common/cifsglob.h +++ b/fs/smb/common/smbglob.h @@ -6,8 +6,8 @@ * Jeremy Allison (jra@samba.org) * */ -#ifndef _COMMON_CIFS_GLOB_H -#define _COMMON_CIFS_GLOB_H +#ifndef _COMMON_SMB_GLOB_H +#define _COMMON_SMB_GLOB_H static inline void inc_rfc1001_len(void *buf, int count) { @@ -27,4 +27,4 @@ static inline void inc_rfc1001_len(void *buf, int count) #define CIFS_DEFAULT_IOSIZE (1024 * 1024) -#endif /* _COMMON_CIFS_GLOB_H */ +#endif /* _COMMON_SMB_GLOB_H */ diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h index 9fa1da647d90..560308e0d042 100644 --- a/fs/smb/server/smb_common.h +++ b/fs/smb/server/smb_common.h @@ -10,7 +10,7 @@ #include "glob.h" #include "nterr.h" -#include "../common/cifsglob.h" +#include "../common/smbglob.h" #include "../common/smb2pdu.h" #include "smb2pdu.h" From 34cf191bb6a349dc88ec2c4f6355fe006ac669e0 Mon Sep 17 00:00:00 2001 From: ZhangGuoDong Date: Mon, 27 Oct 2025 15:12:54 +0800 Subject: [PATCH 11/44] smb: move smb_version_values to common/smbglob.h Merge the struct members of the server and the client: - req_capabilities: from client - header_preamble_size: from client - cap_unicode: from client - capabilities: from server, rename to req_capabilities - max_read_size: from server - max_write_size: from server - max_trans_size: from server - max_credits: from server - create_durable_size: from server - create_durable_v2_size: from server - create_mxac_size: from server - create_disk_id_size: from server - create_posix_size: from server Then move duplicate definitions to common header file. Co-developed-by: ChenXiaoSong Signed-off-by: ChenXiaoSong Signed-off-by: ZhangGuoDong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/cifsglob.h | 22 ---------------------- fs/smb/common/smbglob.h | 31 +++++++++++++++++++++++++++++++ fs/smb/server/smb2misc.c | 2 +- fs/smb/server/smb2ops.c | 32 ++++++++++++++++---------------- fs/smb/server/smb2pdu.c | 10 +++++----- fs/smb/server/smb_common.h | 29 ----------------------------- 6 files changed, 53 insertions(+), 73 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 8fd9aa7e2009..accca43f7af5 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -633,28 +633,6 @@ struct smb_version_operations { struct kvec *xattr_iov); }; -struct smb_version_values { - char *version_string; - __u16 protocol_id; - __u32 req_capabilities; - __u32 large_lock_type; - __u32 exclusive_lock_type; - __u32 shared_lock_type; - __u32 unlock_lock_type; - size_t header_preamble_size; - size_t header_size; - size_t max_header_size; - size_t read_rsp_size; - __le16 lock_cmd; - unsigned int cap_unix; - unsigned int cap_nt_find; - unsigned int cap_large_files; - unsigned int cap_unicode; - __u16 signing_enabled; - __u16 signing_required; - size_t create_lease_size; -}; - #define HEADER_SIZE(server) (server->vals->header_size) #define MAX_HEADER_SIZE(server) (server->vals->max_header_size) #define HEADER_PREAMBLE_SIZE(server) (server->vals->header_preamble_size) diff --git a/fs/smb/common/smbglob.h b/fs/smb/common/smbglob.h index c51d227977c4..84aa6826c3ea 100644 --- a/fs/smb/common/smbglob.h +++ b/fs/smb/common/smbglob.h @@ -9,6 +9,37 @@ #ifndef _COMMON_SMB_GLOB_H #define _COMMON_SMB_GLOB_H +struct smb_version_values { + char *version_string; + __u16 protocol_id; + __le16 lock_cmd; + __u32 req_capabilities; + __u32 max_read_size; + __u32 max_write_size; + __u32 max_trans_size; + __u32 max_credits; + __u32 large_lock_type; + __u32 exclusive_lock_type; + __u32 shared_lock_type; + __u32 unlock_lock_type; + size_t header_preamble_size; + size_t header_size; + size_t max_header_size; + size_t read_rsp_size; + unsigned int cap_unix; + unsigned int cap_nt_find; + unsigned int cap_large_files; + unsigned int cap_unicode; + __u16 signing_enabled; + __u16 signing_required; + size_t create_lease_size; + size_t create_durable_size; + size_t create_durable_v2_size; + size_t create_mxac_size; + size_t create_disk_id_size; + size_t create_posix_size; +}; + static inline void inc_rfc1001_len(void *buf, int count) { be32_add_cpu((__be32 *)buf, count); diff --git a/fs/smb/server/smb2misc.c b/fs/smb/server/smb2misc.c index ae501024665e..67a2d7a793f6 100644 --- a/fs/smb/server/smb2misc.c +++ b/fs/smb/server/smb2misc.c @@ -460,7 +460,7 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work) } validate_credit: - if ((work->conn->vals->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) && + if ((work->conn->vals->req_capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) && smb2_validate_credit_charge(work->conn, hdr)) return 1; diff --git a/fs/smb/server/smb2ops.c b/fs/smb/server/smb2ops.c index 606aa3c5189a..bcf05caa2304 100644 --- a/fs/smb/server/smb2ops.c +++ b/fs/smb/server/smb2ops.c @@ -15,7 +15,7 @@ static struct smb_version_values smb21_server_values = { .version_string = SMB21_VERSION_STRING, .protocol_id = SMB21_PROT_ID, - .capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, + .req_capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, .max_read_size = SMB21_DEFAULT_IOSIZE, .max_write_size = SMB21_DEFAULT_IOSIZE, .max_trans_size = SMB21_DEFAULT_IOSIZE, @@ -41,7 +41,7 @@ static struct smb_version_values smb21_server_values = { static struct smb_version_values smb30_server_values = { .version_string = SMB30_VERSION_STRING, .protocol_id = SMB30_PROT_ID, - .capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, + .req_capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, .max_read_size = SMB3_DEFAULT_IOSIZE, .max_write_size = SMB3_DEFAULT_IOSIZE, .max_trans_size = SMB3_DEFAULT_TRANS_SIZE, @@ -68,7 +68,7 @@ static struct smb_version_values smb30_server_values = { static struct smb_version_values smb302_server_values = { .version_string = SMB302_VERSION_STRING, .protocol_id = SMB302_PROT_ID, - .capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, + .req_capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, .max_read_size = SMB3_DEFAULT_IOSIZE, .max_write_size = SMB3_DEFAULT_IOSIZE, .max_trans_size = SMB3_DEFAULT_TRANS_SIZE, @@ -95,7 +95,7 @@ static struct smb_version_values smb302_server_values = { static struct smb_version_values smb311_server_values = { .version_string = SMB311_VERSION_STRING, .protocol_id = SMB311_PROT_ID, - .capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, + .req_capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, .max_read_size = SMB3_DEFAULT_IOSIZE, .max_write_size = SMB3_DEFAULT_IOSIZE, .max_trans_size = SMB3_DEFAULT_TRANS_SIZE, @@ -204,7 +204,7 @@ void init_smb2_1_server(struct ksmbd_conn *conn) conn->signing_algorithm = SIGNING_ALG_HMAC_SHA256_LE; if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING; + conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_LEASING; } /** @@ -221,20 +221,20 @@ void init_smb3_0_server(struct ksmbd_conn *conn) conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE; if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING | + conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_DIRECTORY_LEASING; if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION && conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; + conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION || (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) && conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; + conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; + conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; } /** @@ -251,19 +251,19 @@ void init_smb3_02_server(struct ksmbd_conn *conn) conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE; if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING | + conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_DIRECTORY_LEASING; if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION || (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) && conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; + conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; + conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES; + conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES; } /** @@ -280,14 +280,14 @@ int init_smb3_11_server(struct ksmbd_conn *conn) conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE; if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING | + conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_DIRECTORY_LEASING; if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; + conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE) - conn->vals->capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES; + conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES; INIT_LIST_HEAD(&conn->preauth_sess_table); return 0; diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 09ac08c818df..d52528792e46 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -282,7 +282,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work) /* Not setting conn guid rsp->ServerGUID, as it * not used by client for identifying connection */ - rsp->Capabilities = cpu_to_le32(conn->vals->capabilities); + rsp->Capabilities = cpu_to_le32(conn->vals->req_capabilities); /* Default Max Message Size till SMB2.0, 64K*/ rsp->MaxTransactSize = cpu_to_le32(conn->vals->max_trans_size); rsp->MaxReadSize = cpu_to_le32(conn->vals->max_read_size); @@ -956,7 +956,7 @@ bool smb3_encryption_negotiated(struct ksmbd_conn *conn) * SMB 3.0 and 3.0.2 dialects use the SMB2_GLOBAL_CAP_ENCRYPTION flag. * SMB 3.1.1 uses the cipher_type field. */ - return (conn->vals->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) || + return (conn->vals->req_capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) || conn->cipher_type; } @@ -1210,7 +1210,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work) rc = -EINVAL; goto err_out; } - rsp->Capabilities = cpu_to_le32(conn->vals->capabilities); + rsp->Capabilities = cpu_to_le32(conn->vals->req_capabilities); /* For stats */ conn->connection_type = conn->dialect; @@ -3464,7 +3464,7 @@ int smb2_open(struct ksmbd_work *work) share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp); if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) || (req_op_level == SMB2_OPLOCK_LEVEL_LEASE && - !(conn->vals->capabilities & SMB2_GLOBAL_CAP_LEASING))) { + !(conn->vals->req_capabilities & SMB2_GLOBAL_CAP_LEASING))) { if (share_ret < 0 && !S_ISDIR(file_inode(fp->filp)->i_mode)) { rc = share_ret; goto err_out1; @@ -7974,7 +7974,7 @@ static int fsctl_validate_negotiate_info(struct ksmbd_conn *conn, goto err_out; } - neg_rsp->Capabilities = cpu_to_le32(conn->vals->capabilities); + neg_rsp->Capabilities = cpu_to_le32(conn->vals->req_capabilities); memset(neg_rsp->Guid, 0, SMB2_CLIENT_GUID_SIZE); neg_rsp->SecurityMode = cpu_to_le16(conn->srv_sec_mode); neg_rsp->Dialect = cpu_to_le16(conn->dialect); diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h index 560308e0d042..93f28defef3e 100644 --- a/fs/smb/server/smb_common.h +++ b/fs/smb/server/smb_common.h @@ -338,35 +338,6 @@ struct file_id_full_dir_info { char FileName[]; } __packed; /* level 0x105 FF rsp data */ -struct smb_version_values { - char *version_string; - __u16 protocol_id; - __le16 lock_cmd; - __u32 capabilities; - __u32 max_read_size; - __u32 max_write_size; - __u32 max_trans_size; - __u32 max_credits; - __u32 large_lock_type; - __u32 exclusive_lock_type; - __u32 shared_lock_type; - __u32 unlock_lock_type; - size_t header_size; - size_t max_header_size; - size_t read_rsp_size; - unsigned int cap_unix; - unsigned int cap_nt_find; - unsigned int cap_large_files; - __u16 signing_enabled; - __u16 signing_required; - size_t create_lease_size; - size_t create_durable_size; - size_t create_durable_v2_size; - size_t create_mxac_size; - size_t create_disk_id_size; - size_t create_posix_size; -}; - struct filesystem_posix_info { /* For undefined recommended transfer size return -1 in that field */ __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ From 36c31540cf5279262bfd148d8537cd04866499f2 Mon Sep 17 00:00:00 2001 From: ZhangGuoDong Date: Fri, 21 Nov 2025 15:44:49 -0600 Subject: [PATCH 12/44] smb: move get_rfc1002_len() to common/smbglob.h Rename get_rfc1002_length() to get_rfc1002_len(), then move duplicate definitions to common header file. Co-developed-by: ChenXiaoSong Signed-off-by: ChenXiaoSong Signed-off-by: ZhangGuoDong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/cifsglob.h | 6 ------ fs/smb/client/cifssmb.c | 6 +++--- fs/smb/client/cifstransport.c | 8 ++++---- fs/smb/client/connect.c | 2 +- fs/smb/common/smbglob.h | 5 +++++ fs/smb/server/smb_common.h | 5 ----- 6 files changed, 13 insertions(+), 19 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index accca43f7af5..4d0aca8097c1 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -670,12 +670,6 @@ struct cifs_mnt_data { int flags; }; -static inline unsigned int -get_rfc1002_length(void *buf) -{ - return be32_to_cpu(*((__be32 *)buf)) & 0xffffff; -} - struct TCP_Server_Info { struct list_head tcp_ses_list; struct list_head smb_ses_list; diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index dcc50a2bfa4b..132d015cbdf1 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -614,7 +614,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server) iov[0].iov_len = 4; iov[0].iov_base = smb; - iov[1].iov_len = get_rfc1002_length(smb); + iov[1].iov_len = get_rfc1002_len(smb); iov[1].iov_base = (char *)smb + 4; rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL, @@ -1458,7 +1458,7 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) rdata->iov[0].iov_base = smb; rdata->iov[0].iov_len = 4; rdata->iov[1].iov_base = (char *)smb + 4; - rdata->iov[1].iov_len = get_rfc1002_length(smb); + rdata->iov[1].iov_len = get_rfc1002_len(smb); trace_smb3_read_enter(rdata->rreq->debug_id, rdata->subreq.debug_index, @@ -1830,7 +1830,7 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) /* 4 for RFC1001 length + 1 for BCC */ iov[0].iov_len = 4; iov[0].iov_base = smb; - iov[1].iov_len = get_rfc1002_length(smb) + 1; + iov[1].iov_len = get_rfc1002_len(smb) + 1; iov[1].iov_base = (char *)smb + 4; rqst.rq_iov = iov; diff --git a/fs/smb/client/cifstransport.c b/fs/smb/client/cifstransport.c index e98b95eff8c9..4c4f5befb6d3 100644 --- a/fs/smb/client/cifstransport.c +++ b/fs/smb/client/cifstransport.c @@ -165,7 +165,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses, int resp_buf_type; iov[0].iov_base = in_buf; - iov[0].iov_len = get_rfc1002_length(in_buf) + 4; + iov[0].iov_len = get_rfc1002_len(in_buf) + 4; flags |= CIFS_NO_RSP_BUF; rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov); cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc); @@ -177,7 +177,7 @@ int cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, bool log_error) { - unsigned int len = get_rfc1002_length(mid->resp_buf) + 4; + unsigned int len = get_rfc1002_len(mid->resp_buf) + 4; dump_smb(mid->resp_buf, min_t(u32, 92, len)); @@ -370,7 +370,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, goto out; } - *pbytes_returned = get_rfc1002_length(midQ->resp_buf); + *pbytes_returned = get_rfc1002_len(midQ->resp_buf); memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); rc = cifs_check_receive(midQ, server, 0); out: @@ -554,7 +554,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, goto out; } - *pbytes_returned = get_rfc1002_length(midQ->resp_buf); + *pbytes_returned = get_rfc1002_len(midQ->resp_buf); memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4); rc = cifs_check_receive(midQ, server, 0); out: diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 2f94d93b95e9..ca4d6055d2f3 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -1295,7 +1295,7 @@ cifs_demultiplex_thread(void *p) * The right amount was read from socket - 4 bytes, * so we can now interpret the length field. */ - pdu_length = get_rfc1002_length(buf); + pdu_length = get_rfc1002_len(buf); cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length); if (!is_smb_response(server, buf[0])) diff --git a/fs/smb/common/smbglob.h b/fs/smb/common/smbglob.h index 84aa6826c3ea..b258199b0d75 100644 --- a/fs/smb/common/smbglob.h +++ b/fs/smb/common/smbglob.h @@ -40,6 +40,11 @@ struct smb_version_values { size_t create_posix_size; }; +static inline unsigned int get_rfc1002_len(void *buf) +{ + return be32_to_cpu(*((__be32 *)buf)) & 0xffffff; +} + static inline void inc_rfc1001_len(void *buf, int count) { be32_add_cpu((__be32 *)buf, count); diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h index 93f28defef3e..ff3e441da125 100644 --- a/fs/smb/server/smb_common.h +++ b/fs/smb/server/smb_common.h @@ -423,9 +423,4 @@ unsigned int ksmbd_server_side_copy_max_chunk_size(void); unsigned int ksmbd_server_side_copy_max_total_size(void); bool is_asterisk(char *p); __le32 smb_map_generic_desired_access(__le32 daccess); - -static inline unsigned int get_rfc1002_len(void *buf) -{ - return be32_to_cpu(*((__be32 *)buf)) & 0xffffff; -} #endif /* __SMB_COMMON_H__ */ From cd311445d9f5510979f6e9f4344178b9f5a4d981 Mon Sep 17 00:00:00 2001 From: ZhangGuoDong Date: Mon, 27 Oct 2025 15:12:56 +0800 Subject: [PATCH 13/44] smb: move SMB1_PROTO_NUMBER to common/smbglob.h Replace the constant of client with SMB1_PROTO_NUMBER, then move the macro definition from server/smb_common.h to common/smbglob.h. Co-developed-by: ChenXiaoSong Signed-off-by: ChenXiaoSong Signed-off-by: ZhangGuoDong Suggested-by: Christophe JAILLET Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/misc.c | 2 +- fs/smb/common/smbglob.h | 2 ++ fs/smb/server/smb_common.h | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c index e10123d8cd7d..340c44dc7b5b 100644 --- a/fs/smb/client/misc.c +++ b/fs/smb/client/misc.c @@ -318,7 +318,7 @@ static int check_smb_hdr(struct smb_hdr *smb) { /* does it have the right SMB "signature" ? */ - if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) { + if (*(__le32 *) smb->Protocol != SMB1_PROTO_NUMBER) { cifs_dbg(VFS, "Bad protocol string signature header 0x%x\n", *(unsigned int *)smb->Protocol); return 1; diff --git a/fs/smb/common/smbglob.h b/fs/smb/common/smbglob.h index b258199b0d75..fa3d30dc6022 100644 --- a/fs/smb/common/smbglob.h +++ b/fs/smb/common/smbglob.h @@ -9,6 +9,8 @@ #ifndef _COMMON_SMB_GLOB_H #define _COMMON_SMB_GLOB_H +#define SMB1_PROTO_NUMBER cpu_to_le32(0x424d53ff) + struct smb_version_values { char *version_string; __u16 protocol_id; diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h index ff3e441da125..0e291fe2d190 100644 --- a/fs/smb/server/smb_common.h +++ b/fs/smb/server/smb_common.h @@ -151,7 +151,6 @@ FILE_EXECUTE | FILE_DELETE_CHILD | \ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES) -#define SMB1_PROTO_NUMBER cpu_to_le32(0x424d53ff) #define SMB_COM_NEGOTIATE 0x72 #define SMB1_CLIENT_GUID_SIZE (16) From 7844d50ca239f0788e732608820f7026cb0cc8fb Mon Sep 17 00:00:00 2001 From: ZhangGuoDong Date: Mon, 27 Oct 2025 15:22:03 +0800 Subject: [PATCH 14/44] smb: move smb_sockaddr_in and smb_sockaddr_in6 to common/smb2pdu.h Rename 4 places: - iface_info_ipv4 -> smb_sockaddr_in - iface_info_ipv6 -> smb_sockaddr_in6 - IPv4address -> IPv4Address - IPv6address -> IPv6Address Then move duplicate definitions to common header file. Co-developed-by: ChenXiaoSong Signed-off-by: ChenXiaoSong Signed-off-by: ZhangGuoDong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/smb2ops.c | 8 ++++---- fs/smb/client/smb2pdu.h | 13 ------------- fs/smb/common/smb2pdu.h | 15 +++++++++++++++ fs/smb/server/smb2pdu.c | 4 ++-- fs/smb/server/smb2pdu.h | 13 ------------- 5 files changed, 21 insertions(+), 32 deletions(-) diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 1e39f2165e42..5103fe3c92f4 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -624,8 +624,8 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, struct network_interface_info_ioctl_rsp *p; struct sockaddr_in *addr4; struct sockaddr_in6 *addr6; - struct iface_info_ipv4 *p4; - struct iface_info_ipv6 *p6; + struct smb_sockaddr_in *p4; + struct smb_sockaddr_in6 *p6; struct cifs_server_iface *info = NULL, *iface = NULL, *niface = NULL; struct cifs_server_iface tmp_iface; ssize_t bytes_left; @@ -685,7 +685,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, */ case INTERNETWORK: addr4 = (struct sockaddr_in *)&tmp_iface.sockaddr; - p4 = (struct iface_info_ipv4 *)p->Buffer; + p4 = (struct smb_sockaddr_in *)p->Buffer; addr4->sin_family = AF_INET; memcpy(&addr4->sin_addr, &p4->IPv4Address, 4); @@ -697,7 +697,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, break; case INTERNETWORKV6: addr6 = (struct sockaddr_in6 *)&tmp_iface.sockaddr; - p6 = (struct iface_info_ipv6 *)p->Buffer; + p6 = (struct smb_sockaddr_in6 *)p->Buffer; addr6->sin6_family = AF_INET6; memcpy(&addr6->sin6_addr, &p6->IPv6Address, 16); diff --git a/fs/smb/client/smb2pdu.h b/fs/smb/client/smb2pdu.h index 101024f8f725..c9901723dfd8 100644 --- a/fs/smb/client/smb2pdu.h +++ b/fs/smb/client/smb2pdu.h @@ -279,19 +279,6 @@ struct network_interface_info_ioctl_rsp { __u8 Buffer[126]; } __packed; -struct iface_info_ipv4 { - __be16 Port; - __be32 IPv4Address; - __be64 Reserved; -} __packed; - -struct iface_info_ipv6 { - __be16 Port; - __be32 FlowInfo; - __u8 IPv6Address[16]; - __be32 ScopeId; -} __packed; - #define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */ struct compress_ioctl { diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h index f79a5165a7cc..4c254957200b 100644 --- a/fs/smb/common/smb2pdu.h +++ b/fs/smb/common/smb2pdu.h @@ -1404,6 +1404,21 @@ struct smb2_ioctl_rsp { __u8 Buffer[]; } __packed; +/* See MS-SMB2 2.2.32.5.1.1 */ +struct smb_sockaddr_in { + __be16 Port; + __be32 IPv4Address; + __u8 Reserved[8]; +} __packed; + +/* See MS-SMB2 2.2.32.5.1.2 */ +struct smb_sockaddr_in6 { + __be16 Port; + __be32 FlowInfo; + __u8 IPv6Address[16]; + __be32 ScopeId; +} __packed; + /* this goes in the ioctl buffer when doing FSCTL_SET_ZERO_DATA */ struct file_zero_data_information { __le64 FileOffset; diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index d52528792e46..c5426f57cadf 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -7900,7 +7900,7 @@ static int fsctl_query_iface_info_ioctl(struct ksmbd_conn *conn, idev = __in_dev_get_rtnl(netdev); if (!idev) continue; - sockaddr_storage->addr4.IPv4address = + sockaddr_storage->addr4.IPv4Address = idev_ipv4_address(idev); nbytes += sizeof(struct network_interface_info_ioctl_rsp); ipv4_set = true; @@ -7908,7 +7908,7 @@ static int fsctl_query_iface_info_ioctl(struct ksmbd_conn *conn, } else { struct inet6_dev *idev6; struct inet6_ifaddr *ifa; - __u8 *ipv6_addr = sockaddr_storage->addr6.IPv6address; + __u8 *ipv6_addr = sockaddr_storage->addr6.IPv6Address; sockaddr_storage->Family = cpu_to_le16(INTERNETWORKV6); sockaddr_storage->addr6.Port = 0; diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h index 5163d5241b90..ac2207299735 100644 --- a/fs/smb/server/smb2pdu.h +++ b/fs/smb/server/smb2pdu.h @@ -138,19 +138,6 @@ struct create_posix_rsp { #define SMB2_0_IOCTL_IS_FSCTL 0x00000001 -struct smb_sockaddr_in { - __be16 Port; - __be32 IPv4address; - __u8 Reserved[8]; -} __packed; - -struct smb_sockaddr_in6 { - __be16 Port; - __be32 FlowInfo; - __u8 IPv6address[16]; - __be32 ScopeId; -} __packed; - #define INTERNETWORK 0x0002 #define INTERNETWORKV6 0x0017 From cc26f593dc193567bdb059a6ffde58e627a44f65 Mon Sep 17 00:00:00 2001 From: ZhangGuoDong Date: Mon, 27 Oct 2025 15:22:04 +0800 Subject: [PATCH 15/44] smb: move copychunk definitions to common/smb2pdu.h Rename 3 places: - copychunk_ioctl -> copychunk_ioctl_req - copychunk -> srv_copychunk - server: ResumeKey -> SourceKeyU64 Merge the struct members of the server and the client, then move duplicate definitions to common header file. Co-developed-by: ChenXiaoSong Signed-off-by: ChenXiaoSong Signed-off-by: ZhangGuoDong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/cifspdu.h | 8 -------- fs/smb/client/smb2ops.c | 6 +++--- fs/smb/client/smb2pdu.h | 24 ------------------------ fs/smb/common/smb2pdu.h | 29 +++++++++++++++++++++++++++++ fs/smb/server/smb2pdu.c | 4 ++-- fs/smb/server/smb2pdu.h | 20 -------------------- 6 files changed, 34 insertions(+), 57 deletions(-) diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h index d9cf7db0ac35..c86a329e5822 100644 --- a/fs/smb/client/cifspdu.h +++ b/fs/smb/client/cifspdu.h @@ -1323,14 +1323,6 @@ typedef struct smb_com_ntransact_rsp { /* parms and data follow */ } __attribute__((packed)) NTRANSACT_RSP; -/* See MS-SMB 2.2.7.2.1.1 */ -struct srv_copychunk { - __le64 SourceOffset; - __le64 DestinationOffset; - __le32 CopyLength; - __u32 Reserved; -} __packed; - typedef struct smb_com_transaction_ioctl_req { struct smb_hdr hdr; /* wct = 23 */ __u8 MaxSetupCount; diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 5103fe3c92f4..dd569cc5abcc 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -1524,7 +1524,7 @@ smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon, static int SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, - struct copychunk_ioctl *pcchunk) + struct copychunk_ioctl_req *pcchunk) { int rc; unsigned int ret_data_len; @@ -1857,10 +1857,10 @@ smb2_copychunk_range(const unsigned int xid, { int rc = 0; unsigned int ret_data_len = 0; - struct copychunk_ioctl *cc_req = NULL; + struct copychunk_ioctl_req *cc_req = NULL; struct copychunk_ioctl_rsp *cc_rsp = NULL; struct cifs_tcon *tcon; - struct copychunk *chunk; + struct srv_copychunk *chunk; u32 chunks, chunk_count, chunk_bytes; u32 copy_bytes, copy_bytes_left; u32 chunks_written, bytes_written; diff --git a/fs/smb/client/smb2pdu.h b/fs/smb/client/smb2pdu.h index c9901723dfd8..de2d83c6463c 100644 --- a/fs/smb/client/smb2pdu.h +++ b/fs/smb/client/smb2pdu.h @@ -193,36 +193,12 @@ struct crt_sd_ctxt { struct smb3_sd sd; } __packed; - -#define COPY_CHUNK_RES_KEY_SIZE 24 struct resume_key_req { char ResumeKey[COPY_CHUNK_RES_KEY_SIZE]; __le32 ContextLength; /* MBZ */ char Context[]; /* ignored, Windows sets to 4 bytes of zero */ } __packed; - -struct copychunk { - __le64 SourceOffset; - __le64 TargetOffset; - __le32 Length; - __le32 Reserved; -} __packed; - -/* this goes in the ioctl buffer when doing a copychunk request */ -struct copychunk_ioctl { - char SourceKey[COPY_CHUNK_RES_KEY_SIZE]; - __le32 ChunkCount; - __le32 Reserved; - struct copychunk Chunks[]; -} __packed; - -struct copychunk_ioctl_rsp { - __le32 ChunksWritten; - __le32 ChunkBytesWritten; - __le32 TotalBytesWritten; -} __packed; - /* See MS-FSCC 2.3.29 and 2.3.30 */ struct get_retrieval_pointer_count_req { __le64 StartingVcn; /* virtual cluster number (signed) */ diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h index 4c254957200b..1bd5835c56e4 100644 --- a/fs/smb/common/smb2pdu.h +++ b/fs/smb/common/smb2pdu.h @@ -1388,6 +1388,35 @@ struct smb2_ioctl_req { __u8 Buffer[]; } __packed; +/* See MS-SMB2 2.2.31.1.1 */ +struct srv_copychunk { + __le64 SourceOffset; + __le64 TargetOffset; + __le32 Length; + __le32 Reserved; +} __packed; + +#define COPY_CHUNK_RES_KEY_SIZE 24 + +/* See MS-SMB2 2.2.31.1 */ +/* this goes in the ioctl buffer when doing a copychunk request */ +struct copychunk_ioctl_req { + union { + char SourceKey[COPY_CHUNK_RES_KEY_SIZE]; + __le64 SourceKeyU64[3]; + }; + __le32 ChunkCount; + __le32 Reserved; + struct srv_copychunk Chunks[] __counted_by_le(ChunkCount); +} __packed; + +/* See MS-SMB2 2.2.32.1 */ +struct copychunk_ioctl_rsp { + __le32 ChunksWritten; + __le32 ChunkBytesWritten; + __le32 TotalBytesWritten; +} __packed; + struct smb2_ioctl_rsp { struct smb2_hdr hdr; __le16 StructureSize; /* Must be 49 */ diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index c5426f57cadf..33f89dca1920 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -7754,11 +7754,11 @@ static int fsctl_copychunk(struct ksmbd_work *work, } src_fp = ksmbd_lookup_foreign_fd(work, - le64_to_cpu(ci_req->ResumeKey[0])); + le64_to_cpu(ci_req->SourceKeyU64[0])); dst_fp = ksmbd_lookup_fd_slow(work, volatile_id, persistent_id); ret = -EINVAL; if (!src_fp || - src_fp->persistent_id != le64_to_cpu(ci_req->ResumeKey[1])) { + src_fp->persistent_id != le64_to_cpu(ci_req->SourceKeyU64[1])) { rsp->hdr.Status = STATUS_OBJECT_NAME_NOT_FOUND; goto out; } diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h index ac2207299735..284d6771060e 100644 --- a/fs/smb/server/smb2pdu.h +++ b/fs/smb/server/smb2pdu.h @@ -174,26 +174,6 @@ struct resume_key_ioctl_rsp { __u8 Context[4]; /* ignored, Windows sets to 4 bytes of zero */ } __packed; -struct srv_copychunk { - __le64 SourceOffset; - __le64 TargetOffset; - __le32 Length; - __le32 Reserved; -} __packed; - -struct copychunk_ioctl_req { - __le64 ResumeKey[3]; - __le32 ChunkCount; - __le32 Reserved; - struct srv_copychunk Chunks[] __counted_by_le(ChunkCount); -} __packed; - -struct copychunk_ioctl_rsp { - __le32 ChunksWritten; - __le32 ChunkBytesWritten; - __le32 TotalBytesWritten; -} __packed; - struct file_sparse { __u8 SetSparse; } __packed; From 9c98f5eec877976dad1179149038a4b164e236b1 Mon Sep 17 00:00:00 2001 From: ZhangGuoDong Date: Mon, 27 Oct 2025 15:22:05 +0800 Subject: [PATCH 16/44] smb: move resume_key_ioctl_rsp to common/smb2pdu.h Rename 2 places: - resume_key_req -> resume_key_ioctl_rsp - server: ResumeKey -> ResumeKeyU64 Merge the struct members of the server and the client, then move duplicate definitions to common header file. Co-developed-by: ChenXiaoSong Signed-off-by: ChenXiaoSong Signed-off-by: ZhangGuoDong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/smb2ops.c | 4 ++-- fs/smb/client/smb2pdu.h | 6 ------ fs/smb/common/smb2pdu.h | 10 ++++++++++ fs/smb/server/smb2pdu.c | 4 ++-- fs/smb/server/smb2pdu.h | 6 ------ 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index dd569cc5abcc..4b005a7adce0 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -1528,7 +1528,7 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon, { int rc; unsigned int ret_data_len; - struct resume_key_req *res_key; + struct resume_key_ioctl_rsp *res_key; rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid, FSCTL_SRV_REQUEST_RESUME_KEY, NULL, 0 /* no input */, @@ -1541,7 +1541,7 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon, cifs_tcon_dbg(VFS, "refcpy ioctl error %d getting resume key\n", rc); goto req_res_key_exit; } - if (ret_data_len < sizeof(struct resume_key_req)) { + if (ret_data_len < sizeof(struct resume_key_ioctl_rsp)) { cifs_tcon_dbg(VFS, "Invalid refcopy resume key length\n"); rc = -EINVAL; goto req_res_key_exit; diff --git a/fs/smb/client/smb2pdu.h b/fs/smb/client/smb2pdu.h index de2d83c6463c..0ce9f93f108f 100644 --- a/fs/smb/client/smb2pdu.h +++ b/fs/smb/client/smb2pdu.h @@ -193,12 +193,6 @@ struct crt_sd_ctxt { struct smb3_sd sd; } __packed; -struct resume_key_req { - char ResumeKey[COPY_CHUNK_RES_KEY_SIZE]; - __le32 ContextLength; /* MBZ */ - char Context[]; /* ignored, Windows sets to 4 bytes of zero */ -} __packed; - /* See MS-FSCC 2.3.29 and 2.3.30 */ struct get_retrieval_pointer_count_req { __le64 StartingVcn; /* virtual cluster number (signed) */ diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h index 1bd5835c56e4..a7ea4214d061 100644 --- a/fs/smb/common/smb2pdu.h +++ b/fs/smb/common/smb2pdu.h @@ -1417,6 +1417,16 @@ struct copychunk_ioctl_rsp { __le32 TotalBytesWritten; } __packed; +/* See MS-SMB2 2.2.32.3 */ +struct resume_key_ioctl_rsp { + union { + char ResumeKey[COPY_CHUNK_RES_KEY_SIZE]; + __u64 ResumeKeyU64[3]; + }; + __le32 ContextLength; /* MBZ */ + char Context[]; /* ignored, Windows sets to 4 bytes of zero */ +} __packed; + struct smb2_ioctl_rsp { struct smb2_hdr hdr; __le16 StructureSize; /* Must be 49 */ diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 33f89dca1920..2cef4e192dbe 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -8112,8 +8112,8 @@ static int fsctl_request_resume_key(struct ksmbd_work *work, return -ENOENT; memset(key_rsp, 0, sizeof(*key_rsp)); - key_rsp->ResumeKey[0] = req->VolatileFileId; - key_rsp->ResumeKey[1] = req->PersistentFileId; + key_rsp->ResumeKeyU64[0] = req->VolatileFileId; + key_rsp->ResumeKeyU64[1] = req->PersistentFileId; ksmbd_fd_put(work, fp); return 0; diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h index 284d6771060e..807079d19d1e 100644 --- a/fs/smb/server/smb2pdu.h +++ b/fs/smb/server/smb2pdu.h @@ -168,12 +168,6 @@ struct file_object_buf_type1_ioctl_rsp { __u8 DomainId[16]; } __packed; -struct resume_key_ioctl_rsp { - __u64 ResumeKey[3]; - __le32 ContextLength; - __u8 Context[4]; /* ignored, Windows sets to 4 bytes of zero */ -} __packed; - struct file_sparse { __u8 SetSparse; } __packed; From 5d510ac31626ed157d2182149559430350cf2104 Mon Sep 17 00:00:00 2001 From: Qianchang Zhao Date: Sun, 9 Nov 2025 10:00:55 +0900 Subject: [PATCH 17/44] ksmbd: skip lock-range check on equal size to avoid size==0 underflow When size equals the current i_size (including 0), the code used to call check_lock_range(filp, i_size, size - 1, WRITE), which computes `size - 1` and can underflow for size==0. Skip the equal case. Cc: stable@vger.kernel.org Reported-by: Qianchang Zhao Reported-by: Zhitong Liu Signed-off-by: Qianchang Zhao Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/vfs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c index 891ed2dc2b73..90e693e4e414 100644 --- a/fs/smb/server/vfs.c +++ b/fs/smb/server/vfs.c @@ -324,6 +324,9 @@ static int check_lock_range(struct file *filp, loff_t start, loff_t end, struct file_lock_context *ctx = locks_inode_context(file_inode(filp)); int error = 0; + if (start == end) + return 0; + if (!ctx || list_empty_careful(&ctx->flc_posix)) return 0; @@ -828,7 +831,7 @@ int ksmbd_vfs_truncate(struct ksmbd_work *work, if (size < inode->i_size) { err = check_lock_range(filp, size, inode->i_size - 1, WRITE); - } else { + } else if (size > inode->i_size) { err = check_lock_range(filp, inode->i_size, size - 1, WRITE); } From 4a7f9607803203fe637c12b4ffce9973d85ee169 Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Sun, 2 Nov 2025 15:30:46 +0800 Subject: [PATCH 18/44] smb/client: fix CAP_BULK_TRANSFER value See MS-CIFS 2.2.4.52.2. Keep it consistent with the value in the documentation. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/cifspdu.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h index c86a329e5822..aba9caee8302 100644 --- a/fs/smb/client/cifspdu.h +++ b/fs/smb/client/cifspdu.h @@ -711,7 +711,12 @@ struct ntlmv2_resp { #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" -/* Capabilities bits (for NTLM SessSetup request) */ + +/* + * Capabilities bits (for NTLM SessSetup request) + * See MS-CIFS 2.2.4.52.2 + * MS-SMB 2.2.4.5.2.1 + */ #define CAP_UNICODE 0x00000004 #define CAP_LARGE_FILES 0x00000008 #define CAP_NT_SMBS 0x00000010 @@ -719,7 +724,7 @@ struct ntlmv2_resp { #define CAP_LEVEL_II_OPLOCKS 0x00000080 #define CAP_NT_FIND 0x00000200 /* reserved should be zero (because NT_SMBs implies the same thing?) */ -#define CAP_BULK_TRANSFER 0x20000000 +#define CAP_BULK_TRANSFER 0x00000400 #define CAP_EXTENDED_SECURITY 0x80000000 /* Action bits */ From 884a1d4e9c09b4a0dbe748890bdd48aac8e5a6b6 Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Sun, 2 Nov 2025 15:30:47 +0800 Subject: [PATCH 19/44] smb: move MAX_CIFS_SMALL_BUFFER_SIZE to common/smbglob.h In order to maintain the code more easily, move duplicate definitions to common header file. By the way, add the copyright and author information for Namjae to common/smbglob.h. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/cifspdu.h | 1 - fs/smb/common/smbglob.h | 4 ++++ fs/smb/server/smb_common.h | 2 -- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h index aba9caee8302..2fb1eb2fff41 100644 --- a/fs/smb/client/cifspdu.h +++ b/fs/smb/client/cifspdu.h @@ -86,7 +86,6 @@ #define NT_TRANSACT_GET_USER_QUOTA 0x07 #define NT_TRANSACT_SET_USER_QUOTA 0x08 -#define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */ /* future chained NTCreateXReadX bigger, but for time being NTCreateX biggest */ /* among the requests (NTCreateX response is bigger with wct of 34) */ #define MAX_CIFS_HDR_SIZE 0x58 /* 4 len + 32 hdr + (2*24 wct) + 2 bct + 2 pad */ diff --git a/fs/smb/common/smbglob.h b/fs/smb/common/smbglob.h index fa3d30dc6022..7853b5771128 100644 --- a/fs/smb/common/smbglob.h +++ b/fs/smb/common/smbglob.h @@ -2,8 +2,10 @@ /* * * Copyright (C) International Business Machines Corp., 2002,2008 + * 2018 Samsung Electronics Co., Ltd. * Author(s): Steve French (sfrench@us.ibm.com) * Jeremy Allison (jra@samba.org) + * Namjae Jeon (linkinjeon@kernel.org) * */ #ifndef _COMMON_SMB_GLOB_H @@ -65,4 +67,6 @@ static inline void inc_rfc1001_len(void *buf, int count) #define CIFS_DEFAULT_IOSIZE (1024 * 1024) +#define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */ + #endif /* _COMMON_SMB_GLOB_H */ diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h index 0e291fe2d190..2669e68dba3a 100644 --- a/fs/smb/server/smb_common.h +++ b/fs/smb/server/smb_common.h @@ -29,8 +29,6 @@ #define SMB_ECHO_INTERVAL (60 * HZ) -#define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */ - #define MAX_STREAM_PROT_LEN 0x00FFFFFF /* Responses when opening a file. */ From 833a75fc9ecc3856a52223d8c245e52703e0a9f1 Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Sun, 2 Nov 2025 15:30:48 +0800 Subject: [PATCH 20/44] smb: move create_durable_req_v2 to common/smb2pdu.h Modify the following places: - some fields in "struct create_durable_req_v2" -> struct durable_context_v2 - durable_context_v2 -> durable_context_v2_req - create_durable_v2 -> create_durable_req_v2 Then move duplicate definitions to common header file. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/smb2pdu.c | 14 +++++++------- fs/smb/client/smb2pdu.h | 12 ------------ fs/smb/common/smb2pdu.h | 14 ++++++++++++++ fs/smb/server/smb2pdu.c | 8 ++++---- fs/smb/server/smb2pdu.h | 9 --------- 5 files changed, 25 insertions(+), 32 deletions(-) diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 8b4a4573e9c3..fe2147c45839 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2424,21 +2424,21 @@ add_lease_context(struct TCP_Server_Info *server, return 0; } -static struct create_durable_v2 * +static struct create_durable_req_v2 * create_durable_v2_buf(struct cifs_open_parms *oparms) { struct cifs_fid *pfid = oparms->fid; - struct create_durable_v2 *buf; + struct create_durable_req_v2 *buf; - buf = kzalloc(sizeof(struct create_durable_v2), GFP_KERNEL); + buf = kzalloc(sizeof(struct create_durable_req_v2), GFP_KERNEL); if (!buf) return NULL; buf->ccontext.DataOffset = cpu_to_le16(offsetof - (struct create_durable_v2, dcontext)); - buf->ccontext.DataLength = cpu_to_le32(sizeof(struct durable_context_v2)); + (struct create_durable_req_v2, dcontext)); + buf->ccontext.DataLength = cpu_to_le32(sizeof(struct durable_context_v2_req)); buf->ccontext.NameOffset = cpu_to_le16(offsetof - (struct create_durable_v2, Name)); + (struct create_durable_req_v2, Name)); buf->ccontext.NameLength = cpu_to_le16(4); /* @@ -2508,7 +2508,7 @@ add_durable_v2_context(struct kvec *iov, unsigned int *num_iovec, iov[num].iov_base = create_durable_v2_buf(oparms); if (iov[num].iov_base == NULL) return -ENOMEM; - iov[num].iov_len = sizeof(struct create_durable_v2); + iov[num].iov_len = sizeof(struct create_durable_req_v2); *num_iovec = num + 1; return 0; } diff --git a/fs/smb/client/smb2pdu.h b/fs/smb/client/smb2pdu.h index 0ce9f93f108f..a700b404a57c 100644 --- a/fs/smb/client/smb2pdu.h +++ b/fs/smb/client/smb2pdu.h @@ -137,18 +137,6 @@ struct share_redirect_error_context_rsp { /* See MS-SMB2 2.2.13.2.11 */ /* Flags */ #define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002 -struct durable_context_v2 { - __le32 Timeout; - __le32 Flags; - __u64 Reserved; - __u8 CreateGuid[16]; -} __packed; - -struct create_durable_v2 { - struct create_context_hdr ccontext; - __u8 Name[8]; - struct durable_context_v2 dcontext; -} __packed; /* See MS-SMB2 2.2.13.2.12 */ struct durable_reconnect_context_v2 { diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h index a7ea4214d061..681855ebacc9 100644 --- a/fs/smb/common/smb2pdu.h +++ b/fs/smb/common/smb2pdu.h @@ -1290,6 +1290,20 @@ struct create_mxac_req { __le64 Timestamp; } __packed; +/* See MS-SMB2 2.2.13.2.11 */ +struct durable_context_v2_req { + __le32 Timeout; + __le32 Flags; /* see SMB2_DHANDLE_FLAG_PERSISTENT */ + __u64 Reserved; + __u8 CreateGuid[16]; +} __packed; + +struct create_durable_req_v2 { + struct create_context_hdr ccontext; + __u8 Name[8]; + struct durable_context_v2_req dcontext; +} __packed; + /* See MS-SMB2 2.2.14.2.5 */ struct create_mxac_rsp { struct create_context_hdr ccontext; diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 2cef4e192dbe..07d21d2f882f 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2806,7 +2806,7 @@ static int parse_durable_handle_context(struct ksmbd_work *work, durable_v2_blob = (struct create_durable_req_v2 *)context; ksmbd_debug(SMB, "Request for durable v2 open\n"); - dh_info->fp = ksmbd_lookup_fd_cguid(durable_v2_blob->CreateGuid); + dh_info->fp = ksmbd_lookup_fd_cguid(durable_v2_blob->dcontext.CreateGuid); if (dh_info->fp) { if (!memcmp(conn->ClientGUID, dh_info->fp->client_guid, SMB2_CLIENT_GUID_SIZE)) { @@ -2824,11 +2824,11 @@ static int parse_durable_handle_context(struct ksmbd_work *work, if ((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) || req_op_level == SMB2_OPLOCK_LEVEL_BATCH) { dh_info->CreateGuid = - durable_v2_blob->CreateGuid; + durable_v2_blob->dcontext.CreateGuid; dh_info->persistent = - le32_to_cpu(durable_v2_blob->Flags); + le32_to_cpu(durable_v2_blob->dcontext.Flags); dh_info->timeout = - le32_to_cpu(durable_v2_blob->Timeout); + le32_to_cpu(durable_v2_blob->dcontext.Timeout); dh_info->type = dh_idx; } break; diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h index 807079d19d1e..93d43da626d4 100644 --- a/fs/smb/server/smb2pdu.h +++ b/fs/smb/server/smb2pdu.h @@ -66,15 +66,6 @@ struct preauth_integrity_info { /* Apple Defined Contexts */ #define SMB2_CREATE_AAPL "AAPL" -struct create_durable_req_v2 { - struct create_context_hdr ccontext; - __u8 Name[8]; - __le32 Timeout; - __le32 Flags; - __u8 Reserved[8]; - __u8 CreateGuid[16]; -} __packed; - #define DURABLE_HANDLE_MAX_TIMEOUT 300000 struct create_durable_reconn_req { From 81a45de432c6c7d82821fb09cb9fc1cf58629f3a Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Sun, 2 Nov 2025 15:30:49 +0800 Subject: [PATCH 21/44] smb: move create_durable_handle_reconnect_v2 to common/smb2pdu.h Modify the following places: - some fields in "struct create_durable_reconn_v2_req" -> struct durable_reconnect_context_v2 - create_durable_reconn_v2_req -> create_durable_handle_reconnect_v2 Then move duplicate definitions to common header file. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/smb2pdu.h | 17 ----------------- fs/smb/common/smb2pdu.h | 16 ++++++++++++++++ fs/smb/server/smb2pdu.c | 10 +++++----- fs/smb/server/smb2pdu.h | 11 ----------- 4 files changed, 21 insertions(+), 33 deletions(-) diff --git a/fs/smb/client/smb2pdu.h b/fs/smb/client/smb2pdu.h index a700b404a57c..741ceabc3bba 100644 --- a/fs/smb/client/smb2pdu.h +++ b/fs/smb/client/smb2pdu.h @@ -138,29 +138,12 @@ struct share_redirect_error_context_rsp { /* Flags */ #define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002 -/* See MS-SMB2 2.2.13.2.12 */ -struct durable_reconnect_context_v2 { - struct { - __u64 PersistentFileId; - __u64 VolatileFileId; - } Fid; - __u8 CreateGuid[16]; - __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */ -} __packed; - /* See MS-SMB2 2.2.14.2.12 */ struct durable_reconnect_context_v2_rsp { __le32 Timeout; __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */ } __packed; -struct create_durable_handle_reconnect_v2 { - struct create_context_hdr ccontext; - __u8 Name[8]; - struct durable_reconnect_context_v2 dcontext; - __u8 Pad[4]; -} __packed; - /* See MS-SMB2 2.2.13.2.5 */ struct crt_twarp_ctxt { struct create_context_hdr ccontext; diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h index 681855ebacc9..77b1b8eb9c0e 100644 --- a/fs/smb/common/smb2pdu.h +++ b/fs/smb/common/smb2pdu.h @@ -1304,6 +1304,22 @@ struct create_durable_req_v2 { struct durable_context_v2_req dcontext; } __packed; +/* See MS-SMB2 2.2.13.2.12 */ +struct durable_reconnect_context_v2 { + struct { + __u64 PersistentFileId; + __u64 VolatileFileId; + } Fid; + __u8 CreateGuid[16]; + __le32 Flags; /* see SMB2_DHANDLE_FLAG_PERSISTENT */ +} __packed; + +struct create_durable_handle_reconnect_v2 { + struct create_context_hdr ccontext; + __u8 Name[8]; + struct durable_reconnect_context_v2 dcontext; +} __packed; + /* See MS-SMB2 2.2.14.2.5 */ struct create_mxac_rsp { struct create_context_hdr ccontext; diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 07d21d2f882f..77438830e2de 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2716,7 +2716,7 @@ static int parse_durable_handle_context(struct ksmbd_work *work, switch (dh_idx) { case DURABLE_RECONN_V2: { - struct create_durable_reconn_v2_req *recon_v2; + struct create_durable_handle_reconnect_v2 *recon_v2; if (dh_info->type == DURABLE_RECONN || dh_info->type == DURABLE_REQ_V2) { @@ -2726,13 +2726,13 @@ static int parse_durable_handle_context(struct ksmbd_work *work, if (le16_to_cpu(context->DataOffset) + le32_to_cpu(context->DataLength) < - sizeof(struct create_durable_reconn_v2_req)) { + sizeof(struct create_durable_handle_reconnect_v2)) { err = -EINVAL; goto out; } - recon_v2 = (struct create_durable_reconn_v2_req *)context; - persistent_id = recon_v2->Fid.PersistentFileId; + recon_v2 = (struct create_durable_handle_reconnect_v2 *)context; + persistent_id = recon_v2->dcontext.Fid.PersistentFileId; dh_info->fp = ksmbd_lookup_durable_fd(persistent_id); if (!dh_info->fp) { ksmbd_debug(SMB, "Failed to get durable handle state\n"); @@ -2740,7 +2740,7 @@ static int parse_durable_handle_context(struct ksmbd_work *work, goto out; } - if (memcmp(dh_info->fp->create_guid, recon_v2->CreateGuid, + if (memcmp(dh_info->fp->create_guid, recon_v2->dcontext.CreateGuid, SMB2_CREATE_GUID_SIZE)) { err = -EBADF; ksmbd_put_durable_fd(dh_info->fp); diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h index 93d43da626d4..d4026d313d67 100644 --- a/fs/smb/server/smb2pdu.h +++ b/fs/smb/server/smb2pdu.h @@ -80,17 +80,6 @@ struct create_durable_reconn_req { } Data; } __packed; -struct create_durable_reconn_v2_req { - struct create_context_hdr ccontext; - __u8 Name[8]; - struct { - __u64 PersistentFileId; - __u64 VolatileFileId; - } Fid; - __u8 CreateGuid[16]; - __le32 Flags; -} __packed; - struct create_alloc_size_req { struct create_context_hdr ccontext; __u8 Name[8]; From 96721fd292264d712b7b9a51752ab87de5035db4 Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Sun, 2 Nov 2025 15:30:50 +0800 Subject: [PATCH 22/44] smb: move create_durable_rsp_v2 to common/smb2pdu.h Modify the following places: - some fields in "struct create_durable_v2_rsp" -> struct durable_context_v2_rsp - durable_reconnect_context_v2_rsp -> durable_context_v2_rsp - create_durable_v2_rsp -> create_durable_rsp_v2 Then move them to common header file. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/smb2pdu.h | 6 ------ fs/smb/common/smb2pdu.h | 12 ++++++++++++ fs/smb/server/oplock.c | 8 ++++---- fs/smb/server/smb2ops.c | 6 +++--- fs/smb/server/smb2pdu.h | 6 ------ 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/fs/smb/client/smb2pdu.h b/fs/smb/client/smb2pdu.h index 741ceabc3bba..32da7a4773e1 100644 --- a/fs/smb/client/smb2pdu.h +++ b/fs/smb/client/smb2pdu.h @@ -138,12 +138,6 @@ struct share_redirect_error_context_rsp { /* Flags */ #define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002 -/* See MS-SMB2 2.2.14.2.12 */ -struct durable_reconnect_context_v2_rsp { - __le32 Timeout; - __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */ -} __packed; - /* See MS-SMB2 2.2.13.2.5 */ struct crt_twarp_ctxt { struct create_context_hdr ccontext; diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h index 77b1b8eb9c0e..4ea515732b38 100644 --- a/fs/smb/common/smb2pdu.h +++ b/fs/smb/common/smb2pdu.h @@ -1320,6 +1320,18 @@ struct create_durable_handle_reconnect_v2 { struct durable_reconnect_context_v2 dcontext; } __packed; +/* See MS-SMB2 2.2.14.2.12 */ +struct durable_context_v2_rsp { + __le32 Timeout; + __le32 Flags; /* see SMB2_DHANDLE_FLAG_PERSISTENT */ +} __packed; + +struct create_durable_rsp_v2 { + struct create_context_hdr ccontext; + __u8 Name[8]; + struct durable_context_v2_rsp dcontext; +} __packed; + /* See MS-SMB2 2.2.14.2.5 */ struct create_mxac_rsp { struct create_context_hdr ccontext; diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c index a04d5702820d..1f07ebf431d7 100644 --- a/fs/smb/server/oplock.c +++ b/fs/smb/server/oplock.c @@ -1617,9 +1617,9 @@ void create_durable_rsp_buf(char *cc) */ void create_durable_v2_rsp_buf(char *cc, struct ksmbd_file *fp) { - struct create_durable_v2_rsp *buf; + struct create_durable_rsp_v2 *buf; - buf = (struct create_durable_v2_rsp *)cc; + buf = (struct create_durable_rsp_v2 *)cc; memset(buf, 0, sizeof(struct create_durable_rsp)); buf->ccontext.DataOffset = cpu_to_le16(offsetof (struct create_durable_rsp, Data)); @@ -1633,9 +1633,9 @@ void create_durable_v2_rsp_buf(char *cc, struct ksmbd_file *fp) buf->Name[2] = '2'; buf->Name[3] = 'Q'; - buf->Timeout = cpu_to_le32(fp->durable_timeout); + buf->dcontext.Timeout = cpu_to_le32(fp->durable_timeout); if (fp->is_persistent) - buf->Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT); + buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT); } /** diff --git a/fs/smb/server/smb2ops.c b/fs/smb/server/smb2ops.c index bcf05caa2304..edd7eca0714a 100644 --- a/fs/smb/server/smb2ops.c +++ b/fs/smb/server/smb2ops.c @@ -59,7 +59,7 @@ static struct smb_version_values smb30_server_values = { .cap_large_files = SMB2_LARGE_FILES, .create_lease_size = sizeof(struct create_lease_v2), .create_durable_size = sizeof(struct create_durable_rsp), - .create_durable_v2_size = sizeof(struct create_durable_v2_rsp), + .create_durable_v2_size = sizeof(struct create_durable_rsp_v2), .create_mxac_size = sizeof(struct create_mxac_rsp), .create_disk_id_size = sizeof(struct create_disk_id_rsp), .create_posix_size = sizeof(struct create_posix_rsp), @@ -86,7 +86,7 @@ static struct smb_version_values smb302_server_values = { .cap_large_files = SMB2_LARGE_FILES, .create_lease_size = sizeof(struct create_lease_v2), .create_durable_size = sizeof(struct create_durable_rsp), - .create_durable_v2_size = sizeof(struct create_durable_v2_rsp), + .create_durable_v2_size = sizeof(struct create_durable_rsp_v2), .create_mxac_size = sizeof(struct create_mxac_rsp), .create_disk_id_size = sizeof(struct create_disk_id_rsp), .create_posix_size = sizeof(struct create_posix_rsp), @@ -113,7 +113,7 @@ static struct smb_version_values smb311_server_values = { .cap_large_files = SMB2_LARGE_FILES, .create_lease_size = sizeof(struct create_lease_v2), .create_durable_size = sizeof(struct create_durable_rsp), - .create_durable_v2_size = sizeof(struct create_durable_v2_rsp), + .create_durable_v2_size = sizeof(struct create_durable_rsp_v2), .create_mxac_size = sizeof(struct create_mxac_rsp), .create_disk_id_size = sizeof(struct create_disk_id_rsp), .create_posix_size = sizeof(struct create_posix_rsp), diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h index d4026d313d67..46e14bd4f2da 100644 --- a/fs/smb/server/smb2pdu.h +++ b/fs/smb/server/smb2pdu.h @@ -98,12 +98,6 @@ struct create_durable_rsp { /* See MS-SMB2 2.2.13.2.11 */ /* Flags */ #define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002 -struct create_durable_v2_rsp { - struct create_context_hdr ccontext; - __u8 Name[8]; - __le32 Timeout; - __le32 Flags; -} __packed; /* equivalent of the contents of SMB3.1.1 POSIX open context response */ struct create_posix_rsp { From 1172d8598499a006d172bb24bebaa3fdc99064a8 Mon Sep 17 00:00:00 2001 From: ZhangGuoDong Date: Sun, 2 Nov 2025 15:30:52 +0800 Subject: [PATCH 23/44] smb: move some duplicate definitions to common/smb2pdu.h In order to maintain the code more easily, move duplicate definitions to common header file. There are only 4 different definitions, the client uses cpu_to_le16() but the server does not: - RSS_CAPABLE - RDMA_CAPABLE - INTERNETWORK - INTERNETWORKV6 The other definitions are exactly the same on both client and server. The struct smb_hdr is defined in MS-CIFS and MS-SMB, but it's also used by SMB2 and SMB3, so move it to the common smb2pdu.h. Co-developed-by: ChenXiaoSong Signed-off-by: ChenXiaoSong Signed-off-by: ZhangGuoDong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/cifspdu.h | 135 +---------------------------- fs/smb/client/smb2pdu.h | 21 ----- fs/smb/common/smb2pdu.h | 172 +++++++++++++++++++++++++++++++++++-- fs/smb/server/smb2pdu.c | 8 +- fs/smb/server/smb2pdu.h | 19 ---- fs/smb/server/smb_common.h | 75 +--------------- 6 files changed, 173 insertions(+), 257 deletions(-) diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h index 2fb1eb2fff41..99cdba9f68dc 100644 --- a/fs/smb/client/cifspdu.h +++ b/fs/smb/client/cifspdu.h @@ -12,6 +12,7 @@ #include #include #include "../common/smbfsctl.h" +#include "../common/smb2pdu.h" #define CIFS_PROT 0 #define POSIX_PROT (CIFS_PROT+1) @@ -179,98 +180,7 @@ #define SMBFLG2_ERR_STATUS cpu_to_le16(0x4000) #define SMBFLG2_UNICODE cpu_to_le16(0x8000) -/* - * These are the file access permission bits defined in CIFS for the - * NTCreateAndX as well as the level 0x107 - * TRANS2_QUERY_PATH_INFORMATION API. The level 0x107, SMB_QUERY_FILE_ALL_INFO - * responds with the AccessFlags. - * The AccessFlags specifies the access permissions a caller has to the - * file and can have any suitable combination of the following values: - */ - -#define FILE_READ_DATA 0x00000001 /* Data can be read from the file */ - /* or directory child entries can */ - /* be listed together with the */ - /* associated child attributes */ - /* (so the FILE_READ_ATTRIBUTES on */ - /* the child entry is not needed) */ -#define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */ - /* or new file can be created in */ - /* the directory */ -#define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */ - /* (for non-local files over SMB it */ - /* is same as FILE_WRITE_DATA) */ - /* or new subdirectory can be */ - /* created in the directory */ -#define FILE_READ_EA 0x00000008 /* Extended attributes associated */ - /* with the file can be read */ -#define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */ - /* with the file can be written */ -#define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */ - /* the file using system paging I/O */ - /* for executing the file / script */ - /* or right to traverse directory */ - /* (but by default all users have */ - /* directory bypass traverse */ - /* privilege and do not need this */ - /* permission on directories at all)*/ -#define FILE_DELETE_CHILD 0x00000040 /* Child entry can be deleted from */ - /* the directory (so the DELETE on */ - /* the child entry is not needed) */ -#define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */ - /* file or directory can be read */ -#define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */ - /* file or directory can be written */ -#define DELETE 0x00010000 /* The file or dir can be deleted */ -#define READ_CONTROL 0x00020000 /* The discretionary access control */ - /* list and ownership associated */ - /* with the file or dir can be read */ -#define WRITE_DAC 0x00040000 /* The discretionary access control */ - /* list associated with the file or */ - /* directory can be written */ -#define WRITE_OWNER 0x00080000 /* Ownership information associated */ - /* with the file/dir can be written */ -#define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ - /* synchronize with the completion */ - /* of an input/output request */ -#define SYSTEM_SECURITY 0x01000000 /* The system access control list */ - /* associated with the file or */ - /* directory can be read or written */ - /* (cannot be in DACL, can in SACL) */ -#define MAXIMUM_ALLOWED 0x02000000 /* Maximal subset of GENERIC_ALL */ - /* permissions which can be granted */ - /* (cannot be in DACL nor SACL) */ -#define GENERIC_ALL 0x10000000 /* Same as: GENERIC_EXECUTE | */ - /* GENERIC_WRITE | */ - /* GENERIC_READ | */ - /* FILE_DELETE_CHILD | */ - /* DELETE | */ - /* WRITE_DAC | */ - /* WRITE_OWNER */ - /* So GENERIC_ALL contains all bits */ - /* mentioned above except these two */ - /* SYSTEM_SECURITY MAXIMUM_ALLOWED */ -#define GENERIC_EXECUTE 0x20000000 /* Same as: FILE_EXECUTE | */ - /* FILE_READ_ATTRIBUTES | */ - /* READ_CONTROL | */ - /* SYNCHRONIZE */ -#define GENERIC_WRITE 0x40000000 /* Same as: FILE_WRITE_DATA | */ - /* FILE_APPEND_DATA | */ - /* FILE_WRITE_EA | */ - /* FILE_WRITE_ATTRIBUTES | */ - /* READ_CONTROL | */ - /* SYNCHRONIZE */ -#define GENERIC_READ 0x80000000 /* Same as: FILE_READ_DATA | */ - /* FILE_READ_EA | */ - /* FILE_READ_ATTRIBUTES | */ - /* READ_CONTROL | */ - /* SYNCHRONIZE */ - -#define FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES) -#define FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \ - | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) -#define FILE_EXEC_RIGHTS (FILE_EXECUTE) - +/* Combinations of file access permission bits */ #define SET_FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_WRITE_EA \ | FILE_READ_ATTRIBUTES \ | FILE_WRITE_ATTRIBUTES \ @@ -282,15 +192,6 @@ | FILE_WRITE_ATTRIBUTES \ | DELETE | READ_CONTROL | WRITE_DAC \ | WRITE_OWNER | SYNCHRONIZE) -#define SET_FILE_EXEC_RIGHTS (FILE_READ_EA | FILE_WRITE_EA | FILE_EXECUTE \ - | FILE_READ_ATTRIBUTES \ - | FILE_WRITE_ATTRIBUTES \ - | DELETE | READ_CONTROL | WRITE_DAC \ - | WRITE_OWNER | SYNCHRONIZE) - -#define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \ - | READ_CONTROL | SYNCHRONIZE) - /* * Invalid readdir handle @@ -416,38 +317,6 @@ #define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */ #define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ -struct smb_hdr { - __be32 smb_buf_length; /* BB length is only two (rarely three) bytes, - with one or two byte "type" preceding it that will be - zero - we could mask the type byte off */ - __u8 Protocol[4]; - __u8 Command; - union { - struct { - __u8 ErrorClass; - __u8 Reserved; - __le16 Error; - } __attribute__((packed)) DosError; - __le32 CifsError; - } __attribute__((packed)) Status; - __u8 Flags; - __le16 Flags2; /* note: le */ - __le16 PidHigh; - union { - struct { - __le32 SequenceNumber; /* le */ - __u32 Reserved; /* zero */ - } __attribute__((packed)) Sequence; - __u8 SecuritySignature[8]; /* le */ - } __attribute__((packed)) Signature; - __u8 pad[2]; - __u16 Tid; - __le16 Pid; - __u16 Uid; - __le16 Mid; - __u8 WordCount; -} __attribute__((packed)); - /* given a pointer to an smb_hdr, retrieve a void pointer to the ByteCount */ static inline void * BCC(struct smb_hdr *smb) diff --git a/fs/smb/client/smb2pdu.h b/fs/smb/client/smb2pdu.h index 32da7a4773e1..98ed7a22cd57 100644 --- a/fs/smb/client/smb2pdu.h +++ b/fs/smb/client/smb2pdu.h @@ -133,11 +133,6 @@ struct share_redirect_error_context_rsp { #define SMB2_LEASE_HANDLE_CACHING_HE 0x02 #define SMB2_LEASE_WRITE_CACHING_HE 0x04 - -/* See MS-SMB2 2.2.13.2.11 */ -/* Flags */ -#define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002 - /* See MS-SMB2 2.2.13.2.5 */ struct crt_twarp_ctxt { struct create_context_hdr ccontext; @@ -198,22 +193,6 @@ struct network_resiliency_req { } __packed; /* There is no buffer for the response ie no struct network_resiliency_rsp */ -#define RSS_CAPABLE cpu_to_le32(0x00000001) -#define RDMA_CAPABLE cpu_to_le32(0x00000002) - -#define INTERNETWORK cpu_to_le16(0x0002) -#define INTERNETWORKV6 cpu_to_le16(0x0017) - -struct network_interface_info_ioctl_rsp { - __le32 Next; /* next interface. zero if this is last one */ - __le32 IfIndex; - __le32 Capability; /* RSS or RDMA Capable */ - __le32 Reserved; - __le64 LinkSpeed; - __le16 Family; - __u8 Buffer[126]; -} __packed; - #define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */ struct compress_ioctl { diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h index 4ea515732b38..be1e652bb474 100644 --- a/fs/smb/common/smb2pdu.h +++ b/fs/smb/common/smb2pdu.h @@ -1149,12 +1149,6 @@ struct smb2_server_client_notification { #define FILE_OVERWRITE_IF_LE cpu_to_le32(0x00000005) #define FILE_CREATE_MASK_LE cpu_to_le32(0x00000007) -#define FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA \ - | FILE_READ_ATTRIBUTES) -#define FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \ - | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) -#define FILE_EXEC_RIGHTS (FILE_EXECUTE) - /* CreateOptions Flags */ #define FILE_DIRECTORY_FILE_LE cpu_to_le32(0x00000001) /* same as #define CREATE_NOT_FILE_LE cpu_to_le32(0x00000001) */ @@ -1290,6 +1284,14 @@ struct create_mxac_req { __le64 Timestamp; } __packed; +/* + * Flags + * See MS-SMB2 2.2.13.2.11 + * MS-SMB2 2.2.13.2.12 + * MS-SMB2 2.2.14.2.12 + */ +#define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002 + /* See MS-SMB2 2.2.13.2.11 */ struct durable_context_v2_req { __le32 Timeout; @@ -1500,6 +1502,26 @@ struct smb_sockaddr_in6 { __be32 ScopeId; } __packed; +/* See MS-SMB2 2.2.32.5 and MS-SMB2 2.2.32.5.1 */ +#define RSS_CAPABLE cpu_to_le32(0x00000001) +#define RDMA_CAPABLE cpu_to_le32(0x00000002) +#define INTERNETWORK cpu_to_le16(0x0002) +#define INTERNETWORKV6 cpu_to_le16(0x0017) +struct network_interface_info_ioctl_rsp { + __le32 Next; /* next interface. zero if this is last one */ + __le32 IfIndex; + __le32 Capability; /* RSS or RDMA Capable */ + __le32 Reserved; + __le64 LinkSpeed; + union { + char SockAddr_Storage[128]; + struct { + __le16 Family; + __u8 Buffer[126]; + }; + }; +} __packed; + /* this goes in the ioctl buffer when doing FSCTL_SET_ZERO_DATA */ struct file_zero_data_information { __le64 FileOffset; @@ -1989,6 +2011,144 @@ struct smb2_lease_ack { __le64 LeaseDuration; } __packed; +/* + * See MS-CIFS 2.2.3.1 + * MS-SMB 2.2.3.1 + */ +struct smb_hdr { + __be32 smb_buf_length; /* BB length is only two (rarely three) bytes, + with one or two byte "type" preceding it that will be + zero - we could mask the type byte off */ + __u8 Protocol[4]; + __u8 Command; + union { + struct { + __u8 ErrorClass; + __u8 Reserved; + __le16 Error; + } __packed DosError; + __le32 CifsError; + } __packed Status; + __u8 Flags; + __le16 Flags2; /* note: le */ + __le16 PidHigh; + union { + struct { + __le32 SequenceNumber; /* le */ + __u32 Reserved; /* zero */ + } __packed Sequence; + __u8 SecuritySignature[8]; /* le */ + } __packed Signature; + __u8 pad[2]; + __u16 Tid; + __le16 Pid; + __u16 Uid; + __le16 Mid; + __u8 WordCount; +} __packed; + #define OP_BREAK_STRUCT_SIZE_20 24 #define OP_BREAK_STRUCT_SIZE_21 36 + +/* + * See MS-SMB2 2.2.13.1.1 + * MS-SMB 2.2.1.4.1 + * These are the file access permission bits defined in CIFS for the + * NTCreateAndX as well as the level 0x107 + * TRANS2_QUERY_PATH_INFORMATION API. The level 0x107, SMB_QUERY_FILE_ALL_INFO + * responds with the AccessFlags. + * The AccessFlags specifies the access permissions a caller has to the + * file and can have any suitable combination of the following values: + */ +#define FILE_READ_DATA 0x00000001 /* Data can be read from the file */ + /* or directory child entries can */ + /* be listed together with the */ + /* associated child attributes */ + /* (so the FILE_READ_ATTRIBUTES on */ + /* the child entry is not needed) */ +#define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */ + /* or new file can be created in */ + /* the directory */ +#define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */ + /* (for non-local files over SMB it */ + /* is same as FILE_WRITE_DATA) */ + /* or new subdirectory can be */ + /* created in the directory */ +#define FILE_READ_EA 0x00000008 /* Extended attributes associated */ + /* with the file can be read */ +#define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */ + /* with the file can be written */ +#define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */ + /* the file using system paging I/O */ + /* for executing the file / script */ + /* or right to traverse directory */ + /* (but by default all users have */ + /* directory bypass traverse */ + /* privilege and do not need this */ + /* permission on directories at all)*/ +#define FILE_DELETE_CHILD 0x00000040 /* Child entry can be deleted from */ + /* the directory (so the DELETE on */ + /* the child entry is not needed) */ +#define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */ + /* file or directory can be read */ +#define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */ + /* file or directory can be written */ +#define DELETE 0x00010000 /* The file or dir can be deleted */ +#define READ_CONTROL 0x00020000 /* The discretionary access control */ + /* list and ownership associated */ + /* with the file or dir can be read */ +#define WRITE_DAC 0x00040000 /* The discretionary access control */ + /* list associated with the file or */ + /* directory can be written */ +#define WRITE_OWNER 0x00080000 /* Ownership information associated */ + /* with the file/dir can be written */ +#define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ + /* synchronize with the completion */ + /* of an input/output request */ +#define SYSTEM_SECURITY 0x01000000 /* The system access control list */ + /* associated with the file or */ + /* directory can be read or written */ + /* (cannot be in DACL, can in SACL) */ +#define MAXIMUM_ALLOWED 0x02000000 /* Maximal subset of GENERIC_ALL */ + /* permissions which can be granted */ + /* (cannot be in DACL nor SACL) */ +#define GENERIC_ALL 0x10000000 /* Same as: GENERIC_EXECUTE | */ + /* GENERIC_WRITE | */ + /* GENERIC_READ | */ + /* FILE_DELETE_CHILD | */ + /* DELETE | */ + /* WRITE_DAC | */ + /* WRITE_OWNER */ + /* So GENERIC_ALL contains all bits */ + /* mentioned above except these two */ + /* SYSTEM_SECURITY MAXIMUM_ALLOWED */ +#define GENERIC_EXECUTE 0x20000000 /* Same as: FILE_EXECUTE | */ + /* FILE_READ_ATTRIBUTES | */ + /* READ_CONTROL | */ + /* SYNCHRONIZE */ +#define GENERIC_WRITE 0x40000000 /* Same as: FILE_WRITE_DATA | */ + /* FILE_APPEND_DATA | */ + /* FILE_WRITE_EA | */ + /* FILE_WRITE_ATTRIBUTES | */ + /* READ_CONTROL | */ + /* SYNCHRONIZE */ +#define GENERIC_READ 0x80000000 /* Same as: FILE_READ_DATA | */ + /* FILE_READ_EA | */ + /* FILE_READ_ATTRIBUTES | */ + /* READ_CONTROL | */ + /* SYNCHRONIZE */ + +/* Combinations of file access permission bits */ +#define FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES) +#define FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \ + | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) +#define FILE_EXEC_RIGHTS (FILE_EXECUTE) +#define SET_FILE_EXEC_RIGHTS (FILE_READ_EA | FILE_WRITE_EA | FILE_EXECUTE \ + | FILE_READ_ATTRIBUTES \ + | FILE_WRITE_ATTRIBUTES \ + | DELETE | READ_CONTROL | WRITE_DAC \ + | WRITE_OWNER | SYNCHRONIZE) +#define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \ + | READ_CONTROL | SYNCHRONIZE) + #endif /* _COMMON_SMB2PDU_H */ diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 77438830e2de..1f0ed9fb1e83 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -7866,9 +7866,9 @@ static int fsctl_query_iface_info_ioctl(struct ksmbd_conn *conn, nii_rsp->Capability = 0; if (netdev->real_num_tx_queues > 1) - nii_rsp->Capability |= cpu_to_le32(RSS_CAPABLE); + nii_rsp->Capability |= RSS_CAPABLE; if (ksmbd_rdma_capable_netdev(netdev)) - nii_rsp->Capability |= cpu_to_le32(RDMA_CAPABLE); + nii_rsp->Capability |= RDMA_CAPABLE; nii_rsp->Next = cpu_to_le32(152); nii_rsp->Reserved = 0; @@ -7894,7 +7894,7 @@ static int fsctl_query_iface_info_ioctl(struct ksmbd_conn *conn, if (!ipv4_set) { struct in_device *idev; - sockaddr_storage->Family = cpu_to_le16(INTERNETWORK); + sockaddr_storage->Family = INTERNETWORK; sockaddr_storage->addr4.Port = 0; idev = __in_dev_get_rtnl(netdev); @@ -7910,7 +7910,7 @@ static int fsctl_query_iface_info_ioctl(struct ksmbd_conn *conn, struct inet6_ifaddr *ifa; __u8 *ipv6_addr = sockaddr_storage->addr6.IPv6Address; - sockaddr_storage->Family = cpu_to_le16(INTERNETWORKV6); + sockaddr_storage->Family = INTERNETWORKV6; sockaddr_storage->addr6.Port = 0; sockaddr_storage->addr6.FlowInfo = 0; diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h index 46e14bd4f2da..d10374e44093 100644 --- a/fs/smb/server/smb2pdu.h +++ b/fs/smb/server/smb2pdu.h @@ -95,10 +95,6 @@ struct create_durable_rsp { } Data; } __packed; -/* See MS-SMB2 2.2.13.2.11 */ -/* Flags */ -#define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002 - /* equivalent of the contents of SMB3.1.1 POSIX open context response */ struct create_posix_rsp { struct create_context_hdr ccontext; @@ -112,9 +108,6 @@ struct create_posix_rsp { #define SMB2_0_IOCTL_IS_FSCTL 0x00000001 -#define INTERNETWORK 0x0002 -#define INTERNETWORKV6 0x0017 - struct sockaddr_storage_rsp { __le16 Family; union { @@ -123,18 +116,6 @@ struct sockaddr_storage_rsp { }; } __packed; -#define RSS_CAPABLE 0x00000001 -#define RDMA_CAPABLE 0x00000002 - -struct network_interface_info_ioctl_rsp { - __le32 Next; /* next interface. zero if this is last one */ - __le32 IfIndex; - __le32 Capability; /* RSS or RDMA Capable */ - __le32 Reserved; - __le64 LinkSpeed; - char SockAddr_Storage[128]; -} __packed; - struct file_object_buf_type1_ioctl_rsp { __u8 ObjectId[16]; __u8 BirthVolumeId[16]; diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h index 2669e68dba3a..6be079d78022 100644 --- a/fs/smb/server/smb_common.h +++ b/fs/smb/server/smb_common.h @@ -75,42 +75,7 @@ #define FILE_CASE_PRESERVED_NAMES 0x00000002 #define FILE_CASE_SENSITIVE_SEARCH 0x00000001 -#define FILE_READ_DATA 0x00000001 /* Data can be read from the file */ -#define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */ -#define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */ -#define FILE_READ_EA 0x00000008 /* Extended attributes associated */ -/* with the file can be read */ -#define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */ -/* with the file can be written */ -#define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */ -/* the file using system paging I/O */ -#define FILE_DELETE_CHILD 0x00000040 -#define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */ -/* file can be read */ -#define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */ -/* file can be written */ -#define DELETE 0x00010000 /* The file can be deleted */ -#define READ_CONTROL 0x00020000 /* The access control list and */ -/* ownership associated with the */ -/* file can be read */ -#define WRITE_DAC 0x00040000 /* The access control list and */ -/* ownership associated with the */ -/* file can be written. */ -#define WRITE_OWNER 0x00080000 /* Ownership information associated */ -/* with the file can be written */ -#define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ -/* synchronize with the completion */ -/* of an input/output request */ -#define GENERIC_ALL 0x10000000 -#define GENERIC_EXECUTE 0x20000000 -#define GENERIC_WRITE 0x40000000 -#define GENERIC_READ 0x80000000 -/* In summary - Relevant file */ -/* access flags from CIFS are */ -/* file_read_data, file_write_data */ -/* file_execute, file_read_attributes*/ -/* write_dac, and delete. */ - +/* Combinations of file access permission bits */ #define SET_FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA \ | FILE_READ_ATTRIBUTES \ | DELETE | READ_CONTROL | WRITE_DAC \ @@ -121,14 +86,6 @@ | FILE_WRITE_ATTRIBUTES \ | DELETE | READ_CONTROL | WRITE_DAC \ | WRITE_OWNER | SYNCHRONIZE) -#define SET_FILE_EXEC_RIGHTS (FILE_READ_EA | FILE_WRITE_EA | FILE_EXECUTE \ - | FILE_READ_ATTRIBUTES \ - | FILE_WRITE_ATTRIBUTES \ - | DELETE | READ_CONTROL | WRITE_DAC \ - | WRITE_OWNER | SYNCHRONIZE) - -#define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \ - | READ_CONTROL | SYNCHRONIZE) /* generic flags for file open */ #define GENERIC_READ_FLAGS (READ_CONTROL | FILE_READ_DATA | \ @@ -159,36 +116,6 @@ #define SMBFLG2_ERR_STATUS cpu_to_le16(0x4000) #define SMBFLG2_UNICODE cpu_to_le16(0x8000) -struct smb_hdr { - __be32 smb_buf_length; - __u8 Protocol[4]; - __u8 Command; - union { - struct { - __u8 ErrorClass; - __u8 Reserved; - __le16 Error; - } __packed DosError; - __le32 CifsError; - } __packed Status; - __u8 Flags; - __le16 Flags2; /* note: le */ - __le16 PidHigh; - union { - struct { - __le32 SequenceNumber; /* le */ - __u32 Reserved; /* zero */ - } __packed Sequence; - __u8 SecuritySignature[8]; /* le */ - } __packed Signature; - __u8 pad[2]; - __le16 Tid; - __le16 Pid; - __le16 Uid; - __le16 Mid; - __u8 WordCount; -} __packed; - struct smb_negotiate_req { struct smb_hdr hdr; /* wct = 0 */ __le16 ByteCount; From d8ac9879182a1e1f3b97d166f5ba5e2f1b3e8535 Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Sun, 2 Nov 2025 15:30:53 +0800 Subject: [PATCH 24/44] smb: move SMB_NEGOTIATE_REQ to common/smb2pdu.h Modify the following places: - negotiate_req -> smb_negotiate_req - NEGOTIATE_REQ -> SMB_NEGOTIATE_REQ - negotiate_rsp -> smb_negotiate_rsp - NEGOTIATE_RSP -> SMB_NEGOTIATE_RSP Then move SMB_NEGOTIATE_REQ to common header file. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/cifspdu.h | 12 ++++-------- fs/smb/client/cifssmb.c | 6 +++--- fs/smb/common/smb2pdu.h | 7 +++++++ fs/smb/server/smb_common.h | 7 +------ 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h index 99cdba9f68dc..1e16ef6f0ff5 100644 --- a/fs/smb/client/cifspdu.h +++ b/fs/smb/client/cifspdu.h @@ -388,19 +388,15 @@ put_bcc(__u16 count, struct smb_hdr *hdr) * */ -typedef struct negotiate_req { - struct smb_hdr hdr; /* wct = 0 */ - __le16 ByteCount; - unsigned char DialectsArray[]; -} __attribute__((packed)) NEGOTIATE_REQ; - #define MIN_TZ_ADJ (15 * 60) /* minimum grid for timezones in seconds */ #define READ_RAW_ENABLE 1 #define WRITE_RAW_ENABLE 2 #define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE) #define SMB1_CLIENT_GUID_SIZE (16) -typedef struct negotiate_rsp { + +/* See MS-CIFS 2.2.4.52.2 */ +typedef struct smb_negotiate_rsp { struct smb_hdr hdr; /* wct = 17 */ __le16 DialectIndex; /* 0xFFFF = no dialect acceptable */ __u8 SecurityMode; @@ -426,7 +422,7 @@ typedef struct negotiate_rsp { unsigned char SecurityBlob[]; } __attribute__((packed)) extended_response; } __attribute__((packed)) u; -} __attribute__((packed)) NEGOTIATE_RSP; +} __packed SMB_NEGOTIATE_RSP; /* SecurityMode bits */ #define SECMODE_USER 0x01 /* off indicates share level security */ diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 132d015cbdf1..fba439447dec 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -361,7 +361,7 @@ static int validate_t2(struct smb_t2_rsp *pSMB) } static int -decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr) +decode_ext_sec_blob(struct cifs_ses *ses, SMB_NEGOTIATE_RSP *pSMBr) { int rc = 0; u16 count; @@ -419,8 +419,8 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server) { - NEGOTIATE_REQ *pSMB; - NEGOTIATE_RSP *pSMBr; + SMB_NEGOTIATE_REQ *pSMB; + SMB_NEGOTIATE_RSP *pSMBr; int rc = 0; int bytes_returned; int i; diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h index be1e652bb474..824d27297bec 100644 --- a/fs/smb/common/smb2pdu.h +++ b/fs/smb/common/smb2pdu.h @@ -2151,4 +2151,11 @@ struct smb_hdr { #define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \ | READ_CONTROL | SYNCHRONIZE) +/* See MS-CIFS 2.2.4.52.1 */ +typedef struct smb_negotiate_req { + struct smb_hdr hdr; /* wct = 0 */ + __le16 ByteCount; + unsigned char DialectsArray[]; +} __packed SMB_NEGOTIATE_REQ; + #endif /* _COMMON_SMB2PDU_H */ diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h index 6be079d78022..c5df18d679b5 100644 --- a/fs/smb/server/smb_common.h +++ b/fs/smb/server/smb_common.h @@ -116,12 +116,7 @@ #define SMBFLG2_ERR_STATUS cpu_to_le16(0x4000) #define SMBFLG2_UNICODE cpu_to_le16(0x8000) -struct smb_negotiate_req { - struct smb_hdr hdr; /* wct = 0 */ - __le16 ByteCount; - unsigned char DialectsArray[]; -} __packed; - +/* See MS-CIFS 2.2.4.52.2 */ struct smb_negotiate_rsp { struct smb_hdr hdr; /* wct = 17 */ __le16 DialectIndex; /* 0xFFFF = no dialect acceptable */ From 84d8d4cf8873b4a9da0d76e9ba9d94ec88311cfd Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Sun, 2 Nov 2025 15:30:54 +0800 Subject: [PATCH 25/44] smb: move list of FileSystemAttributes to common/fscc.h These definitions are exactly the same on both client and server, so move them to new common header file. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/cifsglob.h | 1 + fs/smb/client/cifspdu.h | 27 ------------------------ fs/smb/common/fscc.h | 42 ++++++++++++++++++++++++++++++++++++++ fs/smb/server/smb_common.h | 28 +------------------------ 4 files changed, 44 insertions(+), 54 deletions(-) create mode 100644 fs/smb/common/fscc.h diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 4d0aca8097c1..0c76e0a31386 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -26,6 +26,7 @@ #include #include "../common/smbglob.h" #include "../common/smb2pdu.h" +#include "../common/fscc.h" #include "smb2pdu.h" #include diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h index 1e16ef6f0ff5..7816bd3da8d7 100644 --- a/fs/smb/client/cifspdu.h +++ b/fs/smb/client/cifspdu.h @@ -2100,33 +2100,6 @@ typedef struct { /* minimum includes first three fields, and empty FS Name */ #define MIN_FS_ATTR_INFO_SIZE 12 - -/* List of FileSystemAttributes - see 2.5.1 of MS-FSCC */ -#define FILE_SUPPORTS_SPARSE_VDL 0x10000000 /* faster nonsparse extend */ -#define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000 /* allow ioctl dup extents */ -#define FILE_SUPPORT_INTEGRITY_STREAMS 0x04000000 -#define FILE_SUPPORTS_USN_JOURNAL 0x02000000 -#define FILE_SUPPORTS_OPEN_BY_FILE_ID 0x01000000 -#define FILE_SUPPORTS_EXTENDED_ATTRIBUTES 0x00800000 -#define FILE_SUPPORTS_HARD_LINKS 0x00400000 -#define FILE_SUPPORTS_TRANSACTIONS 0x00200000 -#define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000 -#define FILE_READ_ONLY_VOLUME 0x00080000 -#define FILE_NAMED_STREAMS 0x00040000 -#define FILE_SUPPORTS_ENCRYPTION 0x00020000 -#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 -#define FILE_VOLUME_IS_COMPRESSED 0x00008000 -#define FILE_SUPPORTS_POSIX_UNLINK_RENAME 0x00000400 -#define FILE_RETURNS_CLEANUP_RESULT_INFO 0x00000200 -#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 -#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 -#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 -#define FILE_VOLUME_QUOTAS 0x00000020 -#define FILE_FILE_COMPRESSION 0x00000010 -#define FILE_PERSISTENT_ACLS 0x00000008 -#define FILE_UNICODE_ON_DISK 0x00000004 -#define FILE_CASE_PRESERVED_NAMES 0x00000002 -#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 typedef struct { __le32 Attributes; __le32 MaxPathNameComponentLength; diff --git a/fs/smb/common/fscc.h b/fs/smb/common/fscc.h new file mode 100644 index 000000000000..c8bfb87232ac --- /dev/null +++ b/fs/smb/common/fscc.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ +/* + * + * Copyright (c) International Business Machines Corp., 2009, 2013 + * Etersoft, 2012 + * 2018 Samsung Electronics Co., Ltd. + * Author(s): Steve French (sfrench@us.ibm.com) + * Pavel Shilovsky (pshilovsky@samba.org) 2012 + * Namjae Jeon (linkinjeon@kernel.org) + * + */ +#ifndef _COMMON_SMB_FSCC_H +#define _COMMON_SMB_FSCC_H + +/* List of FileSystemAttributes - see MS-FSCC 2.5.1 */ +#define FILE_SUPPORTS_SPARSE_VDL 0x10000000 /* faster nonsparse extend */ +#define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000 /* allow ioctl dup extents */ +#define FILE_SUPPORT_INTEGRITY_STREAMS 0x04000000 +#define FILE_SUPPORTS_USN_JOURNAL 0x02000000 +#define FILE_SUPPORTS_OPEN_BY_FILE_ID 0x01000000 +#define FILE_SUPPORTS_EXTENDED_ATTRIBUTES 0x00800000 +#define FILE_SUPPORTS_HARD_LINKS 0x00400000 +#define FILE_SUPPORTS_TRANSACTIONS 0x00200000 +#define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000 +#define FILE_READ_ONLY_VOLUME 0x00080000 +#define FILE_NAMED_STREAMS 0x00040000 +#define FILE_SUPPORTS_ENCRYPTION 0x00020000 +#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 +#define FILE_VOLUME_IS_COMPRESSED 0x00008000 +#define FILE_SUPPORTS_POSIX_UNLINK_RENAME 0x00000400 +#define FILE_RETURNS_CLEANUP_RESULT_INFO 0x00000200 +#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 +#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 +#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 +#define FILE_VOLUME_QUOTAS 0x00000020 +#define FILE_FILE_COMPRESSION 0x00000010 +#define FILE_PERSISTENT_ACLS 0x00000008 +#define FILE_UNICODE_ON_DISK 0x00000004 +#define FILE_CASE_PRESERVED_NAMES 0x00000002 +#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 + +#endif /* _COMMON_SMB_FSCC_H */ diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h index c5df18d679b5..653e369efbe8 100644 --- a/fs/smb/server/smb_common.h +++ b/fs/smb/server/smb_common.h @@ -12,6 +12,7 @@ #include "nterr.h" #include "../common/smbglob.h" #include "../common/smb2pdu.h" +#include "../common/fscc.h" #include "smb2pdu.h" /* ksmbd's Specific ERRNO */ @@ -48,33 +49,6 @@ #define ATTR_NO_BUFFERING 0x20000000 #define ATTR_WRITE_THROUGH 0x80000000 -/* List of FileSystemAttributes - see 2.5.1 of MS-FSCC */ -#define FILE_SUPPORTS_SPARSE_VDL 0x10000000 /* faster nonsparse extend */ -#define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000 /* allow ioctl dup extents */ -#define FILE_SUPPORT_INTEGRITY_STREAMS 0x04000000 -#define FILE_SUPPORTS_USN_JOURNAL 0x02000000 -#define FILE_SUPPORTS_OPEN_BY_FILE_ID 0x01000000 -#define FILE_SUPPORTS_EXTENDED_ATTRIBUTES 0x00800000 -#define FILE_SUPPORTS_HARD_LINKS 0x00400000 -#define FILE_SUPPORTS_TRANSACTIONS 0x00200000 -#define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000 -#define FILE_READ_ONLY_VOLUME 0x00080000 -#define FILE_NAMED_STREAMS 0x00040000 -#define FILE_SUPPORTS_ENCRYPTION 0x00020000 -#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 -#define FILE_VOLUME_IS_COMPRESSED 0x00008000 -#define FILE_SUPPORTS_POSIX_UNLINK_RENAME 0x00000400 -#define FILE_RETURNS_CLEANUP_RESULT_INFO 0x00000200 -#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 -#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 -#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 -#define FILE_VOLUME_QUOTAS 0x00000020 -#define FILE_FILE_COMPRESSION 0x00000010 -#define FILE_PERSISTENT_ACLS 0x00000008 -#define FILE_UNICODE_ON_DISK 0x00000004 -#define FILE_CASE_PRESERVED_NAMES 0x00000002 -#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 - /* Combinations of file access permission bits */ #define SET_FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA \ | FILE_READ_ATTRIBUTES \ From d7edd3892d97e6746e30f36f4f13f887ec4d80ed Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Sun, 2 Nov 2025 15:30:55 +0800 Subject: [PATCH 26/44] smb: move some duplicate struct definitions to common/fscc.h Modify the following places: - smb2_file_ntwrk_info -> smb2_file_network_open_info - struct filesystem_device_info -> FILE_SYSTEM_DEVICE_INFO - struct file_directory_info -> FILE_DIRECTORY_INFO - struct file_full_directory_info -> FILE_FULL_DIRECTORY_INFO - struct file_both_directory_info -> FILE_BOTH_DIRECTORY_INFO - struct file_id_full_dir_info -> FILE_ID_FULL_DIR_INFO - struct filesystem_posix_info -> FILE_SYSTEM_POSIX_INFO The fields of these structures are exactly the same on both client and server, so move duplicate definitions to common header file. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/cifspdu.h | 91 ----------------------------- fs/smb/client/inode.c | 4 +- fs/smb/client/readdir.c | 2 +- fs/smb/client/smb2pdu.c | 2 +- fs/smb/client/smb2pdu.h | 13 ----- fs/smb/common/fscc.h | 115 +++++++++++++++++++++++++++++++++++++ fs/smb/server/smb2pdu.c | 72 +++++++++++------------ fs/smb/server/smb2pdu.h | 11 ---- fs/smb/server/smb_common.h | 92 ----------------------------- fs/smb/server/vfs.c | 2 +- 10 files changed, 156 insertions(+), 248 deletions(-) diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h index 7816bd3da8d7..39f431051860 100644 --- a/fs/smb/client/cifspdu.h +++ b/fs/smb/client/cifspdu.h @@ -2036,28 +2036,6 @@ typedef struct { #define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */ -typedef struct { - /* For undefined recommended transfer size return -1 in that field */ - __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ - __le32 BlockSize; - /* The next three fields are in terms of the block size. - (above). If block size is unknown, 4096 would be a - reasonable block size for a server to report. - Note that returning the blocks/blocksavail removes need - to make a second call (to QFSInfo level 0x103 to get this info. - UserBlockAvail is typically less than or equal to BlocksAvail, - if no distinction is made return the same value in each */ - __le64 TotalBlocks; - __le64 BlocksAvail; /* bfree */ - __le64 UserBlocksAvail; /* bavail */ - /* For undefined Node fields or FSID return -1 */ - __le64 TotalFileNodes; - __le64 FreeFileNodes; - __le64 FileSysIdentifier; /* fsid */ - /* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */ - /* NB flags can come from FILE_SYSTEM_DEVICE_INFO call */ -} __attribute__((packed)) FILE_SYSTEM_POSIX_INFO; - /* DeviceType Flags */ #define FILE_DEVICE_CD_ROM 0x00000002 #define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 @@ -2092,11 +2070,6 @@ typedef struct { #define FILE_PORTABLE_DEVICE 0x00004000 #define FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL 0x00020000 -typedef struct { - __le32 DeviceType; - __le32 DeviceCharacteristics; -} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */ - /* minimum includes first three fields, and empty FS Name */ #define MIN_FS_ATTR_INFO_SIZE 12 @@ -2332,70 +2305,6 @@ typedef struct { }; } __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */ -typedef struct { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - char FileName[]; -} __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF resp data */ - -typedef struct { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - __le32 EaSize; /* length of the xattrs */ - char FileName[]; -} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 rsp data */ - -typedef struct { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - __le32 EaSize; /* EA size */ - __le32 Reserved; - __le64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ - char FileName[]; -} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */ - -typedef struct { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - __le32 EaSize; /* length of the xattrs */ - __u8 ShortNameLength; - __u8 Reserved; - __u8 ShortName[24]; - char FileName[]; -} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FFrsp data */ - typedef struct { __u32 ResumeKey; __le16 CreationDate; /* SMB Date */ diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c index cac355364e43..c2ac39d89df2 100644 --- a/fs/smb/client/inode.c +++ b/fs/smb/client/inode.c @@ -1328,7 +1328,7 @@ static int cifs_get_fattr(struct cifs_open_info_data *data, /* for easier reading */ FILE_ALL_INFO *fi; FILE_DIRECTORY_INFO *fdi; - SEARCH_ID_FULL_DIR_INFO *si; + FILE_ID_FULL_DIR_INFO *si; rc = cifs_backup_query_path_info(xid, tcon, sb, full_path, @@ -1339,7 +1339,7 @@ static int cifs_get_fattr(struct cifs_open_info_data *data, move_cifs_info_to_smb2(&data->fi, fi); fdi = (FILE_DIRECTORY_INFO *)fi; - si = (SEARCH_ID_FULL_DIR_INFO *)fi; + si = (FILE_ID_FULL_DIR_INFO *)fi; cifs_dir_info_to_fattr(fattr, fdi, cifs_sb); fattr->cf_uniqueid = le64_to_cpu(si->UniqueId); diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c index f0ce26622a14..2fd95c1e91ab 100644 --- a/fs/smb/client/readdir.c +++ b/fs/smb/client/readdir.c @@ -548,7 +548,7 @@ static void cifs_fill_dirent_full(struct cifs_dirent *de, } static void cifs_fill_dirent_search(struct cifs_dirent *de, - const SEARCH_ID_FULL_DIR_INFO *info) + const FILE_ID_FULL_DIR_INFO *info) { de->name = &info->FileName[0]; de->namelen = le32_to_cpu(info->FileNameLength); diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index fe2147c45839..62ced22fc5a6 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -5454,7 +5454,7 @@ smb2_parse_query_directory(struct cifs_tcon *tcon, info_buf_size = sizeof(FILE_DIRECTORY_INFO); break; case SMB_FIND_FILE_ID_FULL_DIR_INFO: - info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO); + info_buf_size = sizeof(FILE_ID_FULL_DIR_INFO); break; case SMB_FIND_FILE_POSIX_INFO: /* note that posix payload are variable size */ diff --git a/fs/smb/client/smb2pdu.h b/fs/smb/client/smb2pdu.h index 98ed7a22cd57..78bb99f29d38 100644 --- a/fs/smb/client/smb2pdu.h +++ b/fs/smb/client/smb2pdu.h @@ -224,19 +224,6 @@ struct smb2_file_reparse_point_info { __le32 Tag; } __packed; -struct smb2_file_network_open_info { - struct_group_attr(network_open_info, __packed, - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 AllocationSize; - __le64 EndOfFile; - __le32 Attributes; - ); - __le32 Reserved; -} __packed; /* level 34 Query also similar returned in close rsp and open rsp */ - /* See MS-FSCC 2.4.21 */ struct smb2_file_id_information { __le64 VolumeSerialNumber; diff --git a/fs/smb/common/fscc.h b/fs/smb/common/fscc.h index c8bfb87232ac..6fa7c65d304b 100644 --- a/fs/smb/common/fscc.h +++ b/fs/smb/common/fscc.h @@ -12,6 +12,88 @@ #ifndef _COMMON_SMB_FSCC_H #define _COMMON_SMB_FSCC_H +/* See MS-FSCC 2.4.8 */ +typedef struct { + __le32 NextEntryOffset; + __u32 FileIndex; + __le64 CreationTime; + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le64 EndOfFile; + __le64 AllocationSize; + __le32 ExtFileAttributes; + __le32 FileNameLength; + __le32 EaSize; /* length of the xattrs */ + __u8 ShortNameLength; + __u8 Reserved; + __u8 ShortName[24]; + char FileName[]; +} __packed FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FFrsp data */ + +/* See MS-FSCC 2.4.10 */ +typedef struct { + __le32 NextEntryOffset; + __u32 FileIndex; + __le64 CreationTime; + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le64 EndOfFile; + __le64 AllocationSize; + __le32 ExtFileAttributes; + __le32 FileNameLength; + char FileName[]; +} __packed FILE_DIRECTORY_INFO; /* level 0x101 FF resp data */ + +/* See MS-FSCC 2.4.14 */ +typedef struct { + __le32 NextEntryOffset; + __u32 FileIndex; + __le64 CreationTime; + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le64 EndOfFile; + __le64 AllocationSize; + __le32 ExtFileAttributes; + __le32 FileNameLength; + __le32 EaSize; /* length of the xattrs */ + char FileName[]; +} __packed FILE_FULL_DIRECTORY_INFO; /* level 0x102 rsp data */ + +/* See MS-FSCC 2.4.24 */ +typedef struct { + __le32 NextEntryOffset; + __u32 FileIndex; + __le64 CreationTime; + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le64 EndOfFile; + __le64 AllocationSize; + __le32 ExtFileAttributes; + __le32 FileNameLength; + __le32 EaSize; /* EA size */ + __le32 Reserved; + __le64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ + char FileName[]; +} __packed FILE_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */ + +/* See MS-FSCC 2.4.34 */ +struct smb2_file_network_open_info { + struct_group_attr(network_open_info, __packed, + __le64 CreationTime; + __le64 LastAccessTime; + __le64 LastWriteTime; + __le64 ChangeTime; + __le64 AllocationSize; + __le64 EndOfFile; + __le32 Attributes; + ); + __le32 Reserved; +} __packed; /* level 34 Query also similar returned in close rsp and open rsp */ + /* List of FileSystemAttributes - see MS-FSCC 2.5.1 */ #define FILE_SUPPORTS_SPARSE_VDL 0x10000000 /* faster nonsparse extend */ #define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000 /* allow ioctl dup extents */ @@ -39,4 +121,37 @@ #define FILE_CASE_PRESERVED_NAMES 0x00000002 #define FILE_CASE_SENSITIVE_SEARCH 0x00000001 +/* See MS-FSCC 2.5.10 */ +typedef struct { + __le32 DeviceType; + __le32 DeviceCharacteristics; +} __packed FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */ + +/* + * See POSIX Extensions to MS-FSCC 2.3.2.1 + * Link: https://gitlab.com/samba-team/smb3-posix-spec/-/blob/master/fscc_posix_extensions.md + */ +typedef struct { + /* For undefined recommended transfer size return -1 in that field */ + __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ + __le32 BlockSize; + /* The next three fields are in terms of the block size. + * (above). If block size is unknown, 4096 would be a + * reasonable block size for a server to report. + * Note that returning the blocks/blocksavail removes need + * to make a second call (to QFSInfo level 0x103 to get this info. + * UserBlockAvail is typically less than or equal to BlocksAvail, + * if no distinction is made return the same value in each + */ + __le64 TotalBlocks; + __le64 BlocksAvail; /* bfree */ + __le64 UserBlocksAvail; /* bavail */ + /* For undefined Node fields or FSID return -1 */ + __le64 TotalFileNodes; + __le64 FreeFileNodes; + __le64 FileSysIdentifier; /* fsid */ + /* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */ + /* NB flags can come from FILE_SYSTEM_DEVICE_INFO call */ +} __packed FILE_SYSTEM_POSIX_INFO; + #endif /* _COMMON_SMB_FSCC_H */ diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 1f0ed9fb1e83..5696ac8bf5e8 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -3786,15 +3786,15 @@ static int readdir_info_level_struct_sz(int info_level) { switch (info_level) { case FILE_FULL_DIRECTORY_INFORMATION: - return sizeof(struct file_full_directory_info); + return sizeof(FILE_FULL_DIRECTORY_INFO); case FILE_BOTH_DIRECTORY_INFORMATION: - return sizeof(struct file_both_directory_info); + return sizeof(FILE_BOTH_DIRECTORY_INFO); case FILE_DIRECTORY_INFORMATION: - return sizeof(struct file_directory_info); + return sizeof(FILE_DIRECTORY_INFO); case FILE_NAMES_INFORMATION: return sizeof(struct file_names_info); case FILEID_FULL_DIRECTORY_INFORMATION: - return sizeof(struct file_id_full_dir_info); + return sizeof(FILE_ID_FULL_DIR_INFO); case FILEID_BOTH_DIRECTORY_INFORMATION: return sizeof(struct file_id_both_directory_info); case SMB_FIND_FILE_POSIX_INFO: @@ -3809,9 +3809,9 @@ static int dentry_name(struct ksmbd_dir_info *d_info, int info_level) switch (info_level) { case FILE_FULL_DIRECTORY_INFORMATION: { - struct file_full_directory_info *ffdinfo; + FILE_FULL_DIRECTORY_INFO *ffdinfo; - ffdinfo = (struct file_full_directory_info *)d_info->rptr; + ffdinfo = (FILE_FULL_DIRECTORY_INFO *)d_info->rptr; d_info->rptr += le32_to_cpu(ffdinfo->NextEntryOffset); d_info->name = ffdinfo->FileName; d_info->name_len = le32_to_cpu(ffdinfo->FileNameLength); @@ -3819,9 +3819,9 @@ static int dentry_name(struct ksmbd_dir_info *d_info, int info_level) } case FILE_BOTH_DIRECTORY_INFORMATION: { - struct file_both_directory_info *fbdinfo; + FILE_BOTH_DIRECTORY_INFO *fbdinfo; - fbdinfo = (struct file_both_directory_info *)d_info->rptr; + fbdinfo = (FILE_BOTH_DIRECTORY_INFO *)d_info->rptr; d_info->rptr += le32_to_cpu(fbdinfo->NextEntryOffset); d_info->name = fbdinfo->FileName; d_info->name_len = le32_to_cpu(fbdinfo->FileNameLength); @@ -3829,9 +3829,9 @@ static int dentry_name(struct ksmbd_dir_info *d_info, int info_level) } case FILE_DIRECTORY_INFORMATION: { - struct file_directory_info *fdinfo; + FILE_DIRECTORY_INFO *fdinfo; - fdinfo = (struct file_directory_info *)d_info->rptr; + fdinfo = (FILE_DIRECTORY_INFO *)d_info->rptr; d_info->rptr += le32_to_cpu(fdinfo->NextEntryOffset); d_info->name = fdinfo->FileName; d_info->name_len = le32_to_cpu(fdinfo->FileNameLength); @@ -3849,9 +3849,9 @@ static int dentry_name(struct ksmbd_dir_info *d_info, int info_level) } case FILEID_FULL_DIRECTORY_INFORMATION: { - struct file_id_full_dir_info *dinfo; + FILE_ID_FULL_DIR_INFO *dinfo; - dinfo = (struct file_id_full_dir_info *)d_info->rptr; + dinfo = (FILE_ID_FULL_DIR_INFO *)d_info->rptr; d_info->rptr += le32_to_cpu(dinfo->NextEntryOffset); d_info->name = dinfo->FileName; d_info->name_len = le32_to_cpu(dinfo->FileNameLength); @@ -3934,9 +3934,9 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level, switch (info_level) { case FILE_FULL_DIRECTORY_INFORMATION: { - struct file_full_directory_info *ffdinfo; + FILE_FULL_DIRECTORY_INFO *ffdinfo; - ffdinfo = (struct file_full_directory_info *)kstat; + ffdinfo = (FILE_FULL_DIRECTORY_INFO *)kstat; ffdinfo->FileNameLength = cpu_to_le32(conv_len); ffdinfo->EaSize = smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode); @@ -3950,9 +3950,9 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level, } case FILE_BOTH_DIRECTORY_INFORMATION: { - struct file_both_directory_info *fbdinfo; + FILE_BOTH_DIRECTORY_INFO *fbdinfo; - fbdinfo = (struct file_both_directory_info *)kstat; + fbdinfo = (FILE_BOTH_DIRECTORY_INFO *)kstat; fbdinfo->FileNameLength = cpu_to_le32(conv_len); fbdinfo->EaSize = smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode); @@ -3968,9 +3968,9 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level, } case FILE_DIRECTORY_INFORMATION: { - struct file_directory_info *fdinfo; + FILE_DIRECTORY_INFO *fdinfo; - fdinfo = (struct file_directory_info *)kstat; + fdinfo = (FILE_DIRECTORY_INFO *)kstat; fdinfo->FileNameLength = cpu_to_le32(conv_len); if (d_info->hide_dot_file && d_info->name[0] == '.') fdinfo->ExtFileAttributes |= FILE_ATTRIBUTE_HIDDEN_LE; @@ -3990,9 +3990,9 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level, } case FILEID_FULL_DIRECTORY_INFORMATION: { - struct file_id_full_dir_info *dinfo; + FILE_ID_FULL_DIR_INFO *dinfo; - dinfo = (struct file_id_full_dir_info *)kstat; + dinfo = (FILE_ID_FULL_DIR_INFO *)kstat; dinfo->FileNameLength = cpu_to_le32(conv_len); dinfo->EaSize = smb2_get_reparse_tag_special_file(ksmbd_kstat->kstat->mode); @@ -4196,9 +4196,9 @@ static int reserve_populate_dentry(struct ksmbd_dir_info *d_info, switch (info_level) { case FILE_FULL_DIRECTORY_INFORMATION: { - struct file_full_directory_info *ffdinfo; + FILE_FULL_DIRECTORY_INFO *ffdinfo; - ffdinfo = (struct file_full_directory_info *)d_info->wptr; + ffdinfo = (FILE_FULL_DIRECTORY_INFO *)d_info->wptr; memcpy(ffdinfo->FileName, d_info->name, d_info->name_len); ffdinfo->FileName[d_info->name_len] = 0x00; ffdinfo->FileNameLength = cpu_to_le32(d_info->name_len); @@ -4207,9 +4207,9 @@ static int reserve_populate_dentry(struct ksmbd_dir_info *d_info, } case FILE_BOTH_DIRECTORY_INFORMATION: { - struct file_both_directory_info *fbdinfo; + FILE_BOTH_DIRECTORY_INFO *fbdinfo; - fbdinfo = (struct file_both_directory_info *)d_info->wptr; + fbdinfo = (FILE_BOTH_DIRECTORY_INFO *)d_info->wptr; memcpy(fbdinfo->FileName, d_info->name, d_info->name_len); fbdinfo->FileName[d_info->name_len] = 0x00; fbdinfo->FileNameLength = cpu_to_le32(d_info->name_len); @@ -4218,9 +4218,9 @@ static int reserve_populate_dentry(struct ksmbd_dir_info *d_info, } case FILE_DIRECTORY_INFORMATION: { - struct file_directory_info *fdinfo; + FILE_DIRECTORY_INFO *fdinfo; - fdinfo = (struct file_directory_info *)d_info->wptr; + fdinfo = (FILE_DIRECTORY_INFO *)d_info->wptr; memcpy(fdinfo->FileName, d_info->name, d_info->name_len); fdinfo->FileName[d_info->name_len] = 0x00; fdinfo->FileNameLength = cpu_to_le32(d_info->name_len); @@ -4240,9 +4240,9 @@ static int reserve_populate_dentry(struct ksmbd_dir_info *d_info, } case FILEID_FULL_DIRECTORY_INFORMATION: { - struct file_id_full_dir_info *dinfo; + FILE_ID_FULL_DIR_INFO *dinfo; - dinfo = (struct file_id_full_dir_info *)d_info->wptr; + dinfo = (FILE_ID_FULL_DIR_INFO *)d_info->wptr; memcpy(dinfo->FileName, d_info->name, d_info->name_len); dinfo->FileName[d_info->name_len] = 0x00; dinfo->FileNameLength = cpu_to_le32(d_info->name_len); @@ -4504,7 +4504,7 @@ int smb2_query_dir(struct ksmbd_work *work) goto err_out; } else { no_buf_len: - ((struct file_directory_info *) + ((FILE_DIRECTORY_INFO *) ((char *)rsp->Buffer + d_info.last_entry_offset)) ->NextEntryOffset = 0; if (d_info.data_count >= d_info.last_entry_off_align) @@ -5123,7 +5123,7 @@ static int get_file_internal_info(struct smb2_query_info_rsp *rsp, static int get_file_network_open_info(struct smb2_query_info_rsp *rsp, struct ksmbd_file *fp, void *rsp_org) { - struct smb2_file_ntwrk_info *file_info; + struct smb2_file_network_open_info *file_info; struct kstat stat; u64 time; int ret; @@ -5139,7 +5139,7 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp, if (ret) return ret; - file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer; + file_info = (struct smb2_file_network_open_info *)rsp->Buffer; file_info->CreationTime = cpu_to_le64(fp->create_time); time = ksmbd_UnixTimeToNT(stat.atime); @@ -5158,7 +5158,7 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp, } file_info->Reserved = cpu_to_le32(0); rsp->OutputBufferLength = - cpu_to_le32(sizeof(struct smb2_file_ntwrk_info)); + cpu_to_le32(sizeof(struct smb2_file_network_open_info)); return 0; } @@ -5466,9 +5466,9 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, switch (fsinfoclass) { case FS_DEVICE_INFORMATION: { - struct filesystem_device_info *info; + FILE_SYSTEM_DEVICE_INFO *info; - info = (struct filesystem_device_info *)rsp->Buffer; + info = (FILE_SYSTEM_DEVICE_INFO *)rsp->Buffer; info->DeviceType = cpu_to_le32(FILE_DEVICE_DISK); info->DeviceCharacteristics = @@ -5623,14 +5623,14 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, } case FS_POSIX_INFORMATION: { - struct filesystem_posix_info *info; + FILE_SYSTEM_POSIX_INFO *info; if (!work->tcon->posix_extensions) { pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n"); path_put(&path); return -EOPNOTSUPP; } else { - info = (struct filesystem_posix_info *)(rsp->Buffer); + info = (FILE_SYSTEM_POSIX_INFO *)(rsp->Buffer); info->OptimalTransferSize = cpu_to_le32(stfs.f_bsize); info->BlockSize = cpu_to_le32(stfs.f_bsize); info->TotalBlocks = cpu_to_le64(stfs.f_blocks); diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h index d10374e44093..b94de41049f4 100644 --- a/fs/smb/server/smb2pdu.h +++ b/fs/smb/server/smb2pdu.h @@ -217,17 +217,6 @@ struct smb2_file_stream_info { char StreamName[]; } __packed; -struct smb2_file_ntwrk_info { - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 AllocationSize; - __le64 EndOfFile; - __le32 Attributes; - __le32 Reserved; -} __packed; - struct smb2_file_standard_info { __le64 AllocationSize; __le64 EndOfFile; diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h index 653e369efbe8..c171c1e190a5 100644 --- a/fs/smb/server/smb_common.h +++ b/fs/smb/server/smb_common.h @@ -104,11 +104,6 @@ struct filesystem_attribute_info { __le16 FileSystemName[]; /* do not have to save this - get subset? */ } __packed; -struct filesystem_device_info { - __le32 DeviceType; - __le32 DeviceCharacteristics; -} __packed; /* device info level 0x104 */ - struct filesystem_vol_info { __le64 VolumeCreationTime; __le32 SerialNumber; @@ -140,20 +135,6 @@ struct object_id_info { struct fs_extended_info extended_info; } __packed; -struct file_directory_info { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - char FileName[]; -} __packed; /* level 0x101 FF resp data */ - struct file_names_info { __le32 NextEntryOffset; __u32 FileIndex; @@ -161,39 +142,6 @@ struct file_names_info { char FileName[]; } __packed; /* level 0xc FF resp data */ -struct file_full_directory_info { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - __le32 EaSize; - char FileName[]; -} __packed; /* level 0x102 FF resp */ - -struct file_both_directory_info { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - __le32 EaSize; /* length of the xattrs */ - __u8 ShortNameLength; - __u8 Reserved; - __u8 ShortName[24]; - char FileName[]; -} __packed; /* level 0x104 FFrsp data */ - struct file_id_both_directory_info { __le32 NextEntryOffset; __u32 FileIndex; @@ -214,46 +162,6 @@ struct file_id_both_directory_info { char FileName[]; } __packed; -struct file_id_full_dir_info { - __le32 NextEntryOffset; - __u32 FileIndex; - __le64 CreationTime; - __le64 LastAccessTime; - __le64 LastWriteTime; - __le64 ChangeTime; - __le64 EndOfFile; - __le64 AllocationSize; - __le32 ExtFileAttributes; - __le32 FileNameLength; - __le32 EaSize; /* EA size */ - __le32 Reserved; - __le64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ - char FileName[]; -} __packed; /* level 0x105 FF rsp data */ - -struct filesystem_posix_info { - /* For undefined recommended transfer size return -1 in that field */ - __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ - __le32 BlockSize; - /* The next three fields are in terms of the block size. - * (above). If block size is unknown, 4096 would be a - * reasonable block size for a server to report. - * Note that returning the blocks/blocksavail removes need - * to make a second call (to QFSInfo level 0x103 to get this info. - * UserBlockAvail is typically less than or equal to BlocksAvail, - * if no distinction is made return the same value in each - */ - __le64 TotalBlocks; - __le64 BlocksAvail; /* bfree */ - __le64 UserBlocksAvail; /* bavail */ - /* For undefined Node fields or FSID return -1 */ - __le64 TotalFileNodes; - __le64 FreeFileNodes; - __le64 FileSysIdentifier; /* fsid */ - /* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */ - /* NB flags can come from FILE_SYSTEM_DEVICE_INFO call */ -} __packed; - struct smb_version_ops { u16 (*get_cmd_val)(struct ksmbd_work *swork); int (*init_rsp_hdr)(struct ksmbd_work *swork); diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c index 90e693e4e414..39db6992e4c9 100644 --- a/fs/smb/server/vfs.c +++ b/fs/smb/server/vfs.c @@ -1657,7 +1657,7 @@ int ksmbd_vfs_get_dos_attrib_xattr(struct mnt_idmap *idmap, */ void *ksmbd_vfs_init_kstat(char **p, struct ksmbd_kstat *ksmbd_kstat) { - struct file_directory_info *info = (struct file_directory_info *)(*p); + FILE_DIRECTORY_INFO *info = (FILE_DIRECTORY_INFO *)(*p); struct kstat *kstat = ksmbd_kstat->kstat; u64 time; From 464b913993a14b539e978db10c755bb202ab14ed Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Sun, 2 Nov 2025 15:30:56 +0800 Subject: [PATCH 27/44] smb: move FILE_SYSTEM_SIZE_INFO to common/fscc.h Rename the following places: - struct filesystem_info -> FILE_SYSTEM_SIZE_INFO - FILE_SYSTEM_INFO -> FILE_SYSTEM_SIZE_INFO - FreeAllocationUnits -> AvailableAllocationUnits: consistent with MS-FSCC 2.5.8 Then move duplicate definitions to common header file. Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/cifspdu.h | 7 ------- fs/smb/client/cifssmb.c | 6 +++--- fs/smb/common/fscc.h | 8 ++++++++ fs/smb/server/smb2pdu.c | 6 +++--- fs/smb/server/smb_common.h | 7 ------- 5 files changed, 14 insertions(+), 20 deletions(-) diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h index 39f431051860..a9a853b9011f 100644 --- a/fs/smb/client/cifspdu.h +++ b/fs/smb/client/cifspdu.h @@ -1982,13 +1982,6 @@ struct aliasInfo92 { int shareNameOffset; } __attribute__((packed)); -typedef struct { - __le64 TotalAllocationUnits; - __le64 FreeAllocationUnits; - __le32 SectorsPerAllocationUnit; - __le32 BytesPerSector; -} __attribute__((packed)) FILE_SYSTEM_INFO; /* size info, level 0x103 */ - typedef struct { __le32 fsid; __le32 SectorsPerAllocationUnit; diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index fba439447dec..428e582e0414 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -4746,7 +4746,7 @@ CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ TRANSACTION2_QFSI_REQ *pSMB = NULL; TRANSACTION2_QFSI_RSP *pSMBr = NULL; - FILE_SYSTEM_INFO *response_data; + FILE_SYSTEM_SIZE_INFO *response_data; int rc = 0; int bytes_returned = 0; __u16 params, byte_count; @@ -4794,7 +4794,7 @@ CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); response_data = - (FILE_SYSTEM_INFO + (FILE_SYSTEM_SIZE_INFO *) (((char *) &pSMBr->hdr.Protocol) + data_offset); FSData->f_bsize = @@ -4811,7 +4811,7 @@ CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon, FSData->f_blocks = le64_to_cpu(response_data->TotalAllocationUnits); FSData->f_bfree = FSData->f_bavail = - le64_to_cpu(response_data->FreeAllocationUnits); + le64_to_cpu(response_data->AvailableAllocationUnits); cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n", (unsigned long long)FSData->f_blocks, (unsigned long long)FSData->f_bfree, diff --git a/fs/smb/common/fscc.h b/fs/smb/common/fscc.h index 6fa7c65d304b..a0580a772a41 100644 --- a/fs/smb/common/fscc.h +++ b/fs/smb/common/fscc.h @@ -121,6 +121,14 @@ struct smb2_file_network_open_info { #define FILE_CASE_PRESERVED_NAMES 0x00000002 #define FILE_CASE_SENSITIVE_SEARCH 0x00000001 +/* See MS-FSCC 2.5.8 */ +typedef struct { + __le64 TotalAllocationUnits; + __le64 AvailableAllocationUnits; + __le32 SectorsPerAllocationUnit; + __le32 BytesPerSector; +} __packed FILE_SYSTEM_SIZE_INFO; /* size info, level 0x103 */ + /* See MS-FSCC 2.5.10 */ typedef struct { __le32 DeviceType; diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 5696ac8bf5e8..8facd4ca69d0 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -5536,11 +5536,11 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, } case FS_SIZE_INFORMATION: { - struct filesystem_info *info; + FILE_SYSTEM_SIZE_INFO *info; - info = (struct filesystem_info *)(rsp->Buffer); + info = (FILE_SYSTEM_SIZE_INFO *)(rsp->Buffer); info->TotalAllocationUnits = cpu_to_le64(stfs.f_blocks); - info->FreeAllocationUnits = cpu_to_le64(stfs.f_bfree); + info->AvailableAllocationUnits = cpu_to_le64(stfs.f_bfree); info->SectorsPerAllocationUnit = cpu_to_le32(1); info->BytesPerSector = cpu_to_le32(stfs.f_bsize); rsp->OutputBufferLength = cpu_to_le32(24); diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h index c171c1e190a5..13751a4f0888 100644 --- a/fs/smb/server/smb_common.h +++ b/fs/smb/server/smb_common.h @@ -112,13 +112,6 @@ struct filesystem_vol_info { __le16 VolumeLabel[]; } __packed; -struct filesystem_info { - __le64 TotalAllocationUnits; - __le64 FreeAllocationUnits; - __le32 SectorsPerAllocationUnit; - __le32 BytesPerSector; -} __packed; /* size info, level 0x103 */ - #define EXTENDED_INFO_MAGIC 0x43667364 /* Cfsd */ #define STRING_LENGTH 28 From 95e8c1bfa56ebbc243779ee23782b30744da02f6 Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Sun, 2 Nov 2025 15:30:58 +0800 Subject: [PATCH 28/44] smb: do some cleanups Modify the following places: - Add documentation references - ATTR_REPARSE -> ATTR_REPARSE_POINT: consistent with MS-SMB 2.2.1.2.1 - Remove unused File Attribute flags from server, if the server uses them in the future, we can move the client-side definitions to common - Remove unused SMB1_CLIENT_GUID_SIZE from server Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/cifspdu.h | 51 +++++++++++++++++++++----------------- fs/smb/client/readdir.c | 10 ++++---- fs/smb/client/reparse.h | 8 +++--- fs/smb/client/smb1ops.c | 2 +- fs/smb/client/smb2inode.c | 2 +- fs/smb/server/smb_common.h | 19 +++++--------- 6 files changed, 45 insertions(+), 47 deletions(-) diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h index a9a853b9011f..df603bdbe6ba 100644 --- a/fs/smb/client/cifspdu.h +++ b/fs/smb/client/cifspdu.h @@ -19,6 +19,7 @@ #define BAD_PROT 0xFFFF /* SMB command codes: + * See MS-CIFS 2.2.2.1 * Note some commands have minimal (wct=0,bcc=0), or uninteresting, responses * (ie which include no useful data other than the SMB error code itself). * This can allow us to avoid response buffer allocations and copy in some cases @@ -152,6 +153,7 @@ /* * SMB flag definitions + * See MS-CIFS 2.2.3.1 */ #define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock smb */ #define SMBFLG_RCV_POSTED 0x02 /* obsolete */ @@ -165,6 +167,8 @@ /* * SMB flag2 definitions + * See MS-CIFS 2.2.3.1 + * MS-SMB 2.2.3.1 */ #define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1) /* can send long (non-8.3) path names in response */ @@ -225,29 +229,30 @@ /* * File Attribute flags */ -#define ATTR_READONLY 0x0001 -#define ATTR_HIDDEN 0x0002 -#define ATTR_SYSTEM 0x0004 -#define ATTR_VOLUME 0x0008 -#define ATTR_DIRECTORY 0x0010 -#define ATTR_ARCHIVE 0x0020 -#define ATTR_DEVICE 0x0040 -#define ATTR_NORMAL 0x0080 -#define ATTR_TEMPORARY 0x0100 -#define ATTR_SPARSE 0x0200 -#define ATTR_REPARSE 0x0400 -#define ATTR_COMPRESSED 0x0800 -#define ATTR_OFFLINE 0x1000 /* ie file not immediately available - - on offline storage */ -#define ATTR_NOT_CONTENT_INDEXED 0x2000 -#define ATTR_ENCRYPTED 0x4000 -#define ATTR_POSIX_SEMANTICS 0x01000000 -#define ATTR_BACKUP_SEMANTICS 0x02000000 -#define ATTR_DELETE_ON_CLOSE 0x04000000 -#define ATTR_SEQUENTIAL_SCAN 0x08000000 -#define ATTR_RANDOM_ACCESS 0x10000000 -#define ATTR_NO_BUFFERING 0x20000000 -#define ATTR_WRITE_THROUGH 0x80000000 +#define ATTR_READONLY 0x0001 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_HIDDEN 0x0002 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_SYSTEM 0x0004 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_VOLUME 0x0008 +#define ATTR_DIRECTORY 0x0010 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_ARCHIVE 0x0020 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_DEVICE 0x0040 +#define ATTR_NORMAL 0x0080 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_TEMPORARY 0x0100 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_SPARSE 0x0200 /* See MS-SMB 2.2.1.2.1 */ +#define ATTR_REPARSE_POINT 0x0400 /* See MS-SMB 2.2.1.2.1 */ +#define ATTR_COMPRESSED 0x0800 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_OFFLINE 0x1000 /* See MS-SMB 2.2.1.2.1 + ie file not immediately available - + on offline storage */ +#define ATTR_NOT_CONTENT_INDEXED 0x2000 /* See MS-SMB 2.2.1.2.1 */ +#define ATTR_ENCRYPTED 0x4000 /* See MS-SMB 2.2.1.2.1 */ +#define ATTR_POSIX_SEMANTICS 0x0100000 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_BACKUP_SEMANTICS 0x0200000 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_DELETE_ON_CLOSE 0x0400000 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_SEQUENTIAL_SCAN 0x0800000 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_RANDOM_ACCESS 0x1000000 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_NO_BUFFERING 0x2000000 /* See MS-CIFS 2.2.1.2.3 */ +#define ATTR_WRITE_THROUGH 0x8000000 /* See MS-CIFS 2.2.1.2.3 */ /* ShareAccess flags */ #define FILE_NO_SHARE 0x00000000 diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c index 2fd95c1e91ab..7ff728503ed1 100644 --- a/fs/smb/client/readdir.c +++ b/fs/smb/client/readdir.c @@ -98,7 +98,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, default: break; } - } else if (fattr->cf_cifsattrs & ATTR_REPARSE) { + } else if (fattr->cf_cifsattrs & ATTR_REPARSE_POINT) { reparse_need_reval = true; } @@ -138,7 +138,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, * reparse tag and ctime haven't changed. */ rc = 0; - if (fattr->cf_cifsattrs & ATTR_REPARSE) { + if (fattr->cf_cifsattrs & ATTR_REPARSE_POINT) { if (likely(reparse_inode_match(inode, fattr))) { fattr->cf_mode = inode->i_mode; fattr->cf_rdev = inode->i_rdev; @@ -190,7 +190,7 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) * TODO: go through all documented reparse tags to see if we can * reasonably map some of them to directories vs. files vs. symlinks */ - if ((fattr->cf_cifsattrs & ATTR_REPARSE) && + if ((fattr->cf_cifsattrs & ATTR_REPARSE_POINT) && cifs_reparse_point_to_fattr(cifs_sb, fattr, &data)) goto out_reparse; @@ -258,7 +258,7 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info, fattr->cf_nlink = le32_to_cpu(info->HardLinks); fattr->cf_cifsattrs = le32_to_cpu(info->DosAttributes); - if (fattr->cf_cifsattrs & ATTR_REPARSE) + if (fattr->cf_cifsattrs & ATTR_REPARSE_POINT) fattr->cf_cifstag = le32_to_cpu(info->ReparseTag); /* The Mode field in the response can now include the file type as well */ @@ -316,7 +316,7 @@ static void cifs_fulldir_info_to_fattr(struct cifs_fattr *fattr, __dir_info_to_fattr(fattr, info); /* See MS-FSCC 2.4.14, 2.4.19 */ - if (fattr->cf_cifsattrs & ATTR_REPARSE) + if (fattr->cf_cifsattrs & ATTR_REPARSE_POINT) fattr->cf_cifstag = le32_to_cpu(di->EaSize); cifs_fill_common_info(fattr, cifs_sb); } diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h index 66269c10beba..19caab2fd11e 100644 --- a/fs/smb/client/reparse.h +++ b/fs/smb/client/reparse.h @@ -93,7 +93,7 @@ static inline bool reparse_inode_match(struct inode *inode, if (cinode->reparse_tag != IO_REPARSE_TAG_INTERNAL && cinode->reparse_tag != fattr->cf_cifstag) return false; - return (cinode->cifsAttrs & ATTR_REPARSE) && + return (cinode->cifsAttrs & ATTR_REPARSE_POINT) && timespec64_equal(&ctime, &fattr->cf_ctime); } @@ -107,7 +107,7 @@ static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data) attrs = le32_to_cpu(fi->DosAttributes); if (data->reparse_point) { - attrs |= ATTR_REPARSE; + attrs |= ATTR_REPARSE_POINT; fi->DosAttributes = cpu_to_le32(attrs); } @@ -116,12 +116,12 @@ static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data) attrs = le32_to_cpu(fi->Attributes); if (data->reparse_point) { - attrs |= ATTR_REPARSE; + attrs |= ATTR_REPARSE_POINT; fi->Attributes = cpu_to_le32(attrs); } } - ret = attrs & ATTR_REPARSE; + ret = attrs & ATTR_REPARSE_POINT; return ret; } diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index ca8f3dd7ff63..a15ebd3f0d50 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -647,7 +647,7 @@ static int cifs_query_path_info(const unsigned int xid, if (!rc) { move_cifs_info_to_smb2(&data->fi, &fi); - data->reparse_point = le32_to_cpu(fi.Attributes) & ATTR_REPARSE; + data->reparse_point = le32_to_cpu(fi.Attributes) & ATTR_REPARSE_POINT; } #ifdef CONFIG_CIFS_XATTR diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c index 69cb81fa0d3a..d0aad4821ed4 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -50,7 +50,7 @@ static inline __u32 file_create_options(struct dentry *dentry) if (dentry) { ci = CIFS_I(d_inode(dentry)); - if (ci->cifsAttrs & ATTR_REPARSE) + if (ci->cifsAttrs & ATTR_REPARSE_POINT) return OPEN_REPARSE_POINT; } return 0; diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h index 13751a4f0888..a91717da3895 100644 --- a/fs/smb/server/smb_common.h +++ b/fs/smb/server/smb_common.h @@ -38,17 +38,6 @@ #define F_CREATED 2 #define F_OVERWRITTEN 3 -/* - * File Attribute flags - */ -#define ATTR_POSIX_SEMANTICS 0x01000000 -#define ATTR_BACKUP_SEMANTICS 0x02000000 -#define ATTR_DELETE_ON_CLOSE 0x04000000 -#define ATTR_SEQUENTIAL_SCAN 0x08000000 -#define ATTR_RANDOM_ACCESS 0x10000000 -#define ATTR_NO_BUFFERING 0x20000000 -#define ATTR_WRITE_THROUGH 0x80000000 - /* Combinations of file access permission bits */ #define SET_FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA \ | FILE_READ_ATTRIBUTES \ @@ -80,11 +69,15 @@ FILE_EXECUTE | FILE_DELETE_CHILD | \ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES) -#define SMB_COM_NEGOTIATE 0x72 -#define SMB1_CLIENT_GUID_SIZE (16) +#define SMB_COM_NEGOTIATE 0x72 /* See MS-CIFS 2.2.2.1 */ +/* See MS-CIFS 2.2.3.1 */ #define SMBFLG_RESPONSE 0x80 /* this PDU is a response from server */ +/* + * See MS-CIFS 2.2.3.1 + * MS-SMB 2.2.3.1 + */ #define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40) #define SMBFLG2_EXT_SEC cpu_to_le16(0x800) #define SMBFLG2_ERR_STATUS cpu_to_le16(0x4000) From e7e60e8bfcc5bfff0dc40a3b8ab275a4da6990a0 Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Sun, 2 Nov 2025 15:30:59 +0800 Subject: [PATCH 29/44] smb: fix some warnings reported by scripts/checkpatch.pl Fix the following warnings: WARNING: __always_unused or __maybe_unused is preferred over \ __attribute__((__unused__)) WARNING: Prefer __packed over __attribute__((packed)) Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/cifspdu.h | 250 ++++++++++++++++++------------------- fs/smb/client/connect.c | 4 +- fs/smb/client/ntlmssp.h | 8 +- fs/smb/client/rfc1002pdu.h | 8 +- fs/smb/common/smbacl.h | 8 +- 5 files changed, 139 insertions(+), 139 deletions(-) diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h index df603bdbe6ba..d84e10b1477f 100644 --- a/fs/smb/client/cifspdu.h +++ b/fs/smb/client/cifspdu.h @@ -425,8 +425,8 @@ typedef struct smb_negotiate_rsp { struct { unsigned char GUID[SMB1_CLIENT_GUID_SIZE]; unsigned char SecurityBlob[]; - } __attribute__((packed)) extended_response; - } __attribute__((packed)) u; + } __packed extended_response; + } __packed u; } __packed SMB_NEGOTIATE_RSP; /* SecurityMode bits */ @@ -474,7 +474,7 @@ typedef union smb_com_session_setup_andx { unsigned char SecurityBlob[]; /* followed by */ /* STRING NativeOS */ /* STRING NativeLanMan */ - } __attribute__((packed)) req; /* NTLM request format (with + } __packed req; /* NTLM request format (with extended security */ struct { /* request format */ @@ -497,7 +497,7 @@ typedef union smb_com_session_setup_andx { /* STRING PrimaryDomain */ /* STRING NativeOS */ /* STRING NativeLanMan */ - } __attribute__((packed)) req_no_secext; /* NTLM request format (without + } __packed req_no_secext; /* NTLM request format (without extended security */ struct { /* default (NTLM) response format */ @@ -512,7 +512,7 @@ typedef union smb_com_session_setup_andx { /* unsigned char * NativeOS; */ /* unsigned char * NativeLanMan; */ /* unsigned char * PrimaryDomain; */ - } __attribute__((packed)) resp; /* NTLM response + } __packed resp; /* NTLM response (with or without extended sec) */ struct { /* request format */ @@ -532,7 +532,7 @@ typedef union smb_com_session_setup_andx { /* STRING PrimaryDomain */ /* STRING NativeOS */ /* STRING NativeLanMan */ - } __attribute__((packed)) old_req; /* pre-NTLM (LANMAN2.1) req format */ + } __packed old_req; /* pre-NTLM (LANMAN2.1) req format */ struct { /* default (NTLM) response format */ struct smb_hdr hdr; /* wct = 3 */ @@ -544,8 +544,8 @@ typedef union smb_com_session_setup_andx { unsigned char NativeOS[]; /* followed by */ /* unsigned char * NativeLanMan; */ /* unsigned char * PrimaryDomain; */ - } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */ -} __attribute__((packed)) SESSION_SETUP_ANDX; + } __packed old_resp; /* pre-NTLM (LANMAN2.1) response */ +} __packed SESSION_SETUP_ANDX; /* format of NLTMv2 Response ie "case sensitive password" hash when NTLMv2 */ @@ -559,7 +559,7 @@ struct ntlmssp2_name { __le16 type; __le16 length; __u8 data[]; -} __attribute__((packed)); +} __packed; struct ntlmv2_resp { union { @@ -567,15 +567,15 @@ struct ntlmv2_resp { struct { __u8 reserved[8]; __u8 key[CIFS_SERVER_CHALLENGE_SIZE]; - } __attribute__((packed)) challenge; - } __attribute__((packed)); + } __packed challenge; + } __packed; __le32 blob_signature; __u32 reserved; __le64 time; __u64 client_chal; /* random */ __u32 reserved2; /* array of name entries could follow ending in minimum 4 byte struct */ -} __attribute__((packed)); +} __packed; #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" @@ -610,7 +610,7 @@ typedef struct smb_com_tconx_req { unsigned char Password[]; /* followed by */ /* STRING Path *//* \\server\share name */ /* STRING Service */ -} __attribute__((packed)) TCONX_REQ; +} __packed TCONX_REQ; typedef struct smb_com_tconx_rsp { struct smb_hdr hdr; /* wct = 3 , not extended response */ @@ -621,7 +621,7 @@ typedef struct smb_com_tconx_rsp { __u16 ByteCount; unsigned char Service[]; /* always ASCII, not Unicode */ /* STRING NativeFileSystem */ -} __attribute__((packed)) TCONX_RSP; +} __packed TCONX_RSP; typedef struct smb_com_tconx_rsp_ext { struct smb_hdr hdr; /* wct = 7, extended response */ @@ -634,7 +634,7 @@ typedef struct smb_com_tconx_rsp_ext { __u16 ByteCount; unsigned char Service[]; /* always ASCII, not Unicode */ /* STRING NativeFileSystem */ -} __attribute__((packed)) TCONX_RSP_EXT; +} __packed TCONX_RSP_EXT; /* tree connect Flags */ @@ -670,14 +670,14 @@ typedef struct smb_com_echo_req { __le16 EchoCount; __le16 ByteCount; char Data[]; -} __attribute__((packed)) ECHO_REQ; +} __packed ECHO_REQ; typedef struct smb_com_echo_rsp { struct smb_hdr hdr; __le16 SequenceNumber; __le16 ByteCount; char Data[]; -} __attribute__((packed)) ECHO_RSP; +} __packed ECHO_RSP; typedef struct smb_com_logoff_andx_req { struct smb_hdr hdr; /* wct = 2 */ @@ -685,7 +685,7 @@ typedef struct smb_com_logoff_andx_req { __u8 AndXReserved; __u16 AndXOffset; __u16 ByteCount; -} __attribute__((packed)) LOGOFF_ANDX_REQ; +} __packed LOGOFF_ANDX_REQ; typedef struct smb_com_logoff_andx_rsp { struct smb_hdr hdr; /* wct = 2 */ @@ -693,7 +693,7 @@ typedef struct smb_com_logoff_andx_rsp { __u8 AndXReserved; __u16 AndXOffset; __u16 ByteCount; -} __attribute__((packed)) LOGOFF_ANDX_RSP; +} __packed LOGOFF_ANDX_RSP; typedef union smb_com_tree_disconnect { /* as an alternative can use flag on tree_connect PDU to effect disconnect */ @@ -701,36 +701,36 @@ typedef union smb_com_tree_disconnect { /* as an alternative can use flag on struct { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bcc = 0 */ - } __attribute__((packed)) req; + } __packed req; struct { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bcc = 0 */ - } __attribute__((packed)) resp; -} __attribute__((packed)) TREE_DISCONNECT; + } __packed resp; +} __packed TREE_DISCONNECT; typedef struct smb_com_close_req { struct smb_hdr hdr; /* wct = 3 */ __u16 FileID; __u32 LastWriteTime; /* should be zero or -1 */ __u16 ByteCount; /* 0 */ -} __attribute__((packed)) CLOSE_REQ; +} __packed CLOSE_REQ; typedef struct smb_com_close_rsp { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) CLOSE_RSP; +} __packed CLOSE_RSP; typedef struct smb_com_flush_req { struct smb_hdr hdr; /* wct = 1 */ __u16 FileID; __u16 ByteCount; /* 0 */ -} __attribute__((packed)) FLUSH_REQ; +} __packed FLUSH_REQ; typedef struct smb_com_findclose_req { struct smb_hdr hdr; /* wct = 1 */ __u16 FileID; __u16 ByteCount; /* 0 */ -} __attribute__((packed)) FINDCLOSE_REQ; +} __packed FINDCLOSE_REQ; /* OpenFlags */ #define REQ_MORE_INFO 0x00000001 /* legacy (OPEN_AND_X) only */ @@ -777,7 +777,7 @@ typedef struct smb_com_open_req { /* also handles create */ __u8 SecurityFlags; __le16 ByteCount; char fileName[]; -} __attribute__((packed)) OPEN_REQ; +} __packed OPEN_REQ; /* open response: oplock levels */ #define OPLOCK_NONE 0 @@ -809,7 +809,7 @@ typedef struct smb_com_open_rsp { __le16 DeviceState; __u8 DirectoryFlag; __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) OPEN_RSP; +} __packed OPEN_RSP; typedef struct smb_com_open_rsp_ext { struct smb_hdr hdr; /* wct = 42 but meaningless due to MS bug? */ @@ -834,7 +834,7 @@ typedef struct smb_com_open_rsp_ext { __le32 MaximalAccessRights; __le32 GuestMaximalAccessRights; __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) OPEN_RSP_EXT; +} __packed OPEN_RSP_EXT; /* format of legacy open request */ @@ -854,7 +854,7 @@ typedef struct smb_com_openx_req { __le32 Reserved; __le16 ByteCount; /* file name follows */ char fileName[]; -} __attribute__((packed)) OPENX_REQ; +} __packed OPENX_REQ; typedef struct smb_com_openx_rsp { struct smb_hdr hdr; /* wct = 15 */ @@ -872,7 +872,7 @@ typedef struct smb_com_openx_rsp { __u32 FileId; __u16 Reserved; __u16 ByteCount; -} __attribute__((packed)) OPENX_RSP; +} __packed OPENX_RSP; /* For encoding of POSIX Open Request - see trans2 function 0x209 data struct */ @@ -894,7 +894,7 @@ typedef struct smb_com_writex_req { __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ char Data[]; -} __attribute__((packed)) WRITEX_REQ; +} __packed WRITEX_REQ; typedef struct smb_com_write_req { struct smb_hdr hdr; /* wct = 14 */ @@ -914,7 +914,7 @@ typedef struct smb_com_write_req { __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ char Data[]; -} __attribute__((packed)) WRITE_REQ; +} __packed WRITE_REQ; typedef struct smb_com_write_rsp { struct smb_hdr hdr; /* wct = 6 */ @@ -926,7 +926,7 @@ typedef struct smb_com_write_rsp { __le16 CountHigh; __u16 Reserved; __u16 ByteCount; -} __attribute__((packed)) WRITE_RSP; +} __packed WRITE_RSP; /* legacy read request for older servers */ typedef struct smb_com_readx_req { @@ -941,7 +941,7 @@ typedef struct smb_com_readx_req { __le32 Reserved; __le16 Remaining; __le16 ByteCount; -} __attribute__((packed)) READX_REQ; +} __packed READX_REQ; typedef struct smb_com_read_req { struct smb_hdr hdr; /* wct = 12 */ @@ -956,7 +956,7 @@ typedef struct smb_com_read_req { __le16 Remaining; __le32 OffsetHigh; __le16 ByteCount; -} __attribute__((packed)) READ_REQ; +} __packed READ_REQ; typedef struct smb_com_read_rsp { struct smb_hdr hdr; /* wct = 12 */ @@ -972,7 +972,7 @@ typedef struct smb_com_read_rsp { __u64 Reserved2; __u16 ByteCount; /* read response data immediately follows */ -} __attribute__((packed)) READ_RSP; +} __packed READ_RSP; typedef struct locking_andx_range { __le16 Pid; @@ -981,7 +981,7 @@ typedef struct locking_andx_range { __le32 OffsetLow; __le32 LengthHigh; __le32 LengthLow; -} __attribute__((packed)) LOCKING_ANDX_RANGE; +} __packed LOCKING_ANDX_RANGE; #define LOCKING_ANDX_SHARED_LOCK 0x01 #define LOCKING_ANDX_OPLOCK_RELEASE 0x02 @@ -1002,7 +1002,7 @@ typedef struct smb_com_lock_req { __le16 NumberOfLocks; __le16 ByteCount; LOCKING_ANDX_RANGE Locks[]; -} __attribute__((packed)) LOCK_REQ; +} __packed LOCK_REQ; /* lock type */ #define CIFS_RDLCK 0 @@ -1015,7 +1015,7 @@ typedef struct cifs_posix_lock { __le64 start; __le64 length; /* BB what about additional owner info to identify network client */ -} __attribute__((packed)) CIFS_POSIX_LOCK; +} __packed CIFS_POSIX_LOCK; typedef struct smb_com_lock_rsp { struct smb_hdr hdr; /* wct = 2 */ @@ -1023,7 +1023,7 @@ typedef struct smb_com_lock_rsp { __u8 AndXReserved; __le16 AndXOffset; __u16 ByteCount; -} __attribute__((packed)) LOCK_RSP; +} __packed LOCK_RSP; typedef struct smb_com_rename_req { struct smb_hdr hdr; /* wct = 1 */ @@ -1033,7 +1033,7 @@ typedef struct smb_com_rename_req { unsigned char OldFileName[]; /* followed by __u8 BufferFormat2 */ /* followed by NewFileName */ -} __attribute__((packed)) RENAME_REQ; +} __packed RENAME_REQ; /* copy request flags */ #define COPY_MUST_BE_FILE 0x0001 @@ -1053,7 +1053,7 @@ typedef struct smb_com_copy_req { unsigned char OldFileName[]; /* followed by __u8 BufferFormat2 */ /* followed by NewFileName string */ -} __attribute__((packed)) COPY_REQ; +} __packed COPY_REQ; typedef struct smb_com_copy_rsp { struct smb_hdr hdr; /* wct = 1 */ @@ -1061,7 +1061,7 @@ typedef struct smb_com_copy_rsp { __u16 ByteCount; /* may be zero */ __u8 BufferFormat; /* 0x04 - only present if errored file follows */ unsigned char ErrorFileName[]; /* only present if error in copy */ -} __attribute__((packed)) COPY_RSP; +} __packed COPY_RSP; #define CREATE_HARD_LINK 0x103 #define MOVEFILE_COPY_ALLOWED 0x0002 @@ -1077,12 +1077,12 @@ typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */ unsigned char OldFileName[]; /* followed by __u8 BufferFormat2 */ /* followed by NewFileName */ -} __attribute__((packed)) NT_RENAME_REQ; +} __packed NT_RENAME_REQ; typedef struct smb_com_rename_rsp { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) RENAME_RSP; +} __packed RENAME_RSP; typedef struct smb_com_delete_file_req { struct smb_hdr hdr; /* wct = 1 */ @@ -1090,43 +1090,43 @@ typedef struct smb_com_delete_file_req { __le16 ByteCount; __u8 BufferFormat; /* 4 = ASCII */ unsigned char fileName[]; -} __attribute__((packed)) DELETE_FILE_REQ; +} __packed DELETE_FILE_REQ; typedef struct smb_com_delete_file_rsp { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) DELETE_FILE_RSP; +} __packed DELETE_FILE_RSP; typedef struct smb_com_delete_directory_req { struct smb_hdr hdr; /* wct = 0 */ __le16 ByteCount; __u8 BufferFormat; /* 4 = ASCII */ unsigned char DirName[]; -} __attribute__((packed)) DELETE_DIRECTORY_REQ; +} __packed DELETE_DIRECTORY_REQ; typedef struct smb_com_delete_directory_rsp { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) DELETE_DIRECTORY_RSP; +} __packed DELETE_DIRECTORY_RSP; typedef struct smb_com_create_directory_req { struct smb_hdr hdr; /* wct = 0 */ __le16 ByteCount; __u8 BufferFormat; /* 4 = ASCII */ unsigned char DirName[]; -} __attribute__((packed)) CREATE_DIRECTORY_REQ; +} __packed CREATE_DIRECTORY_REQ; typedef struct smb_com_create_directory_rsp { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) CREATE_DIRECTORY_RSP; +} __packed CREATE_DIRECTORY_RSP; typedef struct smb_com_query_information_req { struct smb_hdr hdr; /* wct = 0 */ __le16 ByteCount; /* 1 + namelen + 1 */ __u8 BufferFormat; /* 4 = ASCII */ unsigned char FileName[]; -} __attribute__((packed)) QUERY_INFORMATION_REQ; +} __packed QUERY_INFORMATION_REQ; typedef struct smb_com_query_information_rsp { struct smb_hdr hdr; /* wct = 10 */ @@ -1135,7 +1135,7 @@ typedef struct smb_com_query_information_rsp { __le32 size; __u16 reserved[5]; __le16 ByteCount; /* bcc = 0 */ -} __attribute__((packed)) QUERY_INFORMATION_RSP; +} __packed QUERY_INFORMATION_RSP; typedef struct smb_com_setattr_req { struct smb_hdr hdr; /* wct = 8 */ @@ -1145,12 +1145,12 @@ typedef struct smb_com_setattr_req { __le16 ByteCount; __u8 BufferFormat; /* 4 = ASCII */ unsigned char fileName[]; -} __attribute__((packed)) SETATTR_REQ; +} __packed SETATTR_REQ; typedef struct smb_com_setattr_rsp { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bct = 0 */ -} __attribute__((packed)) SETATTR_RSP; +} __packed SETATTR_RSP; /* empty wct response to setattr */ @@ -1178,7 +1178,7 @@ typedef struct smb_com_ntransact_req { __le16 ByteCount; __u8 Pad[3]; __u8 Parms[]; -} __attribute__((packed)) NTRANSACT_REQ; +} __packed NTRANSACT_REQ; typedef struct smb_com_ntransact_rsp { struct smb_hdr hdr; /* wct = 18 */ @@ -1195,7 +1195,7 @@ typedef struct smb_com_ntransact_rsp { __u16 ByteCount; /* __u8 Pad[3]; */ /* parms and data follow */ -} __attribute__((packed)) NTRANSACT_RSP; +} __packed NTRANSACT_RSP; typedef struct smb_com_transaction_ioctl_req { struct smb_hdr hdr; /* wct = 23 */ @@ -1219,7 +1219,7 @@ typedef struct smb_com_transaction_ioctl_req { __le16 ByteCount; __u8 Pad[3]; __u8 Data[]; -} __attribute__((packed)) TRANSACT_IOCTL_REQ; +} __packed TRANSACT_IOCTL_REQ; typedef struct smb_com_transaction_compr_ioctl_req { struct smb_hdr hdr; /* wct = 23 */ @@ -1243,7 +1243,7 @@ typedef struct smb_com_transaction_compr_ioctl_req { __le16 ByteCount; __u8 Pad[3]; __le16 compression_state; /* See below for valid flags */ -} __attribute__((packed)) TRANSACT_COMPR_IOCTL_REQ; +} __packed TRANSACT_COMPR_IOCTL_REQ; /* compression state flags */ #define COMPRESSION_FORMAT_NONE 0x0000 @@ -1264,7 +1264,7 @@ typedef struct smb_com_transaction_ioctl_rsp { __u8 SetupCount; /* 1 */ __le16 ReturnedDataLen; __le16 ByteCount; -} __attribute__((packed)) TRANSACT_IOCTL_RSP; +} __packed TRANSACT_IOCTL_RSP; #define CIFS_ACL_OWNER 1 #define CIFS_ACL_GROUP 2 @@ -1291,7 +1291,7 @@ typedef struct smb_com_transaction_qsec_req { __u16 Fid; __u16 Reserved2; __le32 AclFlags; -} __attribute__((packed)) QUERY_SEC_DESC_REQ; +} __packed QUERY_SEC_DESC_REQ; typedef struct smb_com_transaction_ssec_req { @@ -1314,7 +1314,7 @@ typedef struct smb_com_transaction_ssec_req { __u16 Fid; __u16 Reserved2; __le32 AclFlags; -} __attribute__((packed)) SET_SEC_DESC_REQ; +} __packed SET_SEC_DESC_REQ; typedef struct smb_com_transaction_change_notify_req { struct smb_hdr hdr; /* wct = 23 */ @@ -1338,7 +1338,7 @@ typedef struct smb_com_transaction_change_notify_req { __le16 ByteCount; /* __u8 Pad[3];*/ /* __u8 Data[];*/ -} __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ; +} __packed TRANSACT_CHANGE_NOTIFY_REQ; /* BB eventually change to use generic ntransact rsp struct and validation routine */ @@ -1356,7 +1356,7 @@ typedef struct smb_com_transaction_change_notify_rsp { __u8 SetupCount; /* 0 */ __u16 ByteCount; /* __u8 Pad[3]; */ -} __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_RSP; +} __packed TRANSACT_CHANGE_NOTIFY_RSP; /* Completion Filter flags for Notify */ #define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 #define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 @@ -1387,7 +1387,7 @@ struct file_notify_information { __le32 Action; __le32 FileNameLength; __u8 FileName[]; -} __attribute__((packed)); +} __packed; struct cifs_quota_data { __u32 rsrvd1; /* 0 */ @@ -1397,7 +1397,7 @@ struct cifs_quota_data { __u64 soft_limit; __u64 hard_limit; char sid[]; /* variable size? */ -} __attribute__((packed)); +} __packed; /* quota sub commands */ #define QUOTA_LIST_CONTINUE 0 @@ -1423,12 +1423,12 @@ struct trans2_req { __u8 Reserved3; __le16 SubCommand; /* 1st setup word - SetupCount words follow */ __le16 ByteCount; -} __attribute__((packed)); +} __packed; struct smb_t2_req { struct smb_hdr hdr; struct trans2_req t2_req; -} __attribute__((packed)); +} __packed; struct trans2_resp { /* struct smb_hdr hdr precedes. Note wct = 10 + setup count */ @@ -1447,12 +1447,12 @@ struct trans2_resp { __u16 ByteCount; __u16 Reserved2;*/ /* data area follows */ -} __attribute__((packed)); +} __packed; struct smb_t2_rsp { struct smb_hdr hdr; struct trans2_resp t2_rsp; -} __attribute__((packed)); +} __packed; /* PathInfo/FileInfo infolevels */ #define SMB_INFO_STANDARD 1 @@ -1549,14 +1549,14 @@ typedef struct smb_com_transaction2_qpi_req { __le16 InformationLevel; __u32 Reserved4; char FileName[]; -} __attribute__((packed)) TRANSACTION2_QPI_REQ; +} __packed TRANSACTION2_QPI_REQ; typedef struct smb_com_transaction2_qpi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct trans2_resp t2; __u16 ByteCount; __u16 Reserved2; /* parameter word is present for infolevels > 100 */ -} __attribute__((packed)) TRANSACTION2_QPI_RSP; +} __packed TRANSACTION2_QPI_RSP; typedef struct smb_com_transaction2_spi_req { struct smb_hdr hdr; /* wct = 15 */ @@ -1582,21 +1582,21 @@ typedef struct smb_com_transaction2_spi_req { __le16 InformationLevel; __u32 Reserved4; char FileName[]; -} __attribute__((packed)) TRANSACTION2_SPI_REQ; +} __packed TRANSACTION2_SPI_REQ; typedef struct smb_com_transaction2_spi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct trans2_resp t2; __u16 ByteCount; __u16 Reserved2; /* parameter word is present for infolevels > 100 */ -} __attribute__((packed)) TRANSACTION2_SPI_RSP; +} __packed TRANSACTION2_SPI_RSP; struct set_file_rename { __le32 overwrite; /* 1 = overwrite dest */ __u32 root_fid; /* zero */ __le32 target_name_len; char target_name[]; /* Must be unicode */ -} __attribute__((packed)); +} __packed; struct smb_com_transaction2_sfi_req { struct smb_hdr hdr; /* wct = 15 */ @@ -1623,14 +1623,14 @@ struct smb_com_transaction2_sfi_req { __le16 InformationLevel; __u16 Reserved4; __u8 payload[]; -} __attribute__((packed)); +} __packed; struct smb_com_transaction2_sfi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct trans2_resp t2; __u16 ByteCount; __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ -} __attribute__((packed)); +} __packed; struct smb_t2_qfi_req { struct smb_hdr hdr; @@ -1638,14 +1638,14 @@ struct smb_t2_qfi_req { __u8 Pad; __u16 Fid; __le16 InformationLevel; -} __attribute__((packed)); +} __packed; struct smb_t2_qfi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct trans2_resp t2; __u16 ByteCount; __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ -} __attribute__((packed)); +} __packed; /* * Flags on T2 FINDFIRST and FINDNEXT @@ -1687,13 +1687,13 @@ typedef struct smb_com_transaction2_ffirst_req { __le16 InformationLevel; __le32 SearchStorageType; char FileName[]; -} __attribute__((packed)) TRANSACTION2_FFIRST_REQ; +} __packed TRANSACTION2_FFIRST_REQ; typedef struct smb_com_transaction2_ffirst_rsp { struct smb_hdr hdr; /* wct = 10 */ struct trans2_resp t2; __u16 ByteCount; -} __attribute__((packed)) TRANSACTION2_FFIRST_RSP; +} __packed TRANSACTION2_FFIRST_RSP; typedef struct smb_com_transaction2_ffirst_rsp_parms { __u16 SearchHandle; @@ -1701,7 +1701,7 @@ typedef struct smb_com_transaction2_ffirst_rsp_parms { __le16 EndofSearch; __le16 EAErrorOffset; __le16 LastNameOffset; -} __attribute__((packed)) T2_FFIRST_RSP_PARMS; +} __packed T2_FFIRST_RSP_PARMS; typedef struct smb_com_transaction2_fnext_req { struct smb_hdr hdr; /* wct = 15 */ @@ -1729,20 +1729,20 @@ typedef struct smb_com_transaction2_fnext_req { __u32 ResumeKey; __le16 SearchFlags; char ResumeFileName[]; -} __attribute__((packed)) TRANSACTION2_FNEXT_REQ; +} __packed TRANSACTION2_FNEXT_REQ; typedef struct smb_com_transaction2_fnext_rsp { struct smb_hdr hdr; /* wct = 10 */ struct trans2_resp t2; __u16 ByteCount; -} __attribute__((packed)) TRANSACTION2_FNEXT_RSP; +} __packed TRANSACTION2_FNEXT_RSP; typedef struct smb_com_transaction2_fnext_rsp_parms { __le16 SearchCount; __le16 EndofSearch; __le16 EAErrorOffset; __le16 LastNameOffset; -} __attribute__((packed)) T2_FNEXT_RSP_PARMS; +} __packed T2_FNEXT_RSP_PARMS; /* QFSInfo Levels */ #define SMB_INFO_ALLOCATION 1 @@ -1786,14 +1786,14 @@ typedef struct smb_com_transaction2_qfsi_req { __le16 ByteCount; __u8 Pad; __le16 InformationLevel; -} __attribute__((packed)) TRANSACTION2_QFSI_REQ; +} __packed TRANSACTION2_QFSI_REQ; typedef struct smb_com_transaction_qfsi_rsp { struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct trans2_resp t2; __u16 ByteCount; __u8 Pad; /* may be three bytes? *//* followed by data area */ -} __attribute__((packed)) TRANSACTION2_QFSI_RSP; +} __packed TRANSACTION2_QFSI_RSP; typedef struct whoami_rsp_data { /* Query level 0x202 */ __u32 flags; /* 0 = Authenticated user 1 = GUEST */ @@ -1806,7 +1806,7 @@ typedef struct whoami_rsp_data { /* Query level 0x202 */ __u32 pad; /* reserved - MBZ */ /* __u64 gid_array[0]; */ /* may be empty */ /* __u8 * psid_list */ /* may be empty */ -} __attribute__((packed)) WHOAMI_RSP_DATA; +} __packed WHOAMI_RSP_DATA; /* SETFSInfo Levels */ #define SMB_SET_CIFS_UNIX_INFO 0x200 @@ -1839,7 +1839,7 @@ typedef struct smb_com_transaction2_setfsi_req { __le16 ClientUnixMajor; /* Data start. */ __le16 ClientUnixMinor; __le64 ClientUnixCap; /* Data end */ -} __attribute__((packed)) TRANSACTION2_SETFSI_REQ; +} __packed TRANSACTION2_SETFSI_REQ; /* level 0x203 request structure follows */ typedef struct smb_com_transaction2_setfs_enc_req { @@ -1865,14 +1865,14 @@ typedef struct smb_com_transaction2_setfs_enc_req { __u16 Reserved4; /* Parameters start. */ __le16 InformationLevel;/* Parameters end. */ /* NTLMSSP Blob, Data start. */ -} __attribute__((packed)) TRANSACTION2_SETFSI_ENC_REQ; +} __packed TRANSACTION2_SETFSI_ENC_REQ; /* response for setfsinfo levels 0x200 and 0x203 */ typedef struct smb_com_transaction2_setfsi_rsp { struct smb_hdr hdr; /* wct = 10 */ struct trans2_resp t2; __u16 ByteCount; -} __attribute__((packed)) TRANSACTION2_SETFSI_RSP; +} __packed TRANSACTION2_SETFSI_RSP; typedef struct smb_com_transaction2_get_dfs_refer_req { struct smb_hdr hdr; /* wct = 15 */ @@ -1898,7 +1898,7 @@ typedef struct smb_com_transaction2_get_dfs_refer_req { seem to matter though */ __le16 MaxReferralLevel; char RequestFileName[]; -} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ; +} __packed TRANSACTION2_GET_DFS_REFER_REQ; #define DFS_VERSION cpu_to_le16(0x0003) @@ -1920,7 +1920,7 @@ typedef struct dfs_referral_level_3 { /* version 4 is same, + one flag bit */ __le16 DfsAlternatePathOffset; __le16 NetworkAddressOffset; /* offset of the link target */ __u8 ServiceSiteGuid[16]; /* MBZ, ignored */ -} __attribute__((packed)) REFERRAL3; +} __packed REFERRAL3; struct get_dfs_referral_rsp { __le16 PathConsumed; @@ -1960,7 +1960,7 @@ struct serverInfo { unsigned char versionMinor; unsigned long type; unsigned int commentOffset; -} __attribute__((packed)); +} __packed; /* * The following structure is the format of the data returned on a NetShareEnum @@ -1972,20 +1972,20 @@ struct shareInfo { char pad; unsigned short type; unsigned int commentOffset; -} __attribute__((packed)); +} __packed; struct aliasInfo { char aliasName[9]; char pad; unsigned int commentOffset; unsigned char type[2]; -} __attribute__((packed)); +} __packed; struct aliasInfo92 { int aliasNameOffset; int serverNameOffset; int shareNameOffset; -} __attribute__((packed)); +} __packed; typedef struct { __le32 fsid; @@ -1993,13 +1993,13 @@ typedef struct { __le32 TotalAllocationUnits; __le32 FreeAllocationUnits; __le16 BytesPerSector; -} __attribute__((packed)) FILE_SYSTEM_ALLOC_INFO; +} __packed FILE_SYSTEM_ALLOC_INFO; typedef struct { __le16 MajorVersionNumber; __le16 MinorVersionNumber; __le64 Capability; -} __attribute__((packed)) FILE_SYSTEM_UNIX_INFO; /* Unix extension level 0x200*/ +} __packed FILE_SYSTEM_UNIX_INFO; /* Unix extension level 0x200*/ /* Version numbers for CIFS UNIX major and minor. */ #define CIFS_UNIX_MAJOR_VERSION 1 @@ -2102,7 +2102,7 @@ typedef struct { /* data block encoding of response to level 263 QPathInfo */ char __pad; DECLARE_FLEX_ARRAY(char, FileName); }; -} __attribute__((packed)) FILE_ALL_INFO; /* level 0x107 QPathInfo */ +} __packed FILE_ALL_INFO; /* level 0x107 QPathInfo */ typedef struct { __le64 AllocationSize; @@ -2111,7 +2111,7 @@ typedef struct { __u8 DeletePending; __u8 Directory; __u16 Pad; -} __attribute__((packed)) FILE_STANDARD_INFO; /* level 0x102 QPathInfo */ +} __packed FILE_STANDARD_INFO; /* level 0x102 QPathInfo */ /* defines for enumerating possible values of the Unix type field below */ @@ -2136,11 +2136,11 @@ typedef struct { __le64 UniqueId; __le64 Permissions; __le64 Nlinks; -} __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ +} __packed FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ typedef struct { DECLARE_FLEX_ARRAY(char, LinkDest); -} __attribute__((packed)) FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ +} __packed FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ /* The following three structures are needed only for setting time to NT4 and some older servers via @@ -2149,13 +2149,13 @@ typedef struct { __u16 Day:5; __u16 Month:4; __u16 Year:7; -} __attribute__((packed)) SMB_DATE; +} __packed SMB_DATE; typedef struct { __u16 TwoSeconds:5; __u16 Minutes:6; __u16 Hours:5; -} __attribute__((packed)) SMB_TIME; +} __packed SMB_TIME; typedef struct { __le16 CreationDate; /* SMB Date see above */ @@ -2168,7 +2168,7 @@ typedef struct { __le32 AllocationSize; __le16 Attributes; /* verify not u32 */ __le32 EASize; -} __attribute__((packed)) FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */ +} __packed FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */ typedef struct { __le64 CreationTime; @@ -2177,7 +2177,7 @@ typedef struct { __le64 ChangeTime; __le32 Attributes; __u32 Pad; -} __attribute__((packed)) FILE_BASIC_INFO; /* size info, level 0x101 */ +} __packed FILE_BASIC_INFO; /* size info, level 0x101 */ struct file_allocation_info { __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ @@ -2185,11 +2185,11 @@ struct file_allocation_info { struct file_end_of_file_info { __le64 FileSize; /* offset to end of file */ -} __attribute__((packed)); /* size info, level 0x104 for set, 0x106 for query */ +} __packed; /* size info, level 0x104 for set, 0x106 for query */ struct file_alt_name_info { DECLARE_FLEX_ARRAY(__u8, alt_name); -} __attribute__((packed)); /* level 0x0108 */ +} __packed; /* level 0x0108 */ struct file_stream_info { __le32 number_of_streams; /* BB check sizes and verify location */ @@ -2206,7 +2206,7 @@ struct file_compression_info { __u8 ch_shift; __u8 cl_shift; __u8 pad[3]; -} __attribute__((packed)); /* level 0x10b */ +} __packed; /* level 0x10b */ /* POSIX ACL set/query path info structures */ #define CIFS_ACL_VERSION 1 @@ -2214,7 +2214,7 @@ struct cifs_posix_ace { /* access control entry (ACE) */ __u8 cifs_e_tag; __u8 cifs_e_perm; __le64 cifs_uid; /* or gid */ -} __attribute__((packed)); +} __packed; struct cifs_posix_acl { /* access control list (ACL) */ __le16 version; @@ -2222,7 +2222,7 @@ struct cifs_posix_acl { /* access control list (ACL) */ __le16 default_entry_count; /* default ACL - count of entries */ struct cifs_posix_ace ace_array[]; /* followed by struct cifs_posix_ace default_ace_array[] */ -} __attribute__((packed)); /* level 0x204 */ +} __packed; /* level 0x204 */ /* types of access control entries already defined in posix_acl.h */ /* #define CIFS_POSIX_ACL_USER_OBJ 0x01 @@ -2257,7 +2257,7 @@ typedef struct { __le32 PosixOpenFlags; __le64 Permissions; __le16 Level; /* reply level requested (see QPathInfo levels) */ -} __attribute__((packed)) OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */ +} __packed OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */ typedef struct { __le16 OplockFlags; @@ -2266,27 +2266,27 @@ typedef struct { __le16 ReturnedLevel; __le16 Pad; /* struct following varies based on requested level */ -} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ +} __packed OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ #define SMB_POSIX_UNLINK_FILE_TARGET 0 #define SMB_POSIX_UNLINK_DIRECTORY_TARGET 1 struct unlink_psx_rq { /* level 0x20a SetPathInfo */ __le16 type; -} __attribute__((packed)); +} __packed; struct file_internal_info { __le64 UniqueId; /* inode number */ -} __attribute__((packed)); /* level 0x3ee */ +} __packed; /* level 0x3ee */ struct file_mode_info { __le32 Mode; -} __attribute__((packed)); /* level 0x3f8 */ +} __packed; /* level 0x3f8 */ struct file_attrib_tag { __le32 Attribute; __le32 ReparseTag; -} __attribute__((packed)); /* level 0x40b */ +} __packed; /* level 0x40b */ /********************************************************/ @@ -2301,7 +2301,7 @@ typedef struct { char __pad; DECLARE_FLEX_ARRAY(char, FileName); }; -} __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */ +} __packed FILE_UNIX_INFO; /* level 0x202 */ typedef struct { __u32 ResumeKey; @@ -2316,7 +2316,7 @@ typedef struct { __le16 Attributes; /* verify not u32 */ __u8 FileNameLength; char FileName[]; -} __attribute__((packed)) FIND_FILE_STANDARD_INFO; /* level 0x1 FF resp data */ +} __packed FIND_FILE_STANDARD_INFO; /* level 0x1 FF resp data */ struct fea { @@ -2325,21 +2325,21 @@ struct fea { __le16 value_len; char name[]; /* optionally followed by value */ -} __attribute__((packed)); +} __packed; /* flags for _FEA.fEA */ #define FEA_NEEDEA 0x80 /* need EA bit */ struct fealist { __le32 list_len; struct fea list; -} __attribute__((packed)); +} __packed; /* used to hold an arbitrary blob of data */ struct data_blob { __u8 *data; size_t length; void (*free) (struct data_blob *data_blob); -} __attribute__((packed)); +} __packed; #ifdef CONFIG_CIFS_POSIX @@ -2442,7 +2442,7 @@ struct xsymlink { char cr2; /* \n */ /* if room left, then end with \n then 0x20s by convention but not required */ char path[1024]; -} __attribute__((packed)); +} __packed; typedef struct file_xattr_info { /* BB do we need another field for flags? BB */ diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index ca4d6055d2f3..ab42235b2955 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -2312,8 +2312,8 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses) } #else /* ! CONFIG_KEYS */ static inline int -cifs_set_cifscreds(struct smb3_fs_context *ctx __attribute__((unused)), - struct cifs_ses *ses __attribute__((unused))) +cifs_set_cifscreds(struct smb3_fs_context *ctx __maybe_unused, + struct cifs_ses *ses __maybe_unused) { return -ENOSYS; } diff --git a/fs/smb/client/ntlmssp.h b/fs/smb/client/ntlmssp.h index 875de43b72de..a11fddc321f6 100644 --- a/fs/smb/client/ntlmssp.h +++ b/fs/smb/client/ntlmssp.h @@ -73,7 +73,7 @@ typedef struct _SECURITY_BUFFER { __le16 Length; __le16 MaximumLength; __le32 BufferOffset; /* offset to buffer */ -} __attribute__((packed)) SECURITY_BUFFER; +} __packed SECURITY_BUFFER; typedef struct _NEGOTIATE_MESSAGE { __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; @@ -85,7 +85,7 @@ typedef struct _NEGOTIATE_MESSAGE { do not set the version is present flag */ char DomainString[]; /* followed by WorkstationString */ -} __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; +} __packed NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; #define NTLMSSP_REVISION_W2K3 0x0F @@ -121,7 +121,7 @@ typedef struct _CHALLENGE_MESSAGE { SECURITY_BUFFER TargetInfoArray; /* SECURITY_BUFFER for version info not present since we do not set the version is present flag */ -} __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; +} __packed CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; typedef struct _AUTHENTICATE_MESSAGE { __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; @@ -136,7 +136,7 @@ typedef struct _AUTHENTICATE_MESSAGE { struct ntlmssp_version Version; /* SECURITY_BUFFER */ char UserString[]; -} __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; +} __packed AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; /* * Size of the session key (crypto key encrypted with the password diff --git a/fs/smb/client/rfc1002pdu.h b/fs/smb/client/rfc1002pdu.h index ac82c2f3a4a2..f5b143088b90 100644 --- a/fs/smb/client/rfc1002pdu.h +++ b/fs/smb/client/rfc1002pdu.h @@ -33,17 +33,17 @@ struct rfc1002_session_packet { __u8 calling_len; __u8 calling_name[32]; __u8 scope2; /* null */ - } __attribute__((packed)) session_req; + } __packed session_req; struct { __be32 retarget_ip_addr; __be16 port; - } __attribute__((packed)) retarget_resp; + } __packed retarget_resp; __u8 neg_ses_resp_error_code; /* POSITIVE_SESSION_RESPONSE packet does not include trailer. SESSION_KEEP_ALIVE packet also does not include a trailer. Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */ - } __attribute__((packed)) trailer; -} __attribute__((packed)); + } __packed trailer; +} __packed; /* Negative Session Response error codes */ #define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */ diff --git a/fs/smb/common/smbacl.h b/fs/smb/common/smbacl.h index a624ec9e4a14..70bba5ff7fc1 100644 --- a/fs/smb/common/smbacl.h +++ b/fs/smb/common/smbacl.h @@ -92,14 +92,14 @@ struct smb_ntsd { __le32 gsidoffset; __le32 sacloffset; __le32 dacloffset; -} __attribute__((packed)); +} __packed; struct smb_sid { __u8 revision; /* revision level */ __u8 num_subauth; __u8 authority[NUM_AUTHS]; __le32 sub_auth[SID_MAX_SUB_AUTHORITIES]; /* sub_auth[num_subauth] */ -} __attribute__((packed)); +} __packed; /* size of a struct smb_sid, sans sub_auth array */ #define CIFS_SID_BASE_SIZE (1 + 1 + NUM_AUTHS) @@ -109,7 +109,7 @@ struct smb_acl { __le16 size; __le16 num_aces; __le16 reserved; -} __attribute__((packed)); +} __packed; struct smb_ace { __u8 type; /* see above and MS-DTYP 2.4.4.1 */ @@ -117,6 +117,6 @@ struct smb_ace { __le16 size; __le32 access_req; struct smb_sid sid; /* ie UUID of user or group who gets these perms */ -} __attribute__((packed)); +} __packed; #endif /* _COMMON_SMBACL_H */ From 5003ad718af7705d6a519445a897843fac88167a Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Thu, 13 Nov 2025 21:32:51 +0800 Subject: [PATCH 30/44] smb: move create_durable_reconn to common/smb2pdu.h The fields in struct create_durable_reconn_req and struct create_durable are exactly the same, so remove create_durable_reconn_req from server, and use typedef to define both create_durable_req_t and create_durable_reconn_t for a single struct. Rename the following places: - struct create_durable -> create_durable_req_t - struct create_durable_reconn_req -> create_durable_reconn_t The documentation references are: - SMB2_CREATE_DURABLE_HANDLE_REQUEST in MS-SMB2 2.2.13.2.3 - SMB2_CREATE_DURABLE_HANDLE_RECONNECT in MS-SMB2 2.2.13.2.4 - SMB2_FILEID in MS-SMB2 2.2.14.1 Descriptions of the struct fields: - __u8 Reserved[16]: DurableRequest field of SMB2_CREATE_DURABLE_HANDLE_REQUEST. A 16-byte field that MUST be reserved. - __u64 PersistentFileId: Persistent field of 2.2.14.1 SMB2_FILEID - __u64 VolatileFileId: Volatile field of 2.2.14.1 SMB2_FILEID - struct Fid: Data field of SMB2_CREATE_DURABLE_HANDLE_RECONNECT. An SMB2_FILEID structure, as specified in section 2.2.14.1. Suggested-by: Namjae Jeon Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/smb2pdu.c | 23 +++++++++++------------ fs/smb/common/smb2pdu.h | 4 ++-- fs/smb/server/smb2pdu.c | 6 +++--- fs/smb/server/smb2pdu.h | 12 ------------ 4 files changed, 16 insertions(+), 29 deletions(-) diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 62ced22fc5a6..032b4b037f07 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2229,21 +2229,20 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) return rc; } - -static struct create_durable * +static create_durable_req_t * create_durable_buf(void) { - struct create_durable *buf; + create_durable_req_t *buf; - buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL); + buf = kzalloc(sizeof(create_durable_req_t), GFP_KERNEL); if (!buf) return NULL; buf->ccontext.DataOffset = cpu_to_le16(offsetof - (struct create_durable, Data)); + (create_durable_req_t, Data)); buf->ccontext.DataLength = cpu_to_le32(16); buf->ccontext.NameOffset = cpu_to_le16(offsetof - (struct create_durable, Name)); + (create_durable_req_t, Name)); buf->ccontext.NameLength = cpu_to_le16(4); /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DHnQ" */ buf->Name[0] = 'D'; @@ -2253,20 +2252,20 @@ create_durable_buf(void) return buf; } -static struct create_durable * +static create_durable_req_t * create_reconnect_durable_buf(struct cifs_fid *fid) { - struct create_durable *buf; + create_durable_req_t *buf; - buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL); + buf = kzalloc(sizeof(create_durable_req_t), GFP_KERNEL); if (!buf) return NULL; buf->ccontext.DataOffset = cpu_to_le16(offsetof - (struct create_durable, Data)); + (create_durable_req_t, Data)); buf->ccontext.DataLength = cpu_to_le32(16); buf->ccontext.NameOffset = cpu_to_le16(offsetof - (struct create_durable, Name)); + (create_durable_req_t, Name)); buf->ccontext.NameLength = cpu_to_le16(4); buf->Data.Fid.PersistentFileId = fid->persistent_fid; buf->Data.Fid.VolatileFileId = fid->volatile_fid; @@ -2552,7 +2551,7 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec, iov[num].iov_base = create_durable_buf(); if (iov[num].iov_base == NULL) return -ENOMEM; - iov[num].iov_len = sizeof(struct create_durable); + iov[num].iov_len = sizeof(create_durable_req_t); *num_iovec = num + 1; return 0; } diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h index 824d27297bec..f38c5739a9d2 100644 --- a/fs/smb/common/smb2pdu.h +++ b/fs/smb/common/smb2pdu.h @@ -1265,7 +1265,7 @@ struct create_posix { } __packed; /* See MS-SMB2 2.2.13.2.3 and MS-SMB2 2.2.13.2.4 */ -struct create_durable { +typedef struct { struct create_context_hdr ccontext; __u8 Name[8]; union { @@ -1275,7 +1275,7 @@ struct create_durable { __u64 VolatileFileId; } Fid; } Data; -} __packed; +} __packed create_durable_req_t, create_durable_reconn_t; /* See MS-SMB2 2.2.13.2.5 */ struct create_mxac_req { diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 8facd4ca69d0..c2369415c6c4 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2756,7 +2756,7 @@ static int parse_durable_handle_context(struct ksmbd_work *work, } case DURABLE_RECONN: { - struct create_durable_reconn_req *recon; + create_durable_reconn_t *recon; if (dh_info->type == DURABLE_RECONN_V2 || dh_info->type == DURABLE_REQ_V2) { @@ -2766,12 +2766,12 @@ static int parse_durable_handle_context(struct ksmbd_work *work, if (le16_to_cpu(context->DataOffset) + le32_to_cpu(context->DataLength) < - sizeof(struct create_durable_reconn_req)) { + sizeof(create_durable_reconn_t)) { err = -EINVAL; goto out; } - recon = (struct create_durable_reconn_req *)context; + recon = (create_durable_reconn_t *)context; persistent_id = recon->Data.Fid.PersistentFileId; dh_info->fp = ksmbd_lookup_durable_fd(persistent_id); if (!dh_info->fp) { diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h index b94de41049f4..66cdc8e4a648 100644 --- a/fs/smb/server/smb2pdu.h +++ b/fs/smb/server/smb2pdu.h @@ -68,18 +68,6 @@ struct preauth_integrity_info { #define DURABLE_HANDLE_MAX_TIMEOUT 300000 -struct create_durable_reconn_req { - struct create_context_hdr ccontext; - __u8 Name[8]; - union { - __u8 Reserved[16]; - struct { - __u64 PersistentFileId; - __u64 VolatileFileId; - } Fid; - } Data; -} __packed; - struct create_alloc_size_req { struct create_context_hdr ccontext; __u8 Name[8]; From 3316a8fc840d82fad5efcf76ad0ea3f76fdca209 Mon Sep 17 00:00:00 2001 From: Qingfang Deng Date: Mon, 17 Nov 2025 16:59:00 +0800 Subject: [PATCH 31/44] ksmbd: server: avoid busy polling in accept loop The ksmbd listener thread was using busy waiting on a listening socket by calling kernel_accept() with SOCK_NONBLOCK and retrying every 100ms on -EAGAIN. Since this thread is dedicated to accepting new connections, there is no need for non-blocking mode. Switch to a blocking accept() call instead, allowing the thread to sleep until a new connection arrives. This avoids unnecessary wakeups and CPU usage. During teardown, call shutdown() on the listening socket so that accept() returns -EINVAL and the thread exits cleanly. The socket release mutex is redundant because kthread_stop() blocks until the listener thread returns, guaranteeing safe teardown ordering. Also remove sk_rcvtimeo and sk_sndtimeo assignments, which only caused accept() to return -EAGAIN prematurely. Signed-off-by: Qingfang Deng Reviewed-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_tcp.c | 41 +++++------------------------------ 1 file changed, 6 insertions(+), 35 deletions(-) diff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c index d2e391c29464..fb38b7b2bd18 100644 --- a/fs/smb/server/transport_tcp.c +++ b/fs/smb/server/transport_tcp.c @@ -22,7 +22,6 @@ struct interface { struct socket *ksmbd_socket; struct list_head entry; char *name; - struct mutex sock_release_lock; int state; }; @@ -56,19 +55,6 @@ static inline void ksmbd_tcp_reuseaddr(struct socket *sock) sock_set_reuseaddr(sock->sk); } -static inline void ksmbd_tcp_rcv_timeout(struct socket *sock, s64 secs) -{ - if (secs && secs < MAX_SCHEDULE_TIMEOUT / HZ - 1) - WRITE_ONCE(sock->sk->sk_rcvtimeo, secs * HZ); - else - WRITE_ONCE(sock->sk->sk_rcvtimeo, MAX_SCHEDULE_TIMEOUT); -} - -static inline void ksmbd_tcp_snd_timeout(struct socket *sock, s64 secs) -{ - sock_set_sndtimeo(sock->sk, secs); -} - static struct tcp_transport *alloc_transport(struct socket *client_sk) { struct tcp_transport *t; @@ -236,20 +222,14 @@ static int ksmbd_kthread_fn(void *p) unsigned int max_ip_conns; while (!kthread_should_stop()) { - mutex_lock(&iface->sock_release_lock); if (!iface->ksmbd_socket) { - mutex_unlock(&iface->sock_release_lock); break; } - ret = kernel_accept(iface->ksmbd_socket, &client_sk, - SOCK_NONBLOCK); - mutex_unlock(&iface->sock_release_lock); - if (ret) { - if (ret == -EAGAIN) - /* check for new connections every 100 msecs */ - schedule_timeout_interruptible(HZ / 10); + ret = kernel_accept(iface->ksmbd_socket, &client_sk, 0); + if (ret == -EINVAL) + break; + if (ret) continue; - } if (!server_conf.max_ip_connections) goto skip_max_ip_conns_limit; @@ -458,10 +438,6 @@ static void tcp_destroy_socket(struct socket *ksmbd_socket) if (!ksmbd_socket) return; - /* set zero to timeout */ - ksmbd_tcp_rcv_timeout(ksmbd_socket, 0); - ksmbd_tcp_snd_timeout(ksmbd_socket, 0); - ret = kernel_sock_shutdown(ksmbd_socket, SHUT_RDWR); if (ret) pr_err("Failed to shutdown socket: %d\n", ret); @@ -532,9 +508,6 @@ static int create_socket(struct interface *iface) goto out_error; } - ksmbd_socket->sk->sk_rcvtimeo = KSMBD_TCP_RECV_TIMEOUT; - ksmbd_socket->sk->sk_sndtimeo = KSMBD_TCP_SEND_TIMEOUT; - ret = kernel_listen(ksmbd_socket, KSMBD_SOCKET_BACKLOG); if (ret) { pr_err("Port listen() error: %d\n", ret); @@ -604,12 +577,11 @@ static int ksmbd_netdev_event(struct notifier_block *nb, unsigned long event, if (iface && iface->state == IFACE_STATE_CONFIGURED) { ksmbd_debug(CONN, "netdev-down event: netdev(%s) is going down\n", iface->name); + kernel_sock_shutdown(iface->ksmbd_socket, SHUT_RDWR); tcp_stop_kthread(iface->ksmbd_kthread); iface->ksmbd_kthread = NULL; - mutex_lock(&iface->sock_release_lock); - tcp_destroy_socket(iface->ksmbd_socket); + sock_release(iface->ksmbd_socket); iface->ksmbd_socket = NULL; - mutex_unlock(&iface->sock_release_lock); iface->state = IFACE_STATE_DOWN; break; @@ -672,7 +644,6 @@ static struct interface *alloc_iface(char *ifname) iface->name = ifname; iface->state = IFACE_STATE_DOWN; list_add(&iface->entry, &iface_list); - mutex_init(&iface->sock_release_lock); return iface; } From b39a1833cc4a2755b02603eec3a71a85e9dff926 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Tue, 18 Nov 2025 09:05:46 +0900 Subject: [PATCH 32/44] ksmbd: fix use-after-free in ksmbd_tree_connect_put under concurrency Under high concurrency, A tree-connection object (tcon) is freed on a disconnect path while another path still holds a reference and later executes *_put()/write on it. Reported-by: Qianchang Zhao Reported-by: Zhitong Liu Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/mgmt/tree_connect.c | 18 ++++-------------- fs/smb/server/mgmt/tree_connect.h | 1 - fs/smb/server/smb2pdu.c | 3 --- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/fs/smb/server/mgmt/tree_connect.c b/fs/smb/server/mgmt/tree_connect.c index ecfc57508671..d3483d9c757c 100644 --- a/fs/smb/server/mgmt/tree_connect.c +++ b/fs/smb/server/mgmt/tree_connect.c @@ -78,7 +78,6 @@ ksmbd_tree_conn_connect(struct ksmbd_work *work, const char *share_name) tree_conn->t_state = TREE_NEW; status.tree_conn = tree_conn; atomic_set(&tree_conn->refcount, 1); - init_waitqueue_head(&tree_conn->refcount_q); ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn, KSMBD_DEFAULT_GFP)); @@ -100,14 +99,8 @@ ksmbd_tree_conn_connect(struct ksmbd_work *work, const char *share_name) void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon) { - /* - * Checking waitqueue to releasing tree connect on - * tree disconnect. waitqueue_active is safe because it - * uses atomic operation for condition. - */ - if (!atomic_dec_return(&tcon->refcount) && - waitqueue_active(&tcon->refcount_q)) - wake_up(&tcon->refcount_q); + if (atomic_dec_and_test(&tcon->refcount)) + kfree(tcon); } int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, @@ -119,14 +112,11 @@ int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, xa_erase(&sess->tree_conns, tree_conn->id); write_unlock(&sess->tree_conns_lock); - if (!atomic_dec_and_test(&tree_conn->refcount)) - wait_event(tree_conn->refcount_q, - atomic_read(&tree_conn->refcount) == 0); - ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id); ksmbd_release_tree_conn_id(sess, tree_conn->id); ksmbd_share_config_put(tree_conn->share_conf); - kfree(tree_conn); + if (atomic_dec_and_test(&tree_conn->refcount)) + kfree(tree_conn); return ret; } diff --git a/fs/smb/server/mgmt/tree_connect.h b/fs/smb/server/mgmt/tree_connect.h index a42cdd051041..f0023d86716f 100644 --- a/fs/smb/server/mgmt/tree_connect.h +++ b/fs/smb/server/mgmt/tree_connect.h @@ -33,7 +33,6 @@ struct ksmbd_tree_connect { int maximal_access; bool posix_extensions; atomic_t refcount; - wait_queue_head_t refcount_q; unsigned int t_state; }; diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index c2369415c6c4..c3eedc70e643 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2190,7 +2190,6 @@ int smb2_tree_disconnect(struct ksmbd_work *work) goto err_out; } - WARN_ON_ONCE(atomic_dec_and_test(&tcon->refcount)); tcon->t_state = TREE_DISCONNECTED; write_unlock(&sess->tree_conns_lock); @@ -2200,8 +2199,6 @@ int smb2_tree_disconnect(struct ksmbd_work *work) goto err_out; } - work->tcon = NULL; - rsp->StructureSize = cpu_to_le16(4); err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_tree_disconnect_rsp)); From e4442b2e95baf0901830c924d0a197b100aca970 Mon Sep 17 00:00:00 2001 From: Aaditya Kansal Date: Tue, 18 Nov 2025 00:20:31 +0530 Subject: [PATCH 33/44] ksmbd: implement error handling for STATUS_INFO_LENGTH_MISMATCH in smb server Add STATUS_INFO_LENGTH_MISMATCH mapping to EMSGSIZE. Currently, STATUS_INFO_LENGTH_MISMATCH has no mapping to any error code, making it difficult to distinguish between invalid parameters and length mismatch. Map STATUS_INFO_LENGTH_MISMATCH to EMSGSIZE while keeping the EINVAL for invalid parameters. Although the buf_len check only checks for buf_size being less than required, there was no error code for lower buf_size. Hence, EMSGSIZE is used. Signed-off-by: Aaditya Kansal Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index c3eedc70e643..11d3fab9bde3 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -6383,7 +6383,6 @@ static int set_file_mode_info(struct ksmbd_file *fp, * @share: ksmbd_share_config pointer * * Return: 0 on success, otherwise error - * TODO: need to implement an error handling for STATUS_INFO_LENGTH_MISMATCH */ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, struct smb2_set_info_req *req, @@ -6396,14 +6395,14 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, case FILE_BASIC_INFORMATION: { if (buf_len < sizeof(struct smb2_file_basic_info)) - return -EINVAL; + return -EMSGSIZE; return set_file_basic_info(fp, (struct smb2_file_basic_info *)buffer, share); } case FILE_ALLOCATION_INFORMATION: { if (buf_len < sizeof(struct smb2_file_alloc_info)) - return -EINVAL; + return -EMSGSIZE; return set_file_allocation_info(work, fp, (struct smb2_file_alloc_info *)buffer); @@ -6411,7 +6410,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, case FILE_END_OF_FILE_INFORMATION: { if (buf_len < sizeof(struct smb2_file_eof_info)) - return -EINVAL; + return -EMSGSIZE; return set_end_of_file_info(work, fp, (struct smb2_file_eof_info *)buffer); @@ -6419,7 +6418,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, case FILE_RENAME_INFORMATION: { if (buf_len < sizeof(struct smb2_file_rename_info)) - return -EINVAL; + return -EMSGSIZE; return set_rename_info(work, fp, (struct smb2_file_rename_info *)buffer, @@ -6428,7 +6427,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, case FILE_LINK_INFORMATION: { if (buf_len < sizeof(struct smb2_file_link_info)) - return -EINVAL; + return -EMSGSIZE; return smb2_create_link(work, work->tcon->share_conf, (struct smb2_file_link_info *)buffer, @@ -6438,7 +6437,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, case FILE_DISPOSITION_INFORMATION: { if (buf_len < sizeof(struct smb2_file_disposition_info)) - return -EINVAL; + return -EMSGSIZE; return set_file_disposition_info(fp, (struct smb2_file_disposition_info *)buffer); @@ -6452,7 +6451,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, } if (buf_len < sizeof(struct smb2_ea_info)) - return -EINVAL; + return -EMSGSIZE; return smb2_set_ea((struct smb2_ea_info *)buffer, buf_len, &fp->filp->f_path, true); @@ -6460,14 +6459,14 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, case FILE_POSITION_INFORMATION: { if (buf_len < sizeof(struct smb2_file_pos_info)) - return -EINVAL; + return -EMSGSIZE; return set_file_position_info(fp, (struct smb2_file_pos_info *)buffer); } case FILE_MODE_INFORMATION: { if (buf_len < sizeof(struct smb2_file_mode_info)) - return -EINVAL; + return -EMSGSIZE; return set_file_mode_info(fp, (struct smb2_file_mode_info *)buffer); } @@ -6574,6 +6573,8 @@ int smb2_set_info(struct ksmbd_work *work) rsp->hdr.Status = STATUS_ACCESS_DENIED; else if (rc == -EINVAL) rsp->hdr.Status = STATUS_INVALID_PARAMETER; + else if (rc == -EMSGSIZE) + rsp->hdr.Status = STATUS_INFO_LENGTH_MISMATCH; else if (rc == -ESHARE) rsp->hdr.Status = STATUS_SHARING_VIOLATION; else if (rc == -ENOENT) From c4a2a49f7df48147529158a092edfde1597d12f3 Mon Sep 17 00:00:00 2001 From: ChenXiaoSong Date: Mon, 17 Nov 2025 19:28:38 +0800 Subject: [PATCH 34/44] smb: move FILE_SYSTEM_ATTRIBUTE_INFO to common/fscc.h Modify the following places: - struct filesystem_attribute_info -> FILE_SYSTEM_ATTRIBUTE_INFO - Remove MIN_FS_ATTR_INFO_SIZE definition - Introduce MAX_FS_NAME_LEN - max_len of FileFsAttributeInformation -> sizeof(FILE_SYSTEM_ATTRIBUTE_INFO) + MAX_FS_NAME_LEN - min_len of FileFsAttributeInformation -> sizeof(FILE_SYSTEM_ATTRIBUTE_INFO) - SMB2_QFS_attr(): memcpy(..., min_len) Then move FILE_SYSTEM_ATTRIBUTE_INFO to common header file. I have tested the relevant code related to FILE_SYSTEM_ATTRIBUTE_INFO (Link[1]). Link[1]: https://chenxiaosong.com/en/FILE_SYSTEM_ATTRIBUTE_INFO.html Suggested-by: Namjae Jeon Tested-by: ChenXiaoSong Signed-off-by: ChenXiaoSong Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/cifspdu.h | 10 ---------- fs/smb/client/smb2pdu.c | 6 +++--- fs/smb/common/fscc.h | 9 +++++++++ fs/smb/server/smb2pdu.c | 6 +++--- fs/smb/server/smb_common.h | 7 ------- 5 files changed, 15 insertions(+), 23 deletions(-) diff --git a/fs/smb/client/cifspdu.h b/fs/smb/client/cifspdu.h index d84e10b1477f..49f35cb3cf2e 100644 --- a/fs/smb/client/cifspdu.h +++ b/fs/smb/client/cifspdu.h @@ -2068,16 +2068,6 @@ typedef struct { #define FILE_PORTABLE_DEVICE 0x00004000 #define FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL 0x00020000 -/* minimum includes first three fields, and empty FS Name */ -#define MIN_FS_ATTR_INFO_SIZE 12 - -typedef struct { - __le32 Attributes; - __le32 MaxPathNameComponentLength; - __le32 FileSystemNameLen; - char FileSystemName[52]; /* do not have to save this - get subset? */ -} __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO; - /******************************************************************************/ /* QueryFileInfo/QueryPathinfo (also for SetPath/SetFile) data buffer formats */ /******************************************************************************/ diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 032b4b037f07..ef2c6ac500f7 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -5981,8 +5981,8 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, max_len = sizeof(FILE_SYSTEM_DEVICE_INFO); min_len = sizeof(FILE_SYSTEM_DEVICE_INFO); } else if (level == FS_ATTRIBUTE_INFORMATION) { - max_len = sizeof(FILE_SYSTEM_ATTRIBUTE_INFO); - min_len = MIN_FS_ATTR_INFO_SIZE; + max_len = sizeof(FILE_SYSTEM_ATTRIBUTE_INFO) + MAX_FS_NAME_LEN; + min_len = sizeof(FILE_SYSTEM_ATTRIBUTE_INFO); } else if (level == FS_SECTOR_SIZE_INFORMATION) { max_len = sizeof(struct smb3_fs_ss_info); min_len = sizeof(struct smb3_fs_ss_info); @@ -6028,7 +6028,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, if (level == FS_ATTRIBUTE_INFORMATION) memcpy(&tcon->fsAttrInfo, offset + (char *)rsp, min_t(unsigned int, - rsp_len, max_len)); + rsp_len, min_len)); else if (level == FS_DEVICE_INFORMATION) memcpy(&tcon->fsDevInfo, offset + (char *)rsp, sizeof(FILE_SYSTEM_DEVICE_INFO)); diff --git a/fs/smb/common/fscc.h b/fs/smb/common/fscc.h index a0580a772a41..35dbacdbb902 100644 --- a/fs/smb/common/fscc.h +++ b/fs/smb/common/fscc.h @@ -94,6 +94,15 @@ 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.5.1 */ +#define MAX_FS_NAME_LEN 52 +typedef struct { + __le32 Attributes; + __le32 MaxPathNameComponentLength; + __le32 FileSystemNameLen; + __le16 FileSystemName[]; /* do not have to save this - get subset? */ +} __packed FILE_SYSTEM_ATTRIBUTE_INFO; + /* List of FileSystemAttributes - see MS-FSCC 2.5.1 */ #define FILE_SUPPORTS_SPARSE_VDL 0x10000000 /* faster nonsparse extend */ #define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000 /* allow ioctl dup extents */ diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 11d3fab9bde3..b638d7fb5f51 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -5479,10 +5479,10 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, } case FS_ATTRIBUTE_INFORMATION: { - struct filesystem_attribute_info *info; + FILE_SYSTEM_ATTRIBUTE_INFO *info; size_t sz; - info = (struct filesystem_attribute_info *)rsp->Buffer; + info = (FILE_SYSTEM_ATTRIBUTE_INFO *)rsp->Buffer; info->Attributes = cpu_to_le32(FILE_SUPPORTS_OBJECT_IDS | FILE_PERSISTENT_ACLS | FILE_UNICODE_ON_DISK | @@ -5501,7 +5501,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, "NTFS", PATH_MAX, conn->local_nls, 0); len = len * 2; info->FileSystemNameLen = cpu_to_le32(len); - sz = sizeof(struct filesystem_attribute_info) + len; + sz = sizeof(FILE_SYSTEM_ATTRIBUTE_INFO) + len; rsp->OutputBufferLength = cpu_to_le32(sz); break; } diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h index a91717da3895..2baf4aa330eb 100644 --- a/fs/smb/server/smb_common.h +++ b/fs/smb/server/smb_common.h @@ -90,13 +90,6 @@ struct smb_negotiate_rsp { __le16 ByteCount; } __packed; -struct filesystem_attribute_info { - __le32 Attributes; - __le32 MaxPathNameComponentLength; - __le32 FileSystemNameLen; - __le16 FileSystemName[]; /* do not have to save this - get subset? */ -} __packed; - struct filesystem_vol_info { __le64 VolumeCreationTime; __le32 SerialNumber; From dc81b8f4f0fc9e1be0c9ce8a918503e175b2c9b2 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Wed, 19 Nov 2025 14:02:30 +0100 Subject: [PATCH 35/44] ksmbd: Replace strcpy + strcat to improve convert_to_nt_pathname strcpy() is deprecated [1] and using strcat() is discouraged. Replace them by assigning the prefix directly and by using memcpy() to copy the pathname. Using memcpy() is safe because we already know the length of the source string and that it is guaranteed to be NUL-terminated. Allocate only as many bytes as needed and replace kzalloc() with kmalloc() since memcpy() overwrites the entire buffer anyway. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strcpy [1] Signed-off-by: Thorsten Blum Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/misc.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/fs/smb/server/misc.c b/fs/smb/server/misc.c index cb2a11ffb23f..a543ec9d3581 100644 --- a/fs/smb/server/misc.c +++ b/fs/smb/server/misc.c @@ -164,6 +164,8 @@ char *convert_to_nt_pathname(struct ksmbd_share_config *share, { char *pathname, *ab_pathname, *nt_pathname; int share_path_len = share->path_sz; + size_t ab_pathname_len; + int prefix; pathname = kmalloc(PATH_MAX, KSMBD_DEFAULT_GFP); if (!pathname) @@ -180,15 +182,18 @@ char *convert_to_nt_pathname(struct ksmbd_share_config *share, goto free_pathname; } - nt_pathname = kzalloc(strlen(&ab_pathname[share_path_len]) + 2, - KSMBD_DEFAULT_GFP); + ab_pathname_len = strlen(&ab_pathname[share_path_len]); + prefix = ab_pathname[share_path_len] == '\0' ? 1 : 0; + nt_pathname = kmalloc(prefix + ab_pathname_len + 1, KSMBD_DEFAULT_GFP); if (!nt_pathname) { nt_pathname = ERR_PTR(-ENOMEM); goto free_pathname; } - if (ab_pathname[share_path_len] == '\0') - strcpy(nt_pathname, "/"); - strcat(nt_pathname, &ab_pathname[share_path_len]); + + if (prefix) + *nt_pathname = '/'; + memcpy(nt_pathname + prefix, &ab_pathname[share_path_len], + ab_pathname_len + 1); ksmbd_conv_path_to_windows(nt_pathname); From 991f8a79db99b14c48d20d2052c82d65b9186cad Mon Sep 17 00:00:00 2001 From: Qianchang Zhao Date: Mon, 24 Nov 2025 16:05:09 +0900 Subject: [PATCH 36/44] ksmbd: vfs: fix race on m_flags in vfs_cache ksmbd maintains delete-on-close and pending-delete state in ksmbd_inode->m_flags. In vfs_cache.c this field is accessed under inconsistent locking: some paths read and modify m_flags under ci->m_lock while others do so without taking the lock at all. Examples: - ksmbd_query_inode_status() and __ksmbd_inode_close() use ci->m_lock when checking or updating m_flags. - ksmbd_inode_pending_delete(), ksmbd_set_inode_pending_delete(), ksmbd_clear_inode_pending_delete() and ksmbd_fd_set_delete_on_close() used to read and modify m_flags without ci->m_lock. This creates a potential data race on m_flags when multiple threads open, close and delete the same file concurrently. In the worst case delete-on-close and pending-delete bits can be lost or observed in an inconsistent state, leading to confusing delete semantics (files that stay on disk after delete-on-close, or files that disappear while still in use). Fix it by: - Making ksmbd_query_inode_status() look at m_flags under ci->m_lock after dropping inode_hash_lock. - Adding ci->m_lock protection to all helpers that read or modify m_flags (ksmbd_inode_pending_delete(), ksmbd_set_inode_pending_delete(), ksmbd_clear_inode_pending_delete(), ksmbd_fd_set_delete_on_close()). - Keeping the existing ci->m_lock protection in __ksmbd_inode_close(), and moving the actual unlink/xattr removal outside the lock. This unifies the locking around m_flags and removes the data race while preserving the existing delete-on-close behaviour. Reported-by: Qianchang Zhao Reported-by: Zhitong Liu Signed-off-by: Qianchang Zhao Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/vfs_cache.c | 88 +++++++++++++++++++++++++++------------ 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c index dfed6fce8904..6ef116585af6 100644 --- a/fs/smb/server/vfs_cache.c +++ b/fs/smb/server/vfs_cache.c @@ -112,40 +112,62 @@ int ksmbd_query_inode_status(struct dentry *dentry) read_lock(&inode_hash_lock); ci = __ksmbd_inode_lookup(dentry); - if (ci) { - ret = KSMBD_INODE_STATUS_OK; - if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS)) - ret = KSMBD_INODE_STATUS_PENDING_DELETE; - atomic_dec(&ci->m_count); - } read_unlock(&inode_hash_lock); + if (!ci) + return ret; + + down_read(&ci->m_lock); + if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS)) + ret = KSMBD_INODE_STATUS_PENDING_DELETE; + else + ret = KSMBD_INODE_STATUS_OK; + up_read(&ci->m_lock); + + atomic_dec(&ci->m_count); return ret; } bool ksmbd_inode_pending_delete(struct ksmbd_file *fp) { - return (fp->f_ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS)); + struct ksmbd_inode *ci = fp->f_ci; + int ret; + + down_read(&ci->m_lock); + ret = (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS)); + up_read(&ci->m_lock); + + return ret; } void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp) { - fp->f_ci->m_flags |= S_DEL_PENDING; + struct ksmbd_inode *ci = fp->f_ci; + + down_write(&ci->m_lock); + ci->m_flags |= S_DEL_PENDING; + up_write(&ci->m_lock); } void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp) { - fp->f_ci->m_flags &= ~S_DEL_PENDING; + struct ksmbd_inode *ci = fp->f_ci; + + down_write(&ci->m_lock); + ci->m_flags &= ~S_DEL_PENDING; + up_write(&ci->m_lock); } void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp, int file_info) { - if (ksmbd_stream_fd(fp)) { - fp->f_ci->m_flags |= S_DEL_ON_CLS_STREAM; - return; - } + struct ksmbd_inode *ci = fp->f_ci; - fp->f_ci->m_flags |= S_DEL_ON_CLS; + down_write(&ci->m_lock); + if (ksmbd_stream_fd(fp)) + ci->m_flags |= S_DEL_ON_CLS_STREAM; + else + ci->m_flags |= S_DEL_ON_CLS; + up_write(&ci->m_lock); } static void ksmbd_inode_hash(struct ksmbd_inode *ci) @@ -257,27 +279,41 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp) struct file *filp; filp = fp->filp; - if (ksmbd_stream_fd(fp) && (ci->m_flags & S_DEL_ON_CLS_STREAM)) { - ci->m_flags &= ~S_DEL_ON_CLS_STREAM; - err = ksmbd_vfs_remove_xattr(file_mnt_idmap(filp), - &filp->f_path, - fp->stream.name, - true); - if (err) - pr_err("remove xattr failed : %s\n", - fp->stream.name); + + if (ksmbd_stream_fd(fp)) { + bool remove_stream_xattr = false; + + down_write(&ci->m_lock); + if (ci->m_flags & S_DEL_ON_CLS_STREAM) { + ci->m_flags &= ~S_DEL_ON_CLS_STREAM; + remove_stream_xattr = true; + } + up_write(&ci->m_lock); + + if (remove_stream_xattr) { + err = ksmbd_vfs_remove_xattr(file_mnt_idmap(filp), + &filp->f_path, + fp->stream.name, + true); + if (err) + pr_err("remove xattr failed : %s\n", + fp->stream.name); + } } if (atomic_dec_and_test(&ci->m_count)) { + bool do_unlink = false; + down_write(&ci->m_lock); if (ci->m_flags & (S_DEL_ON_CLS | S_DEL_PENDING)) { ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING); - up_write(&ci->m_lock); - ksmbd_vfs_unlink(filp); - down_write(&ci->m_lock); + do_unlink = true; } up_write(&ci->m_lock); + if (do_unlink) + ksmbd_vfs_unlink(filp); + ksmbd_inode_free(ci); } } From 1f3fd108c5c5a9885c6c276a2489c49b60a6b90d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 25 Nov 2025 09:55:54 +0100 Subject: [PATCH 37/44] smb: smbdirect: introduce SMBDIRECT_DEBUG_ERR_PTR() helper This can be used like this: int err = somefunc(); pr_warn("err=%1pe\n", SMBDIRECT_DEBUG_ERR_PTR(err)); This will be used in the following fixes in order to be prepared to identify real world problems more easily. Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: Namjae Jeon Cc: Paulo Alcantara Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index ee5a90d691c8..611986827a5e 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -74,6 +74,19 @@ const char *smbdirect_socket_status_string(enum smbdirect_socket_status status) return ""; } +/* + * This can be used with %1pe to print errors as strings or '0' + * And it avoids warnings like: warn: passing zero to 'ERR_PTR' + * from smatch -p=kernel --pedantic + */ +static __always_inline +const void * __must_check SMBDIRECT_DEBUG_ERR_PTR(long error) +{ + if (error == 0) + return NULL; + return ERR_PTR(error); +} + enum smbdirect_keepalive_status { SMBDIRECT_KEEPALIVE_NONE, SMBDIRECT_KEEPALIVE_PENDING, From 1adb2dab9727c5beaaf253f67bf4fc2c54ae70e7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 25 Nov 2025 09:55:55 +0100 Subject: [PATCH 38/44] smb: smbdirect: introduce SMBDIRECT_CHECK_STATUS_{WARN,DISCONNECT}() These will be used in various places in order to assert the current status mostly during the connect and negotiation phase. It will replace the WARN_ON_ONCE(sc->status != ...) calls, which are very useless in order to identify the problem that happened. As a start client and server will need to define their own __SMBDIRECT_SOCKET_DISCONNECT(__sc) macro in order to use SMBDIRECT_CHECK_STATUS_DISCONNECT(). Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: Namjae Jeon Cc: Paulo Alcantara Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/common/smbdirect/smbdirect_socket.h | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/fs/smb/common/smbdirect/smbdirect_socket.h b/fs/smb/common/smbdirect/smbdirect_socket.h index 611986827a5e..384b19177e1c 100644 --- a/fs/smb/common/smbdirect/smbdirect_socket.h +++ b/fs/smb/common/smbdirect/smbdirect_socket.h @@ -394,6 +394,44 @@ static __always_inline void smbdirect_socket_init(struct smbdirect_socket *sc) init_waitqueue_head(&sc->mr_io.cleanup.wait_queue); } +#define __SMBDIRECT_CHECK_STATUS_FAILED(__sc, __expected_status, __error_cmd, __unexpected_cmd) ({ \ + bool __failed = false; \ + if (unlikely((__sc)->first_error)) { \ + __failed = true; \ + __error_cmd \ + } else if (unlikely((__sc)->status != (__expected_status))) { \ + __failed = true; \ + __unexpected_cmd \ + } \ + __failed; \ +}) + +#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; \ + if ((__sc)->rdma.cm_id) { \ + __src = &(__sc)->rdma.cm_id->route.addr.src_addr; \ + __dst = &(__sc)->rdma.cm_id->route.addr.dst_addr; \ + } \ + WARN_ONCE(1, \ + "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); \ + __unexpected_cmd \ + }) + +#define SMBDIRECT_CHECK_STATUS_WARN(__sc, __expected_status) \ + __SMBDIRECT_CHECK_STATUS_WARN(__sc, __expected_status, /* nothing */) + +#define SMBDIRECT_CHECK_STATUS_DISCONNECT(__sc, __expected_status) \ + __SMBDIRECT_CHECK_STATUS_WARN(__sc, __expected_status, \ + __SMBDIRECT_SOCKET_DISCONNECT(__sc);) + struct smbdirect_send_io { struct smbdirect_socket *socket; struct ib_cqe cqe; From 425c32750b48956a6e156b6a4609d281ee471359 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 25 Nov 2025 15:21:53 +0100 Subject: [PATCH 39/44] smb: server: relax WARN_ON_ONCE(SMBDIRECT_SOCKET_*) checks in recv_done() and smb_direct_cm_handler() Namjae reported the following: I have a simple file copy test with windows 11 client, and get the following error message. [ 894.140312] ------------[ cut here ]------------ [ 894.140316] WARNING: CPU: 1 PID: 116 at fs/smb/server/transport_rdma.c:642 recv_done+0x308/0x360 [ksmbd] [ 894.140335] Modules linked in: ksmbd cmac nls_utf8 nls_ucs2_utils libarc4 nls_iso8859_1 snd_hda_codec_intelhdmi snd_hda_codec_hdmi snd_hda_codec_alc882 snd_hda_codec_realtek_lib snd_hda_codec_generic rpcrdma intel_rapl_msr rdma_ucm intel_rapl_common snd_hda_intel ib_iser snd_hda_codec intel_uncore_frequency intel_uncore_frequency_common snd_hda_core intel_tcc_cooling x86_pkg_temp_thermal intel_powerclamp snd_intel_dspcfg libiscsi snd_intel_sdw_acpi coretemp scsi_transport_iscsi snd_hwdep kvm_intel i915 snd_pcm ib_umad rdma_cm snd_seq_midi ib_ipoib kvm snd_seq_midi_event iw_cm snd_rawmidi ghash_clmulni_intel ib_cm aesni_intel snd_seq mei_hdcp drm_buddy rapl snd_seq_device eeepc_wmi asus_wmi snd_timer intel_cstate ttm snd drm_client_lib drm_display_helper sparse_keymap soundcore platform_profile mxm_wmi wmi_bmof joydev mei_me cec acpi_pad mei rc_core drm_kms_helper input_leds i2c_algo_bit mac_hid sch_fq_codel msr parport_pc ppdev lp nfsd parport auth_rpcgss binfmt_misc nfs_acl lockd grace drm sunrpc ramoops efi_pstore [ 894.140414] reed_solomon pstore_blk pstore_zone autofs4 btrfs blake2b_generic xor raid6_pq mlx5_ib ib_uverbs ib_core hid_generic uas usbhid hid r8169 i2c_i801 usb_storage i2c_mux i2c_smbus mlx5_core realtek ahci mlxfw psample libahci video wmi [last unloaded: ksmbd] [ 894.140442] CPU: 1 UID: 0 PID: 116 Comm: kworker/1:1H Tainted: G W 6.18.0-rc5+ #1 PREEMPT(voluntary) [ 894.140447] Tainted: [W]=WARN [ 894.140448] Hardware name: System manufacturer System Product Name/H110M-K, BIOS 3601 12/12/2017 [ 894.140450] Workqueue: ib-comp-wq ib_cq_poll_work [ib_core] [ 894.140476] RIP: 0010:recv_done+0x308/0x360 [ksmbd] [ 894.140487] Code: 2e f2 ff ff 5b 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc 41 8b 55 10 49 8b 75 08 b9 02 00 00 00 e8 ed f4 f2 c3 e9 59 fd ff ff <0f> 0b e9 02 ff ff ff 49 8b 74 24 28 49 8d 94 24 c8 00 00 00 bf 00 [ 894.140490] RSP: 0018:ffffa47ec03f3d78 EFLAGS: 00010293 [ 894.140492] RAX: 0000000000000001 RBX: ffff8eb84c818000 RCX: 000000010002ba00 [ 894.140494] RDX: 0000000037600001 RSI: 0000000000000083 RDI: ffff8eb92ec9ee40 [ 894.140496] RBP: ffffa47ec03f3da0 R08: 0000000000000000 R09: 0000000000000010 [ 894.140498] R10: ffff8eb801705680 R11: fefefefefefefeff R12: ffff8eb7454b8810 [ 894.140499] R13: ffff8eb746deb988 R14: ffff8eb746deb980 R15: ffff8eb84c818000 [ 894.140501] FS: 0000000000000000(0000) GS:ffff8eb9a7355000(0000) knlGS:0000000000000000 [ 894.140503] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 894.140505] CR2: 00002d9401d60018 CR3: 0000000010a40006 CR4: 00000000003726f0 [ 894.140507] Call Trace: [ 894.140509] [ 894.140512] __ib_process_cq+0x8e/0x190 [ib_core] [ 894.140530] ib_cq_poll_work+0x2f/0x90 [ib_core] [ 894.140545] process_scheduled_works+0xd4/0x430 [ 894.140554] worker_thread+0x12a/0x270 [ 894.140558] kthread+0x10d/0x250 [ 894.140564] ? __pfx_worker_thread+0x10/0x10 [ 894.140567] ? __pfx_kthread+0x10/0x10 [ 894.140571] ret_from_fork+0x11a/0x160 [ 894.140574] ? __pfx_kthread+0x10/0x10 [ 894.140577] ret_from_fork_asm+0x1a/0x30 [ 894.140584] [ 894.140585] ---[ end trace 0000000000000000 ]--- [ 894.154363] ------------[ cut here ]------------ [ 894.154367] WARNING: CPU: 3 PID: 5543 at fs/smb/server/transport_rdma.c:1728 smb_direct_cm_handler+0x121/0x130 [ksmbd] [ 894.154384] Modules linked in: ksmbd cmac nls_utf8 nls_ucs2_utils libarc4 nls_iso8859_1 snd_hda_codec_intelhdmi snd_hda_codec_hdmi snd_hda_codec_alc882 snd_hda_codec_realtek_lib snd_hda_codec_generic rpcrdma intel_rapl_msr rdma_ucm intel_rapl_common snd_hda_intel ib_iser snd_hda_codec intel_uncore_frequency intel_uncore_frequency_common snd_hda_core intel_tcc_cooling x86_pkg_temp_thermal intel_powerclamp snd_intel_dspcfg libiscsi snd_intel_sdw_acpi coretemp scsi_transport_iscsi snd_hwdep kvm_intel i915 snd_pcm ib_umad rdma_cm snd_seq_midi ib_ipoib kvm snd_seq_midi_event iw_cm snd_rawmidi ghash_clmulni_intel ib_cm aesni_intel snd_seq mei_hdcp drm_buddy rapl snd_seq_device eeepc_wmi asus_wmi snd_timer intel_cstate ttm snd drm_client_lib drm_display_helper sparse_keymap soundcore platform_profile mxm_wmi wmi_bmof joydev mei_me cec acpi_pad mei rc_core drm_kms_helper input_leds i2c_algo_bit mac_hid sch_fq_codel msr parport_pc ppdev lp nfsd parport auth_rpcgss binfmt_misc nfs_acl lockd grace drm sunrpc ramoops efi_pstore [ 894.154456] reed_solomon pstore_blk pstore_zone autofs4 btrfs blake2b_generic xor raid6_pq mlx5_ib ib_uverbs ib_core hid_generic uas usbhid hid r8169 i2c_i801 usb_storage i2c_mux i2c_smbus mlx5_core realtek ahci mlxfw psample libahci video wmi [last unloaded: ksmbd] [ 894.154483] CPU: 3 UID: 0 PID: 5543 Comm: kworker/3:6 Tainted: G W 6.18.0-rc5+ #1 PREEMPT(voluntary) [ 894.154487] Tainted: [W]=WARN [ 894.154488] Hardware name: System manufacturer System Product Name/H110M-K, BIOS 3601 12/12/2017 [ 894.154490] Workqueue: ib_cm cm_work_handler [ib_cm] [ 894.154499] RIP: 0010:smb_direct_cm_handler+0x121/0x130 [ksmbd] [ 894.154507] Code: e7 e8 13 b1 ef ff 44 89 e1 4c 89 ee 48 c7 c7 80 d7 59 c1 48 89 c2 e8 2e 4d ef c3 31 c0 5b 41 5c 41 5d 41 5e 5d c3 cc cc cc cc <0f> 0b eb a5 66 66 2e 0f 1f 84 00 00 00 00 00 90 90 90 90 90 90 90 [ 894.154510] RSP: 0018:ffffa47ec1b27c00 EFLAGS: 00010206 [ 894.154512] RAX: ffffffffc1304e00 RBX: ffff8eb89ae50880 RCX: 0000000000000000 [ 894.154514] RDX: ffff8eb730960000 RSI: ffffa47ec1b27c60 RDI: ffff8eb7454b9400 [ 894.154515] RBP: ffffa47ec1b27c20 R08: 0000000000000002 R09: ffff8eb730b8c18b [ 894.154517] R10: 0000000000000001 R11: 0000000000000001 R12: 0000000000000009 [ 894.154518] R13: ffff8eb7454b9400 R14: ffff8eb7454b8810 R15: ffff8eb815c43000 [ 894.154520] FS: 0000000000000000(0000) GS:ffff8eb9a7455000(0000) knlGS:0000000000000000 [ 894.154522] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 894.154523] CR2: 00007fe1310e99d0 CR3: 0000000010a40005 CR4: 00000000003726f0 [ 894.154525] Call Trace: [ 894.154527] [ 894.154530] cma_cm_event_handler+0x27/0xd0 [rdma_cm] [ 894.154541] cma_ib_handler+0x99/0x2e0 [rdma_cm] [ 894.154551] cm_process_work+0x28/0xf0 [ib_cm] [ 894.154557] cm_queue_work_unlock+0x41/0xf0 [ib_cm] [ 894.154563] cm_work_handler+0x2eb/0x25b0 [ib_cm] [ 894.154568] ? pwq_activate_first_inactive+0x52/0x70 [ 894.154572] ? pwq_dec_nr_in_flight+0x244/0x330 [ 894.154575] process_scheduled_works+0xd4/0x430 [ 894.154579] worker_thread+0x12a/0x270 [ 894.154581] kthread+0x10d/0x250 [ 894.154585] ? __pfx_worker_thread+0x10/0x10 [ 894.154587] ? __pfx_kthread+0x10/0x10 [ 894.154590] ret_from_fork+0x11a/0x160 [ 894.154593] ? __pfx_kthread+0x10/0x10 [ 894.154596] ret_from_fork_asm+0x1a/0x30 [ 894.154602] [ 894.154603] ---[ end trace 0000000000000000 ]--- [ 894.154931] ksmbd: smb_direct: disconnected [ 894.157278] ksmbd: smb_direct: disconnected I guess sc->first_error is already set and sc->status is thus unexpected, so this should avoid the WARN[_ON]_ONCE() if sc->first_error is already set and have a usable error path. While there set sc->first_error as soon as possible. v1 of this patch revealed the real problem with this message: [ 309.560973] expected[NEGOTIATE_NEEDED] != RDMA_CONNECT_RUNNING first_error=0 local=192.168.0.200:445 remote=192.168.0.100:60445 [ 309.561034] WARNING: CPU: 2 PID: 78 at transport_rdma.c:643 recv_done+0x2fa/0x3d0 [ksmbd] Some drivers (at least mlx5_ib) might post a recv completion before RDMA_CM_EVENT_ESTABLISHED, so we need to adjust our expectation in that case. Fixes: e2d5e516c663 ("smb: server: only turn into SMBDIRECT_SOCKET_CONNECTED when negotiation is done") Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: Namjae Jeon Cc: Paulo Alcantara Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_rdma.c | 40 +++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index e2be9a496154..4e7ab8d9314f 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -19,6 +19,8 @@ #include #include +#define __SMBDIRECT_SOCKET_DISCONNECT(__sc) smb_direct_disconnect_rdma_connection(__sc) + #include "glob.h" #include "connection.h" #include "smb_common.h" @@ -231,6 +233,9 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, disconnect_work); + if (sc->first_error == 0) + sc->first_error = -ECONNABORTED; + /* * make sure this and other work is not queued again * but here we don't block and avoid @@ -241,9 +246,6 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) disable_delayed_work(&sc->idle.timer_work); disable_work(&sc->idle.immediate_work); - if (sc->first_error == 0) - sc->first_error = -ECONNABORTED; - switch (sc->status) { case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: @@ -287,6 +289,9 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work) static void smb_direct_disconnect_rdma_connection(struct smbdirect_socket *sc) { + if (sc->first_error == 0) + sc->first_error = -ECONNABORTED; + /* * make sure other work (than disconnect_work) is * not queued again but here we don't block and avoid @@ -296,9 +301,6 @@ smb_direct_disconnect_rdma_connection(struct smbdirect_socket *sc) disable_work(&sc->idle.immediate_work); disable_delayed_work(&sc->idle.timer_work); - if (sc->first_error == 0) - sc->first_error = -ECONNABORTED; - switch (sc->status) { case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: @@ -639,7 +641,18 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) return; } sc->recv_io.reassembly.full_packet_received = true; - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_NEEDED); + /* + * Some drivers (at least mlx5_ib) might post a + * recv completion before RDMA_CM_EVENT_ESTABLISHED, + * we need to adjust our expectation in that case. + */ + if (!sc->first_error && sc->status == SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING) + sc->status = SMBDIRECT_SOCKET_NEGOTIATE_NEEDED; + if (SMBDIRECT_CHECK_STATUS_WARN(sc, SMBDIRECT_SOCKET_NEGOTIATE_NEEDED)) { + put_recvmsg(sc, recvmsg); + smb_direct_disconnect_rdma_connection(sc); + return; + } sc->status = SMBDIRECT_SOCKET_NEGOTIATE_RUNNING; enqueue_reassembly(sc, recvmsg, 0); wake_up(&sc->status_wait); @@ -1725,7 +1738,18 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, switch (event->event) { case RDMA_CM_EVENT_ESTABLISHED: { - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); + /* + * Some drivers (at least mlx5_ib) might post a + * recv completion before RDMA_CM_EVENT_ESTABLISHED, + * we need to adjust our expectation in that case. + * + * As we already started the negotiation, we just + * ignore RDMA_CM_EVENT_ESTABLISHED here. + */ + if (!sc->first_error && sc->status > SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING) + break; + if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING)) + break; sc->status = SMBDIRECT_SOCKET_NEGOTIATE_NEEDED; wake_up(&sc->status_wait); break; From dc10cf1368af8cb816dcaa2502ba7d44fff20612 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 25 Nov 2025 15:21:54 +0100 Subject: [PATCH 40/44] smb: client: relax WARN_ON_ONCE(SMBDIRECT_SOCKET_*) checks in recv_done() and smbd_conn_upcall() sc->first_error might already be set and sc->status is thus unexpected, so this should avoid the WARN[_ON]_ONCE() if sc->first_error is already set and have a usable error path. While there set sc->first_error as soon as possible. This is done based on a problem seen in similar places on the server. And there it was already very useful in order to find the problem when we have a meaningful WARN_ONCE() that prints details about the connection. This is much more useful: [ 309.560973] expected[NEGOTIATE_NEEDED] != RDMA_CONNECT_RUNNING first_error=0 local=192.168.0.200:445 remote=192.168.0.100:60445 [ 309.561034] WARNING: CPU: 2 PID: 78 at transport_rdma.c:643 recv_done+0x2fa/0x3d0 [ksmbd] than what we had before (only): [ 894.140316] WARNING: CPU: 1 PID: 116 at fs/smb/server/transport_rdma.c:642 recv_done+0x308/0x360 [ksmbd] Fixes: 58dfba8a2d4e ("smb: client/smbdirect: replace SMBDIRECT_SOCKET_CONNECTING with more detailed states") Cc: Steve French Cc: Tom Talpey Cc: Long Li Cc: Namjae Jeon Cc: Paulo Alcantara Cc: linux-cifs@vger.kernel.org Cc: samba-technical@lists.samba.org Signed-off-by: Stefan Metzmacher Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/client/smbdirect.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index c6c428c2e08d..788a0670c4a8 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -7,6 +7,7 @@ #include #include #include +#define __SMBDIRECT_SOCKET_DISCONNECT(__sc) smbd_disconnect_rdma_connection(__sc) #include "../common/smbdirect/smbdirect_pdu.h" #include "smbdirect.h" #include "cifs_debug.h" @@ -186,6 +187,9 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) struct smbdirect_socket *sc = container_of(work, struct smbdirect_socket, disconnect_work); + if (sc->first_error == 0) + sc->first_error = -ECONNABORTED; + /* * make sure this and other work is not queued again * but here we don't block and avoid @@ -197,9 +201,6 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) disable_work(&sc->idle.immediate_work); disable_delayed_work(&sc->idle.timer_work); - if (sc->first_error == 0) - sc->first_error = -ECONNABORTED; - switch (sc->status) { case SMBDIRECT_SOCKET_NEGOTIATE_NEEDED: case SMBDIRECT_SOCKET_NEGOTIATE_RUNNING: @@ -242,6 +243,9 @@ static void smbd_disconnect_rdma_work(struct work_struct *work) static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) { + if (sc->first_error == 0) + sc->first_error = -ECONNABORTED; + /* * make sure other work (than disconnect_work) is * not queued again but here we don't block and avoid @@ -252,9 +256,6 @@ static void smbd_disconnect_rdma_connection(struct smbdirect_socket *sc) disable_work(&sc->idle.immediate_work); disable_delayed_work(&sc->idle.timer_work); - if (sc->first_error == 0) - sc->first_error = -ECONNABORTED; - switch (sc->status) { case SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED: case SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED: @@ -322,27 +323,27 @@ static int smbd_conn_upcall( switch (event->event) { case RDMA_CM_EVENT_ADDR_RESOLVED: - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); + if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING)) + break; sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_NEEDED; wake_up(&sc->status_wait); break; case RDMA_CM_EVENT_ROUTE_RESOLVED: - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); + if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING)) + break; sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_NEEDED; wake_up(&sc->status_wait); break; case RDMA_CM_EVENT_ADDR_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ADDR_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ADDR_FAILED; smbd_disconnect_rdma_work(&sc->disconnect_work); break; case RDMA_CM_EVENT_ROUTE_ERROR: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RESOLVE_ROUTE_RUNNING); sc->status = SMBDIRECT_SOCKET_RESOLVE_ROUTE_FAILED; smbd_disconnect_rdma_work(&sc->disconnect_work); break; @@ -428,7 +429,8 @@ static int smbd_conn_upcall( min_t(u8, sp->responder_resources, peer_responder_resources); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); + if (SMBDIRECT_CHECK_STATUS_DISCONNECT(sc, SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING)) + break; sc->status = SMBDIRECT_SOCKET_NEGOTIATE_NEEDED; wake_up(&sc->status_wait); break; @@ -437,7 +439,6 @@ static int smbd_conn_upcall( case RDMA_CM_EVENT_UNREACHABLE: case RDMA_CM_EVENT_REJECTED: log_rdma_event(ERR, "connecting failed event=%s\n", event_name); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_RDMA_CONNECT_RUNNING); sc->status = SMBDIRECT_SOCKET_RDMA_CONNECT_FAILED; smbd_disconnect_rdma_work(&sc->disconnect_work); break; @@ -699,7 +700,8 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) negotiate_done = process_negotiation_response(response, wc->byte_len); put_receive_buffer(sc, response); - WARN_ON_ONCE(sc->status != SMBDIRECT_SOCKET_NEGOTIATE_RUNNING); + if (SMBDIRECT_CHECK_STATUS_WARN(sc, SMBDIRECT_SOCKET_NEGOTIATE_RUNNING)) + negotiate_done = false; if (!negotiate_done) { sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED; smbd_disconnect_rdma_connection(sc); From 1fab1fa091f5aa97265648b53ea031deedd26235 Mon Sep 17 00:00:00 2001 From: Qianchang Zhao Date: Wed, 26 Nov 2025 12:24:18 +0900 Subject: [PATCH 41/44] ksmbd: ipc: fix use-after-free in ipc_msg_send_request ipc_msg_send_request() waits for a generic netlink reply using an ipc_msg_table_entry on the stack. The generic netlink handler (handle_generic_event()/handle_response()) fills entry->response under ipc_msg_table_lock, but ipc_msg_send_request() used to validate and free entry->response without holding the same lock. Under high concurrency this allows a race where handle_response() is copying data into entry->response while ipc_msg_send_request() has just freed it, leading to a slab-use-after-free reported by KASAN in handle_generic_event(): BUG: KASAN: slab-use-after-free in handle_generic_event+0x3c4/0x5f0 [ksmbd] Write of size 12 at addr ffff888198ee6e20 by task pool/109349 ... Freed by task: kvfree ipc_msg_send_request [ksmbd] ksmbd_rpc_open -> ksmbd_session_rpc_open [ksmbd] Fix by: - Taking ipc_msg_table_lock in ipc_msg_send_request() while validating entry->response, freeing it when invalid, and removing the entry from ipc_msg_table. - Returning the final entry->response pointer to the caller only after the hash entry is removed under the lock. - Returning NULL in the error path, preserving the original API semantics. This makes all accesses to entry->response consistent with handle_response(), which already updates and fills the response buffer under ipc_msg_table_lock, and closes the race that allowed the UAF. Cc: stable@vger.kernel.org Reported-by: Qianchang Zhao Reported-by: Zhitong Liu Signed-off-by: Qianchang Zhao Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_ipc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/smb/server/transport_ipc.c b/fs/smb/server/transport_ipc.c index 2c08cccfa680..2dbabe2d8005 100644 --- a/fs/smb/server/transport_ipc.c +++ b/fs/smb/server/transport_ipc.c @@ -553,12 +553,16 @@ static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle up_write(&ipc_msg_table_lock); ret = ipc_msg_send(msg); - if (ret) + if (ret) { + down_write(&ipc_msg_table_lock); goto out; + } ret = wait_event_interruptible_timeout(entry.wait, entry.response != NULL, IPC_WAIT_TIMEOUT); + + down_write(&ipc_msg_table_lock); if (entry.response) { ret = ipc_validate_msg(&entry); if (ret) { @@ -567,7 +571,6 @@ static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle } } out: - down_write(&ipc_msg_table_lock); hash_del(&entry.ipc_table_hlist); up_write(&ipc_msg_table_lock); return entry.response; From 9cfcd8601e56fd5e1fdb3adae57322fa5d7d3689 Mon Sep 17 00:00:00 2001 From: Bharath SM Date: Thu, 30 Oct 2025 00:34:29 +0530 Subject: [PATCH 42/44] smb: client: show smb lease key in open_files output Add the SMB lease key in /proc/fs/cifs/open_files for debugging purposes. Signed-off-by: Bharath SM Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 1fb71d2d31b5..1383caa5a034 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -249,9 +249,9 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v) seq_puts(m, "# Format:\n"); seq_puts(m, "# "); #ifdef CONFIG_CIFS_DEBUG2 - seq_puts(m, " \n"); + seq_puts(m, " \n"); #else - seq_puts(m, " \n"); + seq_puts(m, " \n"); #endif /* CIFS_DEBUG2 */ spin_lock(&cifs_tcp_ses_lock); list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { @@ -274,6 +274,7 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v) /* Append lease/oplock caching state as RHW letters */ inode = d_inode(cfile->dentry); + cinode = NULL; n = 0; if (inode) { cinode = CIFS_I(inode); @@ -291,6 +292,12 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v) else seq_puts(m, "NONE"); + seq_puts(m, " "); + if (cinode && cinode->lease_granted) + seq_printf(m, "%pUl", cinode->lease_key); + else + seq_puts(m, "-"); + #ifdef CONFIG_CIFS_DEBUG2 seq_printf(m, " %llu", cfile->fid.mid); #endif /* CONFIG_CIFS_DEBUG2 */ From f78b83dce273ff2d9a4515b2945ec427e675c204 Mon Sep 17 00:00:00 2001 From: Bharath SM Date: Thu, 30 Oct 2025 00:40:36 +0530 Subject: [PATCH 43/44] smb: client: show smb lease key in open_dirs output Show cached directory smb lease key in /proc/fs/cifs/open_dirs for debugging purposes. Signed-off-by: Bharath SM Signed-off-by: Steve French --- fs/smb/client/cifs_debug.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 1383caa5a034..7fdcaf9feb16 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -324,7 +324,7 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v) seq_puts(m, "# Version:1\n"); seq_puts(m, "# Format:\n"); - seq_puts(m, "# \n"); + seq_puts(m, "# \n"); spin_lock(&cifs_tcp_ses_lock); list_for_each(stmp, &cifs_tcp_ses_list) { @@ -343,11 +343,15 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v) (unsigned long)atomic_long_read(&cfids->total_dirents_entries), (unsigned long long)atomic64_read(&cfids->total_dirents_bytes)); list_for_each_entry(cfid, &cfids->entries, entry) { - seq_printf(m, "0x%x 0x%llx 0x%llx %s", + seq_printf(m, "0x%x 0x%llx 0x%llx ", tcon->tid, ses->Suid, - cfid->fid.persistent_fid, - cfid->path); + cfid->fid.persistent_fid); + if (cfid->has_lease) + seq_printf(m, "%pUl ", cfid->fid.lease_key); + else + seq_puts(m, "- "); + seq_printf(m, "%s", cfid->path); if (cfid->file_all_info_is_valid) seq_printf(m, "\tvalid file info"); if (cfid->dirents.is_valid) From e1469f56089fc00bc94706a07c5cd63fa3e8625b Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 5 Aug 2025 09:57:45 +0100 Subject: [PATCH 44/44] cifs: Use netfs_alloc/free_folioq_buffer() Use netfs_alloc/free_folioq_buffer() rather than doing its own version. Signed-off-by: David Howells cc: Steve French cc: Paulo Alcantara cc: Shyam Prasad N cc: Tom Talpey (RDMA, smbdirect) cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org Signed-off-by: Steve French --- fs/smb/client/smb2ops.c | 73 ++++++----------------------------------- 1 file changed, 10 insertions(+), 63 deletions(-) diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 4b005a7adce0..7ace6d4d305b 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -4484,61 +4484,6 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst, return rc; } -/* - * Clear a read buffer, discarding the folios which have the 1st mark set. - */ -static void cifs_clear_folioq_buffer(struct folio_queue *buffer) -{ - struct folio_queue *folioq; - - while ((folioq = buffer)) { - for (int s = 0; s < folioq_count(folioq); s++) - if (folioq_is_marked(folioq, s)) - folio_put(folioq_folio(folioq, s)); - buffer = folioq->next; - kfree(folioq); - } -} - -/* - * Allocate buffer space into a folio queue. - */ -static struct folio_queue *cifs_alloc_folioq_buffer(ssize_t size) -{ - struct folio_queue *buffer = NULL, *tail = NULL, *p; - struct folio *folio; - unsigned int slot; - - do { - if (!tail || folioq_full(tail)) { - p = kmalloc(sizeof(*p), GFP_NOFS); - if (!p) - goto nomem; - folioq_init(p, 0); - if (tail) { - tail->next = p; - p->prev = tail; - } else { - buffer = p; - } - tail = p; - } - - folio = folio_alloc(GFP_KERNEL|__GFP_HIGHMEM, 0); - if (!folio) - goto nomem; - - slot = folioq_append_mark(tail, folio); - size -= folioq_folio_size(tail, slot); - } while (size > 0); - - return buffer; - -nomem: - cifs_clear_folioq_buffer(buffer); - return NULL; -} - /* * Copy data from an iterator to the folios in a folio queue buffer. */ @@ -4564,7 +4509,7 @@ void smb3_free_compound_rqst(int num_rqst, struct smb_rqst *rqst) { for (int i = 0; i < num_rqst; i++) - cifs_clear_folioq_buffer(rqst[i].rq_buffer); + netfs_free_folioq_buffer(rqst[i].rq_buffer); } /* @@ -4599,8 +4544,10 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst, new->rq_nvec = old->rq_nvec; if (size > 0) { - buffer = cifs_alloc_folioq_buffer(size); - if (!buffer) + size_t cur_size = 0; + rc = netfs_alloc_folioq_buffer(NULL, &buffer, &cur_size, + size, GFP_NOFS); + if (rc < 0) goto err_free; new->rq_buffer = buffer; @@ -4932,7 +4879,7 @@ static void smb2_decrypt_offload(struct work_struct *work) } free_pages: - cifs_clear_folioq_buffer(dw->buffer); + netfs_free_folioq_buffer(dw->buffer); cifs_small_buf_release(dw->buf); kfree(dw); } @@ -4970,9 +4917,9 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, dw->len = len; len = round_up(dw->len, PAGE_SIZE); - rc = -ENOMEM; - dw->buffer = cifs_alloc_folioq_buffer(len); - if (!dw->buffer) + size_t cur_size = 0; + rc = netfs_alloc_folioq_buffer(NULL, &dw->buffer, &cur_size, len, GFP_NOFS); + if (rc < 0) goto discard_data; iov_iter_folio_queue(&iter, ITER_DEST, dw->buffer, 0, 0, len); @@ -5033,7 +4980,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, } free_pages: - cifs_clear_folioq_buffer(dw->buffer); + netfs_free_folioq_buffer(dw->buffer); free_dw: kfree(dw); return rc;