Merge tag 'v7.2-rc2-smb3-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:
 "This contains a set of SMB server fixes mostly around session setup,
  multichannel/session binding, and protocol-compatible error reporting:

   - Fix SID-to-id mapping so only SIDs with a valid local Unix
     representation are translated, while preserving other Windows
     SIDs in NT ACL xattrs

   - Fix SMB3 multichannel binding across multi-round authentication,
     keep the derived channel key separate from the established session
     key, and enforce the 32-channel session limit

   - Match Windows-compatible close timestamp behavior by coalescing
     automatic write time updates smaller than 15ms

   - Return STATUS_DISK_FULL for SET_INFO allocation failures caused
     by ENOSPC or EFBIG

   - Fix several signed SESSION_SETUP error paths so clients see the
     intended server status instead of replacing it with
     STATUS_ACCESS_DENIED

   - Fix reauthentication on bound channels and reject different-user
     channel binding with STATUS_ACCESS_DENIED

   - Use the referenced session dialect/signing algorithm when
     validating and signing rejected cross-dialect binding requests"

* tag 'v7.2-rc2-smb3-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: use the session dialect for rejected binding signatures
  ksmbd: mark rejected cross-dialect bindings as signed
  ksmbd: sign rejected SMB2.1 session binding responses
  ksmbd: handle channel binding with a different user
  ksmbd: find bound sessions during reauthentication
  ksmbd: mark invalid session responses as signed
  smb/server: map SET_INFO ENOSPC to disk full
  ksmbd: coalesce sub-15ms write time updates on close
  ksmbd: fix multichannel binding and enforce channel limit
  ksmbd: validate SID namespace before mapping IDs
This commit is contained in:
Linus Torvalds
2026-07-09 16:30:56 -07:00
8 changed files with 218 additions and 86 deletions

View File

@@ -133,16 +133,17 @@ static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess,
* @blen: NTLMv2 blob length
* @domain_name: domain name
* @cryptkey: session crypto key
* @sess_key: derived session key output buffer
*
* Return: 0 on success, error number on error
*/
int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
char *cryptkey)
char *cryptkey, char *sess_key)
{
char ntlmv2_hash[CIFS_ENCPWD_SIZE];
char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
char sess_key[SMB2_NTLMV2_SESSKEY_SIZE];
char base_key[SMB2_NTLMV2_SESSKEY_SIZE];
struct hmac_md5_ctx ctx;
int rc;
@@ -165,7 +166,7 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
/* Generate the session key */
hmac_md5_usingrawkey(ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE,
ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE,
sess_key);
base_key);
if (crypto_memneq(ntlmv2->ntlmv2_hash, ntlmv2_rsp,
CIFS_HMAC_MD5_HASH_SIZE)) {
@@ -173,12 +174,12 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
goto out;
}
memcpy(sess->sess_key, sess_key, sizeof(sess_key));
memcpy(sess_key, base_key, sizeof(base_key));
rc = 0;
out:
memzero_explicit(ntlmv2_hash, sizeof(ntlmv2_hash));
memzero_explicit(ntlmv2_rsp, sizeof(ntlmv2_rsp));
memzero_explicit(sess_key, sizeof(sess_key));
memzero_explicit(base_key, sizeof(base_key));
return rc;
}
@@ -189,12 +190,13 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
* @blob_len: length of the @authblob message
* @conn: connection
* @sess: session of connection
* @sess_key: derived session key output buffer
*
* Return: 0 on success, error number on error
*/
int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
int blob_len, struct ksmbd_conn *conn,
struct ksmbd_session *sess)
struct ksmbd_session *sess, char *sess_key)
{
char *domain_name;
unsigned int nt_off, dn_off;
@@ -234,7 +236,7 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
ret = ksmbd_auth_ntlmv2(conn, sess,
(struct ntlmv2_resp *)((char *)authblob + nt_off),
nt_len - CIFS_ENCPWD_SIZE,
domain_name, conn->ntlmssp.cryptkey);
domain_name, conn->ntlmssp.cryptkey, sess_key);
kfree(domain_name);
if (ret)
return ret;
@@ -257,8 +259,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
if (!ctx_arc4)
return -ENOMEM;
arc4_setkey(ctx_arc4, sess->sess_key, SMB2_NTLMV2_SESSKEY_SIZE);
arc4_crypt(ctx_arc4, sess->sess_key,
arc4_setkey(ctx_arc4, sess_key, SMB2_NTLMV2_SESSKEY_SIZE);
arc4_crypt(ctx_arc4, sess_key,
(char *)authblob + sess_key_off, sess_key_len);
kfree_sensitive(ctx_arc4);
}
@@ -400,7 +402,8 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
#ifdef CONFIG_SMB_SERVER_KERBEROS5
int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
int in_len, char *out_blob, int *out_len)
int in_len, char *out_blob, int *out_len,
char *sess_key)
{
struct ksmbd_spnego_authen_response *resp;
struct ksmbd_login_response_ext *resp_ext = NULL;
@@ -448,14 +451,14 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
} else {
if (!ksmbd_compare_user(sess->user, user)) {
ksmbd_debug(AUTH, "different user tried to reuse session\n");
retval = -EPERM;
retval = -EKEYREJECTED;
ksmbd_free_user(user);
goto out;
}
ksmbd_free_user(user);
}
memcpy(sess->sess_key, resp->payload, resp->session_key_len);
memcpy(sess_key, resp->payload, resp->session_key_len);
memcpy(out_blob, resp->payload + resp->session_key_len,
resp->spnego_blob_len);
*out_len = resp->spnego_blob_len;
@@ -466,7 +469,8 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
}
#else
int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
int in_len, char *out_blob, int *out_len)
int in_len, char *out_blob, int *out_len,
char *sess_key)
{
return -EOPNOTSUPP;
}
@@ -525,7 +529,7 @@ struct derivation {
bool binding;
};
static void generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess,
static void generate_key(struct ksmbd_conn *conn, const char *sess_key,
struct kvec label, struct kvec context, __u8 *key,
unsigned int key_size)
{
@@ -536,7 +540,7 @@ static void generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess,
unsigned char prfhash[SMB2_HMACSHA256_SIZE];
struct hmac_sha256_ctx ctx;
hmac_sha256_init_usingrawkey(&ctx, sess->sess_key,
hmac_sha256_init_usingrawkey(&ctx, sess_key,
SMB2_NTLMV2_SESSKEY_SIZE);
hmac_sha256_update(&ctx, i, 4);
hmac_sha256_update(&ctx, label.iov_base, label.iov_len);
@@ -559,18 +563,21 @@ static int generate_smb3signingkey(struct ksmbd_session *sess,
const struct derivation *signing)
{
struct channel *chann;
char *key;
char *key, *sess_key;
chann = lookup_chann_list(sess, conn);
if (!chann)
return 0;
if (conn->dialect >= SMB30_PROT_ID && signing->binding)
if (conn->dialect >= SMB30_PROT_ID && signing->binding) {
key = chann->smb3signingkey;
else
sess_key = chann->sess_key;
} else {
key = sess->smb3signingkey;
sess_key = sess->sess_key;
}
generate_key(conn, sess, signing->label, signing->context, key,
generate_key(conn, sess_key, signing->label, signing->context, key,
SMB3_SIGN_KEY_SIZE);
if (!(conn->dialect >= SMB30_PROT_ID && signing->binding))
@@ -627,11 +634,11 @@ static void generate_smb3encryptionkey(struct ksmbd_conn *conn,
struct ksmbd_session *sess,
const struct derivation_twin *ptwin)
{
generate_key(conn, sess, ptwin->encryption.label,
generate_key(conn, sess->sess_key, ptwin->encryption.label,
ptwin->encryption.context, sess->smb3encryptionkey,
SMB3_ENC_DEC_KEY_SIZE);
generate_key(conn, sess, ptwin->decryption.label,
generate_key(conn, sess->sess_key, ptwin->decryption.label,
ptwin->decryption.context,
sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE);

View File

@@ -41,17 +41,18 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
void ksmbd_copy_gss_neg_header(void *buf);
int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
char *cryptkey);
char *cryptkey, char *sess_key);
int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
int blob_len, struct ksmbd_conn *conn,
struct ksmbd_session *sess);
struct ksmbd_session *sess, char *sess_key);
int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob,
int blob_len, struct ksmbd_conn *conn);
unsigned int
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 in_len, char *out_blob, int *out_len,
char *sess_key);
void ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
int n_vec, char *sig);
void ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,

View File

@@ -255,7 +255,7 @@ static void free_channel_list(struct ksmbd_session *sess)
down_write(&sess->chann_lock);
xa_for_each(&sess->ksmbd_chann_list, index, chann) {
xa_erase(&sess->ksmbd_chann_list, index);
kfree(chann);
kfree_sensitive(chann);
}
xa_destroy(&sess->ksmbd_chann_list);
@@ -449,7 +449,7 @@ static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
if (!chann)
return -ENOENT;
kfree(chann);
kfree_sensitive(chann);
return 0;
}

View File

@@ -19,6 +19,7 @@
struct ksmbd_file_table;
struct channel {
char sess_key[SMB2_NTLMV2_SESSKEY_SIZE];
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
struct ksmbd_conn *conn;
};

View File

@@ -199,6 +199,12 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
else
conn->ops->set_rsp_status(work,
STATUS_USER_SESSION_DELETED);
if (conn->ops->is_sign_req(work, conn->ops->get_cmd_val(work))) {
struct smb2_hdr *rsp_hdr;
rsp_hdr = ksmbd_resp_buf_curr(work);
rsp_hdr->Flags |= SMB2_FLAGS_SIGNED;
}
goto send;
} else if (rc > 0) {
rc = conn->ops->get_ksmbd_tcon(work);
@@ -237,8 +243,14 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
if (work->sess &&
(work->sess->sign || smb3_11_final_sess_setup_resp(work) ||
conn->ops->is_sign_req(work, command)))
conn->ops->set_sign_rsp(work);
conn->ops->is_sign_req(work, command))) {
if (command == SMB2_SESSION_SETUP_HE &&
work->sess->dialect >= SMB30_PROT_ID &&
conn->dialect < SMB30_PROT_ID)
smb3_set_sign_rsp(work);
else
conn->ops->set_sign_rsp(work);
}
} while (is_chained == true);
send:

View File

@@ -61,6 +61,9 @@ static void __wbuf(struct ksmbd_work *work, void **req, void **rsp)
(FILE_ATTRIBUTE_MASK & ~(FILE_ATTRIBUTE_INTEGRITY_STREAM | \
FILE_ATTRIBUTE_NO_SCRUB_DATA))
/* Windows reports automatic write-time updates at roughly 15 ms resolution. */
#define KSMBD_WRITE_TIME_RESOLUTION (15ULL * 10000)
/**
* check_session_id() - check for valid session id in smb header
* @conn: connection instance
@@ -95,6 +98,47 @@ struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn
return chann;
}
#define KSMBD_MAX_CHANNELS 32
static int register_session_channel(struct ksmbd_session *sess,
struct ksmbd_conn *conn,
const char *sess_key)
{
struct channel *chann, *old;
unsigned long index;
unsigned int count = 0;
int rc = 0;
down_write(&sess->chann_lock);
if (xa_load(&sess->ksmbd_chann_list, (long)conn))
goto out;
xa_for_each(&sess->ksmbd_chann_list, index, chann)
count++;
if (count >= KSMBD_MAX_CHANNELS) {
rc = -ENOSPC;
goto out;
}
chann = kmalloc_obj(struct channel, KSMBD_DEFAULT_GFP);
if (!chann) {
rc = -ENOMEM;
goto out;
}
chann->conn = conn;
memcpy(chann->sess_key, sess_key, sizeof(chann->sess_key));
old = xa_store(&sess->ksmbd_chann_list, (long)conn, chann,
KSMBD_DEFAULT_GFP);
if (xa_is_err(old)) {
kfree_sensitive(chann);
rc = xa_err(old);
}
out:
up_write(&sess->chann_lock);
return rc;
}
/**
* smb2_get_ksmbd_tcon() - get tree connection information using a tree id.
* @work: smb work
@@ -1644,9 +1688,11 @@ static int ntlm_authenticate(struct ksmbd_work *work,
{
struct ksmbd_conn *conn = work->conn;
struct ksmbd_session *sess = work->sess;
struct channel *chann = NULL, *old;
struct ksmbd_user *user;
char channel_key[SMB2_NTLMV2_SESSKEY_SIZE] = {};
char *auth_key = conn->binding ? channel_key : sess->sess_key;
u64 prev_id;
bool binding = conn->binding;
int sz, rc;
ksmbd_debug(SMB, "authenticate phase\n");
@@ -1688,7 +1734,7 @@ static int ntlm_authenticate(struct ksmbd_work *work,
if (!ksmbd_compare_user(sess->user, user)) {
ksmbd_free_user(user);
return -EPERM;
return -EKEYREJECTED;
}
ksmbd_free_user(user);
} else {
@@ -1705,11 +1751,13 @@ static int ntlm_authenticate(struct ksmbd_work *work,
sz = conn->mechTokenLen;
else
sz = le16_to_cpu(req->SecurityBufferLength);
rc = ksmbd_decode_ntlmssp_auth_blob(authblob, sz, conn, sess);
rc = ksmbd_decode_ntlmssp_auth_blob(authblob, sz, conn, sess,
auth_key);
if (rc) {
set_user_flag(sess->user, KSMBD_USER_FLAG_BAD_PASSWORD);
ksmbd_debug(SMB, "authentication failed\n");
return -EPERM;
rc = -EPERM;
goto out;
}
}
@@ -1744,37 +1792,30 @@ static int ntlm_authenticate(struct ksmbd_work *work,
binding_session:
if (conn->dialect >= SMB30_PROT_ID) {
chann = lookup_chann_list(sess, conn);
if (!chann) {
chann = kmalloc_obj(struct channel, KSMBD_DEFAULT_GFP);
if (!chann)
return -ENOMEM;
chann->conn = conn;
down_write(&sess->chann_lock);
old = xa_store(&sess->ksmbd_chann_list, (long)conn, chann,
KSMBD_DEFAULT_GFP);
up_write(&sess->chann_lock);
if (xa_is_err(old)) {
kfree(chann);
return xa_err(old);
}
}
rc = register_session_channel(sess, conn, auth_key);
if (rc)
goto out;
}
if (conn->ops->generate_signingkey) {
rc = conn->ops->generate_signingkey(sess, conn);
if (rc) {
ksmbd_debug(SMB, "SMB3 signing key generation failed\n");
return -EINVAL;
rc = -EINVAL;
goto out;
}
}
if (!ksmbd_conn_lookup_dialect(conn)) {
pr_err("fail to verify the dialect\n");
return -ENOENT;
rc = -ENOENT;
goto out;
}
return 0;
rc = 0;
out:
if (binding)
memzero_explicit(channel_key, sizeof(channel_key));
return rc;
}
#ifdef CONFIG_SMB_SERVER_KERBEROS5
@@ -1785,8 +1826,10 @@ static int krb5_authenticate(struct ksmbd_work *work,
struct ksmbd_conn *conn = work->conn;
struct ksmbd_session *sess = work->sess;
char *in_blob, *out_blob;
struct channel *chann = NULL, *old;
char channel_key[SMB2_NTLMV2_SESSKEY_SIZE] = {};
char *auth_key = conn->binding ? channel_key : sess->sess_key;
u64 prev_sess_id;
bool binding = conn->binding;
int in_len, out_len;
int retval;
@@ -1799,10 +1842,12 @@ static int krb5_authenticate(struct ksmbd_work *work,
(le16_to_cpu(rsp->SecurityBufferOffset) + 4);
retval = ksmbd_krb5_authenticate(sess, in_blob, in_len,
out_blob, &out_len);
out_blob, &out_len, auth_key);
if (retval) {
ksmbd_debug(SMB, "krb5 authentication failed\n");
return -EINVAL;
if (retval != -EKEYREJECTED)
retval = -EINVAL;
goto out;
}
/* Check previous session */
@@ -1839,37 +1884,30 @@ static int krb5_authenticate(struct ksmbd_work *work,
binding_session:
if (conn->dialect >= SMB30_PROT_ID) {
chann = lookup_chann_list(sess, conn);
if (!chann) {
chann = kmalloc_obj(struct channel, KSMBD_DEFAULT_GFP);
if (!chann)
return -ENOMEM;
chann->conn = conn;
down_write(&sess->chann_lock);
old = xa_store(&sess->ksmbd_chann_list, (long)conn,
chann, KSMBD_DEFAULT_GFP);
up_write(&sess->chann_lock);
if (xa_is_err(old)) {
kfree(chann);
return xa_err(old);
}
}
retval = register_session_channel(sess, conn, auth_key);
if (retval)
goto out;
}
if (conn->ops->generate_signingkey) {
retval = conn->ops->generate_signingkey(sess, conn);
if (retval) {
ksmbd_debug(SMB, "SMB3 signing key generation failed\n");
return -EINVAL;
retval = -EINVAL;
goto out;
}
}
if (!ksmbd_conn_lookup_dialect(conn)) {
pr_err("fail to verify the dialect\n");
return -ENOENT;
retval = -ENOENT;
goto out;
}
return 0;
retval = 0;
out:
if (binding)
memzero_explicit(channel_key, sizeof(channel_key));
return retval;
}
#else
static int krb5_authenticate(struct ksmbd_work *work,
@@ -1975,12 +2013,35 @@ int smb2_sess_setup(struct ksmbd_work *work)
} else if ((conn->dialect < SMB30_PROT_ID ||
server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
sess = NULL;
sess = ksmbd_session_lookup_slowpath(le64_to_cpu(req->hdr.SessionId));
if (sess) {
int sign_ret;
work->sess = sess;
if (sess->dialect >= SMB30_PROT_ID)
sign_ret = smb3_check_sign_req(work);
else
sign_ret = smb2_check_sign_req(work);
if (sess->state != SMB2_SESSION_VALID ||
!(req->hdr.Flags & SMB2_FLAGS_SIGNED) ||
!sign_ret) {
ksmbd_user_session_put(sess);
work->sess = NULL;
sess = NULL;
}
}
rc = -EACCES;
goto out_err;
} else {
sess = ksmbd_session_lookup(conn,
le64_to_cpu(req->hdr.SessionId));
if (!sess) {
sess = ksmbd_session_lookup_slowpath(le64_to_cpu(req->hdr.SessionId));
if (sess && !lookup_chann_list(sess, conn)) {
ksmbd_user_session_put(sess);
sess = NULL;
}
}
if (!sess) {
rc = -ENOENT;
goto out_err;
@@ -2091,12 +2152,19 @@ int smb2_sess_setup(struct ksmbd_work *work)
rsp->hdr.Status = STATUS_REQUEST_NOT_ACCEPTED;
else if (rc == -EFAULT)
rsp->hdr.Status = STATUS_NETWORK_SESSION_EXPIRED;
else if (rc == -ENOMEM)
else if (rc == -ENOMEM || rc == -ENOSPC)
rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
else if (rc == -EOPNOTSUPP)
rsp->hdr.Status = STATUS_NOT_SUPPORTED;
else if (rc == -EKEYREJECTED)
rsp->hdr.Status = STATUS_ACCESS_DENIED;
else if (rc)
rsp->hdr.Status = STATUS_LOGON_FAILURE;
if ((rsp->hdr.Status == STATUS_USER_SESSION_DELETED ||
(rsp->hdr.Status == STATUS_INVALID_PARAMETER &&
(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING))) &&
(req->hdr.Flags & SMB2_FLAGS_SIGNED))
rsp->hdr.Flags |= SMB2_FLAGS_SIGNED;
if (conn->mechToken) {
kfree(conn->mechToken);
@@ -2104,6 +2172,17 @@ int smb2_sess_setup(struct ksmbd_work *work)
}
if (rc < 0) {
if (sess && conn->dialect == SMB311_PROT_ID &&
(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
struct preauth_session *preauth_sess;
preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id);
if (preauth_sess) {
list_del(&preauth_sess->preauth_entry);
kfree(preauth_sess);
}
}
/*
* SecurityBufferOffset should be set to zero
* in session setup error response.
@@ -2130,8 +2209,16 @@ int smb2_sess_setup(struct ksmbd_work *work)
sess->last_active = jiffies;
sess->state = SMB2_SESSION_EXPIRED;
}
ksmbd_user_session_put(sess);
work->sess = NULL;
/*
* Keep the binding session reference until the response is
* signed and sent. Error responses for a signed binding
* request are signed with the existing session signing key.
*/
if (!(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING) ||
work->sess != sess) {
ksmbd_user_session_put(sess);
work->sess = NULL;
}
if (try_delay) {
ksmbd_conn_set_need_reconnect(conn);
ssleep(5);
@@ -3943,6 +4030,7 @@ int smb2_open(struct ksmbd_work *work)
time = ksmbd_UnixTimeToNT(stat.atime);
rsp->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
fp->open_mtime = time;
rsp->LastWriteTime = cpu_to_le64(time);
rsp->ChangeTime = cpu_to_le64(fp->change_time);
/*
@@ -6409,6 +6497,9 @@ int smb2_close(struct ksmbd_work *work)
time = ksmbd_UnixTimeToNT(stat.atime);
rsp->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
if (time > fp->open_mtime &&
time - fp->open_mtime < KSMBD_WRITE_TIME_RESOLUTION)
time = fp->open_mtime;
rsp->LastWriteTime = cpu_to_le64(time);
rsp->ChangeTime = cpu_to_le64(fp->change_time);
ksmbd_fd_put(work, fp);
@@ -7080,6 +7171,8 @@ int smb2_set_info(struct ksmbd_work *work)
rsp->hdr.Status = STATUS_INVALID_PARAMETER;
else if (rc == -EMSGSIZE)
rsp->hdr.Status = STATUS_INFO_LENGTH_MISMATCH;
else if (rc == -ENOSPC || rc == -EFBIG)
rsp->hdr.Status = STATUS_DISK_FULL;
else if (rc == -ESHARE)
rsp->hdr.Status = STATUS_SHARING_VIOLATION;
else if (rc == -ENOENT)
@@ -9483,7 +9576,6 @@ bool smb2_is_sign_req(struct ksmbd_work *work, unsigned int command)
if ((rcv_hdr2->Flags & SMB2_FLAGS_SIGNED) &&
command != SMB2_NEGOTIATE_HE &&
command != SMB2_SESSION_SETUP_HE &&
command != SMB2_OPLOCK_BREAK_HE)
return true;
@@ -9595,9 +9687,13 @@ int smb3_check_sign_req(struct ksmbd_work *work)
} else {
chann = lookup_chann_list(work->sess, conn);
if (!chann) {
return 0;
if (le16_to_cpu(hdr->Command) != SMB2_SESSION_SETUP_HE ||
!(hdr->Flags & SMB2_FLAGS_SIGNED))
return 0;
signing_key = work->sess->smb3signingkey;
} else {
signing_key = chann->smb3signingkey;
}
signing_key = chann->smb3signingkey;
}
if (!signing_key) {
@@ -9632,13 +9728,14 @@ void smb3_set_sign_rsp(struct ksmbd_work *work)
struct channel *chann;
char signature[SMB2_CMACAES_SIZE];
struct kvec *iov;
u16 command = conn->ops->get_cmd_val(work);
int n_vec = 1;
char *signing_key;
hdr = ksmbd_resp_buf_curr(work);
if (conn->binding == false &&
le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
if (command == SMB2_SESSION_SETUP_HE &&
(!conn->binding || hdr->Status != STATUS_SUCCESS)) {
signing_key = work->sess->smb3signingkey;
} else {
chann = lookup_chann_list(work->sess, work->conn);

View File

@@ -258,6 +258,7 @@ static int sid_to_id(struct mnt_idmap *idmap,
struct smb_sid *psid, uint sidtype,
struct smb_fattr *fattr)
{
const struct smb_sid *sid_prefix;
int rc = -EINVAL;
/*
@@ -279,6 +280,12 @@ static int sid_to_id(struct mnt_idmap *idmap,
kuid_t uid;
uid_t id;
/* Only the server domain RID has a local uid representation. */
sid_prefix = &server_conf.domain_sid;
if (psid->num_subauth != sid_prefix->num_subauth + 1 ||
compare_sids(psid, sid_prefix))
return -EINVAL;
id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
uid = KUIDT_INIT(id);
uid = from_vfsuid(idmap, &init_user_ns, VFSUIDT_INIT(uid));
@@ -290,6 +297,12 @@ static int sid_to_id(struct mnt_idmap *idmap,
kgid_t gid;
gid_t id;
/* Local gids are represented by S-1-22-2-<gid>. */
sid_prefix = &sid_unix_groups;
if (psid->num_subauth != sid_prefix->num_subauth + 1 ||
compare_sids(psid, sid_prefix))
return -EINVAL;
id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
gid = KGIDT_INIT(id);
gid = from_vfsgid(idmap, &init_user_ns, VFSGIDT_INIT(gid));
@@ -900,9 +913,9 @@ int parse_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd,
rc = sid_to_id(idmap, owner_sid_ptr, SIDOWNER, fattr);
if (rc) {
pr_err("%s: Error %d mapping Owner SID to uid\n",
__func__, rc);
ksmbd_debug(SMB, "Owner SID has no Unix uid mapping\n");
owner_sid_ptr = NULL;
rc = 0;
}
}
@@ -918,9 +931,9 @@ int parse_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd,
}
rc = sid_to_id(idmap, group_sid_ptr, SIDUNIX_GROUP, fattr);
if (rc) {
pr_err("%s: Error %d mapping Group SID to gid\n",
__func__, rc);
ksmbd_debug(SMB, "Group SID has no Unix gid mapping\n");
group_sid_ptr = NULL;
rc = 0;
}
}

View File

@@ -105,6 +105,7 @@ struct ksmbd_file {
__u64 change_time;
__u64 allocation_size;
__u64 itime;
__u64 open_mtime;
bool is_nt_open;
bool attrib_only;