mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
eight ksmbd server fixes
-----BEGIN PGP SIGNATURE-----
iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmpj6jgACgkQiiy9cAdy
T1F7Agv/Q0LNuCs18A0dR8SlNLwbo6lE6RVL3A8TfFKqiqpyigPBf0Ax2VqR/uuH
6rfuwZYLMNOp9P+jgFYPug8+fx2Ya58oLlVtCY+JooASUbwEg7PG/R3oHuZe4tOS
m6m8+DVO82JwGH88dkLXBvyrlkxCWZJtPWlS3s+os/2mGAX8M4hvIiCKGz3PAFmb
Qul3AGlxlSgi7eKuZGMU2OslgRVmMVOrNUgW4LfkDP/c8JjwgdDAuhebJOV2sAKi
qL8GlIk/ZsXbZ9qK2ogQ03dt3WxcikWcqbj4GX/d0191sPRx0XuRRXwhOetTUzR3
7PtcDSk6x94+ut4vpuheEaz4Mx8MiNV73pJzNqPQ5WLbA493PUJdEVPbQE2z+y5j
lPFRRYqNtTDAMKv5ZFCUSKs7gO52/jIgdn+RSJ29tJ2Di4IzmguTGv3Cwmq/yL7s
lhfoo2YM55AVkgeOfSsHXNGB89XQjolGb0S5j5fHCkmtvKt5zoWVTp8eoHgG7jih
l7h1AR1X
=7btg
-----END PGP SIGNATURE-----
Merge tag 'v7.2-rc4-smb3-server-fixes' of git://git.samba.org/ksmbd
Pull smb server fixes from Steve French:
"This contains eight ksmbd fixes covering POSIX ACL handling, SMB
signing enforcement, DACL parsing and construction hardening, session
lifetime handling, and validation of malformed transform and
compressed SMB2 requests:
- preserve inherited POSIX ACL mask when creating objects.
- enforce the session signing requirement for plaintext SMB requests.
- harden DACL/ACE processing against size overflows, incomplete ACE
copies, and undersized SIDs.
- defer teardown of a previous session until NTLM authentication
succeeds.
- reject undersized encryption-transform and decompressed SMB2
requests before they can reach normal SMB2 request processing"
* tag 'v7.2-rc4-smb3-server-fixes' of git://git.samba.org/ksmbd:
ksmbd: reject undersized decompressed SMB2 requests
ksmbd: validate minimum PDU size for transform requests
ksmbd: defer destroy_previous_session() until after NTLM authentication
ksmbd: validate ACE size against SID sub-authorities
ksmbd: restore DACL size on check_add_overflow() to avoid malformed ACL
ksmbd: bound DACL dedup walk to copied ACEs
ksmbd: enforce signing required by the session
ksmbd: preserve VFS inherited POSIX ACL mask
This commit is contained in:
commit
8e371eff3f
|
|
@ -56,7 +56,8 @@ int ksmbd_decompress_request(struct ksmbd_conn *conn)
|
|||
}
|
||||
|
||||
max_allowed_pdu_size = SMB3_MAX_MSGSIZE + conn->vals->max_write_size;
|
||||
if (out_size > max_allowed_pdu_size ||
|
||||
if (out_size < sizeof(struct smb2_pdu) ||
|
||||
out_size > max_allowed_pdu_size ||
|
||||
out_size > MAX_STREAM_PROT_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
|||
|
|
@ -441,6 +441,8 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
|
|||
/* "+2" for BCC field (ByteCount, 2 bytes) */
|
||||
#define SMB1_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb_hdr) + 2)
|
||||
#define SMB2_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb2_pdu))
|
||||
#define SMB2_TRANSFORM_MIN_SUPPORTED_PDU_SIZE \
|
||||
(sizeof(struct smb2_transform_hdr) + sizeof(struct smb2_hdr))
|
||||
|
||||
/**
|
||||
* ksmbd_conn_handler_loop() - session thread to listen on new smb requests
|
||||
|
|
@ -455,6 +457,7 @@ int ksmbd_conn_handler_loop(void *p)
|
|||
struct ksmbd_conn *conn = (struct ksmbd_conn *)p;
|
||||
struct ksmbd_transport *t = conn->transport;
|
||||
unsigned int pdu_size, max_allowed_pdu_size, max_req;
|
||||
__le32 proto;
|
||||
char hdr_buf[4] = {0,};
|
||||
int size;
|
||||
|
||||
|
|
@ -546,11 +549,14 @@ int ksmbd_conn_handler_loop(void *p)
|
|||
if (!ksmbd_smb_request(conn))
|
||||
break;
|
||||
|
||||
if (((struct smb2_hdr *)smb_get_msg(conn->request_buf))->ProtocolId ==
|
||||
SMB2_PROTO_NUMBER) {
|
||||
if (pdu_size < SMB2_MIN_SUPPORTED_PDU_SIZE)
|
||||
break;
|
||||
}
|
||||
proto = *(__le32 *)smb_get_msg(conn->request_buf);
|
||||
if (proto == SMB2_PROTO_NUMBER &&
|
||||
pdu_size < SMB2_MIN_SUPPORTED_PDU_SIZE)
|
||||
break;
|
||||
|
||||
if (proto == SMB2_TRANSFORM_PROTO_NUM &&
|
||||
pdu_size < SMB2_TRANSFORM_MIN_SUPPORTED_PDU_SIZE)
|
||||
break;
|
||||
|
||||
if (!default_conn_ops.process_fn) {
|
||||
pr_err("No connection request callback\n");
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ static int __process_request(struct ksmbd_work *work, struct ksmbd_conn *conn,
|
|||
{
|
||||
struct smb_version_cmds *cmds;
|
||||
u16 command;
|
||||
bool signed_req;
|
||||
int ret;
|
||||
|
||||
if (check_conn_state(work))
|
||||
|
|
@ -138,7 +139,14 @@ static int __process_request(struct ksmbd_work *work, struct ksmbd_conn *conn,
|
|||
return SERVER_HANDLER_ABORT;
|
||||
}
|
||||
|
||||
if (work->sess && conn->ops->is_sign_req(work, command)) {
|
||||
signed_req = conn->ops->is_sign_req && conn->ops->is_sign_req(work, command);
|
||||
if (work->sess && work->sess->sign && !work->encrypted &&
|
||||
!signed_req) {
|
||||
conn->ops->set_rsp_status(work, STATUS_ACCESS_DENIED);
|
||||
return SERVER_HANDLER_ABORT;
|
||||
}
|
||||
|
||||
if (work->sess && signed_req) {
|
||||
ret = conn->ops->check_sign_req(work);
|
||||
if (!ret) {
|
||||
conn->ops->set_rsp_status(work, STATUS_ACCESS_DENIED);
|
||||
|
|
|
|||
|
|
@ -1717,11 +1717,6 @@ static int ntlm_authenticate(struct ksmbd_work *work,
|
|||
return -EPERM;
|
||||
}
|
||||
|
||||
/* Check for previous session */
|
||||
prev_id = le64_to_cpu(req->PreviousSessionId);
|
||||
if (prev_id && prev_id != sess->id)
|
||||
destroy_previous_session(conn, user, prev_id);
|
||||
|
||||
if (sess->state == SMB2_SESSION_VALID) {
|
||||
/*
|
||||
* Reuse session if anonymous try to connect
|
||||
|
|
@ -1761,6 +1756,10 @@ static int ntlm_authenticate(struct ksmbd_work *work,
|
|||
}
|
||||
}
|
||||
|
||||
prev_id = le64_to_cpu(req->PreviousSessionId);
|
||||
if (prev_id && prev_id != sess->id)
|
||||
destroy_previous_session(conn, sess->user, prev_id);
|
||||
|
||||
/*
|
||||
* If session state is SMB2_SESSION_VALID, We can assume
|
||||
* that it is reauthentication. And the user/password
|
||||
|
|
@ -9596,8 +9595,7 @@ bool smb2_is_sign_req(struct ksmbd_work *work, unsigned int command)
|
|||
struct smb2_hdr *rcv_hdr2 = smb_get_msg(work->request_buf);
|
||||
|
||||
if ((rcv_hdr2->Flags & SMB2_FLAGS_SIGNED) &&
|
||||
command != SMB2_NEGOTIATE_HE &&
|
||||
command != SMB2_OPLOCK_BREAK_HE)
|
||||
command != SMB2_NEGOTIATE_HE)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -608,7 +608,8 @@ static void parse_dacl(struct mnt_idmap *idmap,
|
|||
static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
|
||||
struct smb_ace *pndace,
|
||||
struct smb_fattr *fattr, u16 *num_aces,
|
||||
u16 *size, u32 nt_aces_num)
|
||||
u16 *size, u16 existing_nt_aces,
|
||||
bool had_nt_aces)
|
||||
{
|
||||
struct posix_acl_entry *pace;
|
||||
struct smb_sid *sid;
|
||||
|
|
@ -640,14 +641,14 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
|
|||
|
||||
gid = posix_acl_gid_translate(idmap, pace);
|
||||
id_to_sid(gid, SIDUNIX_GROUP, sid);
|
||||
} else if (pace->e_tag == ACL_OTHER && !nt_aces_num) {
|
||||
} else if (pace->e_tag == ACL_OTHER && !had_nt_aces) {
|
||||
smb_copy_sid(sid, &sid_everyone);
|
||||
} else {
|
||||
kfree(sid);
|
||||
continue;
|
||||
}
|
||||
ntace = pndace;
|
||||
for (j = 0; j < nt_aces_num; j++) {
|
||||
for (j = 0; j < existing_nt_aces; j++) {
|
||||
if (ntace->sid.sub_auth[ntace->sid.num_subauth - 1] ==
|
||||
sid->sub_auth[sid->num_subauth - 1])
|
||||
goto pass_same_sid;
|
||||
|
|
@ -662,6 +663,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
|
|||
ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags,
|
||||
pace->e_perm, 0777);
|
||||
if (check_add_overflow(*size, ace_sz, size)) {
|
||||
*size -= ace_sz;
|
||||
kfree(sid);
|
||||
break;
|
||||
}
|
||||
|
|
@ -676,6 +678,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
|
|||
ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED,
|
||||
0x03, pace->e_perm, 0777);
|
||||
if (check_add_overflow(*size, ace_sz, size)) {
|
||||
*size -= ace_sz;
|
||||
kfree(sid);
|
||||
break;
|
||||
}
|
||||
|
|
@ -689,7 +692,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
|
|||
kfree(sid);
|
||||
}
|
||||
|
||||
if (nt_aces_num)
|
||||
if (had_nt_aces)
|
||||
return;
|
||||
|
||||
posix_default_acl:
|
||||
|
|
@ -721,6 +724,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
|
|||
ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b,
|
||||
pace->e_perm, 0777);
|
||||
if (check_add_overflow(*size, ace_sz, size)) {
|
||||
*size -= ace_sz;
|
||||
kfree(sid);
|
||||
break;
|
||||
}
|
||||
|
|
@ -742,6 +746,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
|
|||
{
|
||||
struct smb_ace *ntace, *pndace;
|
||||
u16 nt_num_aces = le16_to_cpu(nt_dacl->num_aces), num_aces = 0;
|
||||
u16 copied_nt_aces;
|
||||
unsigned short size = 0;
|
||||
int i;
|
||||
|
||||
|
|
@ -751,20 +756,29 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
|
|||
for (i = 0; i < nt_num_aces; i++) {
|
||||
unsigned short nt_ace_size;
|
||||
|
||||
if (offsetof(struct smb_ace, access_req) > aces_size)
|
||||
if (aces_size < offsetof(struct smb_ace, sid) +
|
||||
CIFS_SID_BASE_SIZE)
|
||||
break;
|
||||
|
||||
nt_ace_size = le16_to_cpu(ntace->size);
|
||||
if (nt_ace_size > aces_size)
|
||||
if (nt_ace_size > aces_size ||
|
||||
nt_ace_size < offsetof(struct smb_ace, sid) +
|
||||
CIFS_SID_BASE_SIZE)
|
||||
break;
|
||||
|
||||
if (ntace->sid.num_subauth == 0 ||
|
||||
ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES)
|
||||
ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
|
||||
nt_ace_size < offsetof(struct smb_ace, sid) +
|
||||
CIFS_SID_BASE_SIZE +
|
||||
sizeof(__le32) *
|
||||
ntace->sid.num_subauth)
|
||||
goto next_ace;
|
||||
|
||||
memcpy((char *)pndace + size, ntace, nt_ace_size);
|
||||
if (check_add_overflow(size, nt_ace_size, &size))
|
||||
if (check_add_overflow(size, nt_ace_size, &size)) {
|
||||
size -= nt_ace_size;
|
||||
break;
|
||||
}
|
||||
num_aces++;
|
||||
|
||||
next_ace:
|
||||
|
|
@ -773,8 +787,10 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
|
|||
}
|
||||
}
|
||||
|
||||
copied_nt_aces = num_aces;
|
||||
set_posix_acl_entries_dacl(idmap, pndace, fattr,
|
||||
&num_aces, &size, nt_num_aces);
|
||||
&num_aces, &size, copied_nt_aces,
|
||||
nt_num_aces != 0);
|
||||
pndacl->num_aces = cpu_to_le16(num_aces);
|
||||
pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
|
||||
}
|
||||
|
|
@ -792,7 +808,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap,
|
|||
|
||||
if (fattr->cf_acls) {
|
||||
set_posix_acl_entries_dacl(idmap, pndace, fattr,
|
||||
&num_aces, &size, num_aces);
|
||||
&num_aces, &size, num_aces, false);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1886,10 +1886,6 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
|
|||
const struct path *path, struct inode *parent_inode)
|
||||
{
|
||||
struct posix_acl *acls;
|
||||
struct posix_acl_entry *pace;
|
||||
struct dentry *dentry = path->dentry;
|
||||
struct inode *inode = d_inode(dentry);
|
||||
int rc, i;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_FS_POSIX_ACL))
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -1897,29 +1893,9 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
|
|||
acls = get_inode_acl(parent_inode, ACL_TYPE_DEFAULT);
|
||||
if (IS_ERR_OR_NULL(acls))
|
||||
return -ENOENT;
|
||||
pace = acls->a_entries;
|
||||
|
||||
for (i = 0; i < acls->a_count; i++, pace++) {
|
||||
if (pace->e_tag == ACL_MASK) {
|
||||
pace->e_perm = 0x07;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = set_posix_acl(idmap, dentry, ACL_TYPE_ACCESS, acls);
|
||||
if (rc < 0)
|
||||
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",
|
||||
rc);
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
rc = set_posix_acl(idmap, dentry, ACL_TYPE_DEFAULT,
|
||||
acls);
|
||||
if (rc < 0)
|
||||
ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",
|
||||
rc);
|
||||
}
|
||||
|
||||
posix_acl_release(acls);
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ksmbd_vfs_update_compressed_fattr(struct dentry *dentry, __le32 *fattr)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user