mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 12:34:02 +02:00
- Prevent unintended data exposure by clearing pipe compound padding and
the response buffer.
- Initialize missing fields in FS_OBJECT_ID_INFORMATION,
FS_CONTROL_INFORMATION, and FS_POSIX_INFORMATION.
- Propagate DACL parsing and allocation failures so malformed security
descriptors are rejected.
- Rate-limit errors for unmapped SIDs to prevent kernel log flooding.
- Drain multichannel sessions during LOGOFF, wake deferred locks and
cancellable requests, and ensure cancellation callbacks run only once.
- Fix listener kthread reference handling and teardown ordering during
netdevice events.
- Validate normalized-name and IPC share configuration response lengths.
- Update the KSMBD MAINTAINERS entry and add Paulo Alcantara as
an SMBDIRECT co-maintainer.
-----BEGIN PGP SIGNATURE-----
iQJKBAABCgA0FiEE6NzKS6Uv/XAAGHgyZwv7A1FEIQgFAmqWnz0WHGxpbmtpbmpl
b25Aa2VybmVsLm9yZwAKCRBnC/sDUUQhCJK8EACCE2K2p9CH6kiy9VnMjEqTbIBF
ZRCmxrspoPAMuTbK6529dXHUVTsXlUdJ/FVzGwNLtvXwEIVjNaQDqBEFWCdPElE+
8grKsC1S3gH3t8Z1wT6eNh5cpDoA+rWJDbNK4DsmHdoVagyjd9dd7fkMi7nq0WJS
NO7BTHaTuTaZDul8UXc1gqkVLviZZWkrtkGVVnsJV1z5cFls6P81cVmtzP0836cU
kVDYSI0EZnX+1P5CtOxL3r5LDBex6lRHU+rj1ypJRJDM2nR+bYIeJk+XMjylKCHT
liPj7dwI/ptVzp+n3dbcTyhLZayDhZ0/GeJanX2/midtiNSKhao9h94BymPU91jV
JugPlkAO8Vqwo7xojWRqudz4Kg/vgr66NexQ/3W2tuRXXFN4kEWmQG0N5+kH0K3d
sJ5xA9uLj24+d29fjylkdSGpuRLR8XcR01he2CaqLRopXZrCxFChwzZwbads1rI/
kXtYrORB0u99ScwTRQeW90dzeZ+1R3aHOyf8H86zyJ07l2NxG8t5L/49vuaiaiEZ
5r4hhPVumlmDQdPoOcugOmkJL68+W4TzS7UfcOSgq43W31BE1dYsaX7u4MHNk/Nq
UiWJJPArJ3ry8e4GLqQXx4ylZJnykGS9s676gFCO1GAI+eXoQ4R0k7RCKy/TW0ap
t3oa0Yj+Y4QAZCD3Rw==
=UL/J
-----END PGP SIGNATURE-----
Merge tag 'ksmbd-for-7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/smb
Pull smb server fixes from Namjae Jeon:
- Prevent unintended data exposure by clearing pipe compound padding
and the response buffer
- Initialize missing fields in FS_OBJECT_ID_INFORMATION,
FS_CONTROL_INFORMATION, and FS_POSIX_INFORMATION
- Propagate DACL parsing and allocation failures so malformed security
descriptors are rejected
- Rate-limit errors for unmapped SIDs to prevent kernel log flooding
- Drain multichannel sessions during LOGOFF, wake deferred locks and
cancellable requests, and ensure cancellation callbacks run only once
- Fix listener kthread reference handling and teardown ordering during
netdevice events
- Validate normalized-name and IPC share configuration response lengths
- Update the KSMBD MAINTAINERS entry and add Paulo Alcantara as an
SMBDIRECT co-maintainer
* tag 'ksmbd-for-7.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/smb:
ksmbd: validate normalized name response length
ksmbd: fix listener task lifetime on netdev events
ksmbd: prevent out-of-bounds reads in share config responses
ksmbd: rate limit unmapped SID errors
ksmbd: propagate DACL parsing errors
ksmbd: zero pipe read compound padding
ksmbd: safely drain sessions during logoff
MAINTAINERS: Update the KSMBD entry
MAINTAINERS: Add Paulo Alcantara as an SMBDIRECT co-maintainer
ksmbd: fill in FileSysIdentifier in FS_POSIX_INFORMATION
ksmbd: initialize FileSystemControlFlags in FS_CONTROL_INFORMATION
ksmbd: zero the FS_OBJECT_ID_INFORMATION buffer before filling it in
This commit is contained in:
commit
9a58da8005
|
|
@ -14236,8 +14236,6 @@ F: tools/testing/selftests/
|
|||
KERNEL SMB3 SERVER (KSMBD)
|
||||
M: Namjae Jeon <linkinjeon@kernel.org>
|
||||
M: Namjae Jeon <linkinjeon@samba.org>
|
||||
M: Steve French <smfrench@gmail.com>
|
||||
M: Steve French <sfrench@samba.org>
|
||||
R: Sergey Senozhatsky <senozhatsky@chromium.org>
|
||||
R: Tom Talpey <tom@talpey.com>
|
||||
R: ChenXiaoSong <chenxiaosong@chenxiaosong.com>
|
||||
|
|
@ -25232,10 +25230,9 @@ F: Documentation/admin-guide/LSM/Smack.rst
|
|||
F: security/smack/
|
||||
|
||||
SMBDIRECT (RDMA Stream Transport with Read/Write-Offload, MS-SMBD)
|
||||
M: Steve French <smfrench@gmail.com>
|
||||
M: Steve French <sfrench@samba.org>
|
||||
M: Namjae Jeon <linkinjeon@kernel.org>
|
||||
M: Namjae Jeon <linkinjeon@samba.org>
|
||||
M: Paulo Alcantara <pc@manguebit.org>
|
||||
R: Stefan Metzmacher <metze@samba.org>
|
||||
R: Tom Talpey <tom@talpey.com>
|
||||
L: linux-cifs@vger.kernel.org
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "mgmt/ksmbd_ida.h"
|
||||
#include "mgmt/user_session.h"
|
||||
#include "connection.h"
|
||||
#include "vfs_cache.h"
|
||||
#include "compress.h"
|
||||
#include "transport_tcp.h"
|
||||
#include "transport_rdma.h"
|
||||
|
|
@ -384,12 +385,12 @@ static void ksmbd_conn_cancel_async_requests(struct ksmbd_conn *conn)
|
|||
spin_lock(&conn->request_lock);
|
||||
list_for_each_entry_safe(work, tmp, &conn->async_requests,
|
||||
async_request_entry) {
|
||||
if (work->state != KSMBD_WORK_ACTIVE)
|
||||
if (cmpxchg(&work->state, KSMBD_WORK_ACTIVE,
|
||||
KSMBD_WORK_CANCELLED) != KSMBD_WORK_ACTIVE)
|
||||
continue;
|
||||
|
||||
ksmbd_debug(CONN, "Cancel async request id %d\n",
|
||||
work->async_id);
|
||||
work->state = KSMBD_WORK_CANCELLED;
|
||||
if (work->cancel_fn)
|
||||
work->cancel_fn(work->cancel_argv);
|
||||
}
|
||||
|
|
@ -473,6 +474,9 @@ int ksmbd_conn_wait_idle_sess(struct ksmbd_conn *curr_conn,
|
|||
if (retry_count >= max_timeout)
|
||||
return -EIO;
|
||||
|
||||
/* A blocked byte-range lock cannot drain until teardown wakes it. */
|
||||
ksmbd_wake_session_blocked_works(sess);
|
||||
|
||||
down_read(&conn_list_lock);
|
||||
hash_for_each(conn_list, bkt, conn, hlist) {
|
||||
if (ksmbd_session_is_bound_to_conn(sess, conn)) {
|
||||
|
|
|
|||
|
|
@ -146,9 +146,9 @@ static struct ksmbd_share_config *__share_lookup(const char *name)
|
|||
|
||||
static int parse_veto_list(struct ksmbd_share_config *share,
|
||||
char *veto_list,
|
||||
int veto_list_sz)
|
||||
size_t veto_list_sz)
|
||||
{
|
||||
int sz = 0;
|
||||
size_t sz;
|
||||
|
||||
if (!veto_list_sz)
|
||||
return 0;
|
||||
|
|
@ -156,7 +156,7 @@ static int parse_veto_list(struct ksmbd_share_config *share,
|
|||
while (veto_list_sz > 0) {
|
||||
struct ksmbd_veto_pattern *p;
|
||||
|
||||
sz = strlen(veto_list);
|
||||
sz = strnlen(veto_list, veto_list_sz);
|
||||
if (!sz)
|
||||
break;
|
||||
|
||||
|
|
@ -164,7 +164,7 @@ static int parse_veto_list(struct ksmbd_share_config *share,
|
|||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
p->pattern = kstrdup(veto_list, KSMBD_DEFAULT_GFP);
|
||||
p->pattern = kstrndup(veto_list, sz, KSMBD_DEFAULT_GFP);
|
||||
if (!p->pattern) {
|
||||
kfree(p);
|
||||
return -ENOMEM;
|
||||
|
|
@ -172,6 +172,9 @@ static int parse_veto_list(struct ksmbd_share_config *share,
|
|||
|
||||
list_add(&p->list, &share->veto_list);
|
||||
|
||||
if (sz == veto_list_sz)
|
||||
break;
|
||||
|
||||
veto_list += sz + 1;
|
||||
veto_list_sz -= (sz + 1);
|
||||
}
|
||||
|
|
@ -224,17 +227,28 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work,
|
|||
}
|
||||
|
||||
if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
|
||||
int path_len = PATH_MAX;
|
||||
size_t path_len;
|
||||
|
||||
if (resp->payload_sz)
|
||||
path_len = resp->payload_sz - resp->veto_list_sz;
|
||||
|
||||
share->path = kstrndup(ksmbd_share_config_path(resp), path_len,
|
||||
KSMBD_DEFAULT_GFP);
|
||||
if (!share->path) {
|
||||
ret = -ENOMEM;
|
||||
if (resp->payload_sz <= resp->veto_list_sz) {
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
ret = 0;
|
||||
path_len = resp->payload_sz - resp->veto_list_sz;
|
||||
if (resp->veto_list_sz)
|
||||
path_len--;
|
||||
|
||||
if (!path_len) {
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
share->path = kstrndup(
|
||||
ksmbd_share_config_path(resp),
|
||||
path_len, KSMBD_DEFAULT_GFP);
|
||||
if (!share->path)
|
||||
ret = -ENOMEM;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
if (share->path) {
|
||||
share->path_sz = strlen(share->path);
|
||||
while (share->path_sz > 1 &&
|
||||
share->path[share->path_sz - 1] == '/')
|
||||
|
|
|
|||
|
|
@ -666,10 +666,21 @@ void destroy_previous_session(struct ksmbd_conn *conn,
|
|||
memcmp(user->passkey, prev_user->passkey, user->passkey_sz))
|
||||
goto out;
|
||||
|
||||
down_write(&prev_sess->chann_lock);
|
||||
if (prev_sess->tearing_down) {
|
||||
up_write(&prev_sess->chann_lock);
|
||||
goto out;
|
||||
}
|
||||
prev_sess->tearing_down = true;
|
||||
up_write(&prev_sess->chann_lock);
|
||||
|
||||
ksmbd_all_conn_set_status(prev_sess, KSMBD_SESS_NEED_RECONNECT);
|
||||
err = ksmbd_conn_wait_idle_sess(conn, prev_sess);
|
||||
if (err) {
|
||||
ksmbd_all_conn_set_status(prev_sess, KSMBD_SESS_NEED_SETUP);
|
||||
down_write(&prev_sess->chann_lock);
|
||||
prev_sess->tearing_down = false;
|
||||
up_write(&prev_sess->chann_lock);
|
||||
ksmbd_all_conn_set_status(prev_sess, KSMBD_SESS_GOOD);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ struct ksmbd_session {
|
|||
|
||||
bool sign;
|
||||
bool enc;
|
||||
bool tearing_down;
|
||||
|
||||
int state;
|
||||
__u8 *Preauth_HashValue;
|
||||
|
|
|
|||
|
|
@ -97,6 +97,11 @@ static int register_session_channel(struct ksmbd_session *sess,
|
|||
int rc = 0;
|
||||
|
||||
down_write(&sess->chann_lock);
|
||||
if (sess->tearing_down) {
|
||||
rc = -ESHUTDOWN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (xa_load(&sess->ksmbd_chann_list, (long)conn))
|
||||
goto out;
|
||||
|
||||
|
|
@ -873,7 +878,8 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work)
|
|||
req = smb_get_msg(work->request_buf);
|
||||
if ((req->InfoType == SMB2_O_INFO_FILE &&
|
||||
(req->FileInfoClass == FILE_FULL_EA_INFORMATION ||
|
||||
req->FileInfoClass == FILE_ALL_INFORMATION)) ||
|
||||
req->FileInfoClass == FILE_ALL_INFORMATION ||
|
||||
req->FileInfoClass == FILE_NORMALIZED_NAME_INFORMATION)) ||
|
||||
req->InfoType == SMB2_O_INFO_SECURITY)
|
||||
sz = large_sz;
|
||||
}
|
||||
|
|
@ -3086,17 +3092,41 @@ int smb2_session_logoff(struct ksmbd_work *work)
|
|||
smb2_set_err_rsp(work);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
down_write(&sess->chann_lock);
|
||||
if (sess->tearing_down) {
|
||||
up_write(&sess->chann_lock);
|
||||
ksmbd_conn_unlock(conn);
|
||||
rsp->hdr.Status = STATUS_USER_SESSION_DELETED;
|
||||
smb2_set_err_rsp(work);
|
||||
return -ENOENT;
|
||||
}
|
||||
sess->tearing_down = true;
|
||||
up_write(&sess->chann_lock);
|
||||
|
||||
ksmbd_all_conn_set_status(sess, KSMBD_SESS_NEED_RECONNECT);
|
||||
ksmbd_conn_unlock(conn);
|
||||
|
||||
err = ksmbd_conn_wait_idle_sess(conn, sess);
|
||||
if (err) {
|
||||
down_write(&sess->chann_lock);
|
||||
sess->tearing_down = false;
|
||||
up_write(&sess->chann_lock);
|
||||
ksmbd_all_conn_set_status(sess, KSMBD_SESS_GOOD);
|
||||
rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;
|
||||
smb2_set_err_rsp(work);
|
||||
return err;
|
||||
}
|
||||
|
||||
ksmbd_close_session_fds(work);
|
||||
ksmbd_conn_wait_idle(conn);
|
||||
|
||||
if (ksmbd_tree_conn_session_logoff(sess)) {
|
||||
ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
|
||||
rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
|
||||
smb2_set_err_rsp(work);
|
||||
return -ENOENT;
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
err = 0;
|
||||
}
|
||||
|
||||
down_write(&conn->session_lock);
|
||||
|
|
@ -3106,6 +3136,9 @@ int smb2_session_logoff(struct ksmbd_work *work)
|
|||
|
||||
ksmbd_all_conn_set_status(sess, KSMBD_SESS_NEED_SETUP);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
rsp->StructureSize = cpu_to_le16(4);
|
||||
err = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_logoff_rsp));
|
||||
if (err) {
|
||||
|
|
@ -6757,7 +6790,7 @@ static int get_file_normalized_name_info(struct ksmbd_work *work,
|
|||
{
|
||||
struct smb2_file_alt_name_info *file_info;
|
||||
char *filename, *normalized, *stream_name;
|
||||
int conv_len, filename_len;
|
||||
int buf_free_len, conv_len, filename_len;
|
||||
|
||||
if (work->conn->dialect < SMB311_PROT_ID) {
|
||||
rsp->hdr.Status = STATUS_NOT_SUPPORTED;
|
||||
|
|
@ -6781,6 +6814,14 @@ static int get_file_normalized_name_info(struct ksmbd_work *work,
|
|||
return -ENOMEM;
|
||||
|
||||
filename_len = strlen(normalized);
|
||||
buf_free_len = smb2_resp_buf_len(work, sizeof(*rsp) +
|
||||
sizeof(*file_info));
|
||||
if (buf_free_len < 0 ||
|
||||
(size_t)buf_free_len < (filename_len + 1) * sizeof(__le16)) {
|
||||
kfree(normalized);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
file_info = (struct smb2_file_alt_name_info *)rsp->Buffer;
|
||||
conv_len = smbConvertToUTF16((__le16 *)file_info->FileName,
|
||||
normalized, filename_len,
|
||||
|
|
@ -7444,6 +7485,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
struct object_id_info *info;
|
||||
|
||||
info = (struct object_id_info *)(rsp->Buffer);
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
if (path.mnt->mnt_sb->s_uuid_len == 16)
|
||||
memcpy(info->objid, path.mnt->mnt_sb->s_uuid.b,
|
||||
|
|
@ -7499,6 +7541,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
info->FreeSpaceStopFiltering = 0;
|
||||
info->DefaultQuotaThreshold = cpu_to_le64(SMB2_NO_FID);
|
||||
info->DefaultQuotaLimit = cpu_to_le64(SMB2_NO_FID);
|
||||
info->FileSystemControlFlags = 0;
|
||||
info->Padding = 0;
|
||||
rsp->OutputBufferLength = cpu_to_le32(48);
|
||||
fixed_len = 48;
|
||||
|
|
@ -7521,6 +7564,9 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
info->UserBlocksAvail = cpu_to_le64(stfs.f_bavail);
|
||||
info->TotalFileNodes = cpu_to_le64(stfs.f_files);
|
||||
info->FreeFileNodes = cpu_to_le64(stfs.f_ffree);
|
||||
info->FileSysIdentifier =
|
||||
cpu_to_le64((u64)(u32)stfs.f_fsid.val[1] << 32 |
|
||||
(u32)stfs.f_fsid.val[0]);
|
||||
rsp->OutputBufferLength = cpu_to_le32(56);
|
||||
fixed_len = 56;
|
||||
}
|
||||
|
|
@ -8620,13 +8666,18 @@ static noinline int smb2_read_pipe(struct ksmbd_work *work)
|
|||
}
|
||||
|
||||
aux_payload_buf =
|
||||
kvmalloc(rpc_resp->payload_sz, KSMBD_DEFAULT_GFP);
|
||||
kvmalloc(ALIGN(rpc_resp->payload_sz, 8),
|
||||
KSMBD_DEFAULT_GFP);
|
||||
if (!aux_payload_buf) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(aux_payload_buf, rpc_resp->payload, rpc_resp->payload_sz);
|
||||
if (rpc_resp->payload_sz & 7)
|
||||
memset(aux_payload_buf + rpc_resp->payload_sz, 0,
|
||||
ALIGN(rpc_resp->payload_sz, 8) -
|
||||
rpc_resp->payload_sz);
|
||||
|
||||
nbytes = rpc_resp->payload_sz;
|
||||
err = ksmbd_iov_pin_rsp_read(work, (void *)rsp,
|
||||
|
|
@ -9680,14 +9731,14 @@ int smb2_cancel(struct ksmbd_work *work)
|
|||
* still on conn->async_requests with a live cancel_fn
|
||||
* pointing at the freed file_lock.
|
||||
*/
|
||||
if (iter->state != KSMBD_WORK_ACTIVE)
|
||||
if (cmpxchg(&iter->state, KSMBD_WORK_ACTIVE,
|
||||
KSMBD_WORK_CANCELLED) != KSMBD_WORK_ACTIVE)
|
||||
break;
|
||||
|
||||
ksmbd_debug(SMB,
|
||||
"smb2 with AsyncId %llu cancelled command = 0x%x\n",
|
||||
le64_to_cpu(hdr->Id.AsyncId),
|
||||
le16_to_cpu(chdr->Command));
|
||||
iter->state = KSMBD_WORK_CANCELLED;
|
||||
if (iter->cancel_fn == smb2_notify_cancel_fn)
|
||||
cancelled_notify =
|
||||
smb2_notify_cancel_claim(iter->cancel_argv);
|
||||
|
|
@ -9716,11 +9767,16 @@ int smb2_cancel(struct ksmbd_work *work)
|
|||
iter == work)
|
||||
continue;
|
||||
|
||||
if (cmpxchg(&iter->state, KSMBD_WORK_ACTIVE,
|
||||
KSMBD_WORK_CANCELLED) != KSMBD_WORK_ACTIVE)
|
||||
break;
|
||||
|
||||
ksmbd_debug(SMB,
|
||||
"smb2 with mid %llu cancelled command = 0x%x\n",
|
||||
le64_to_cpu(hdr->MessageId),
|
||||
le16_to_cpu(chdr->Command));
|
||||
iter->state = KSMBD_WORK_CANCELLED;
|
||||
if (iter->cancel_fn)
|
||||
iter->cancel_fn(iter->cancel_argv);
|
||||
break;
|
||||
}
|
||||
spin_unlock(&conn->request_lock);
|
||||
|
|
|
|||
|
|
@ -383,10 +383,10 @@ void free_acl_state(struct posix_acl_state *state)
|
|||
kfree(state->groups);
|
||||
}
|
||||
|
||||
static void parse_dacl(struct mnt_idmap *idmap,
|
||||
struct smb_acl *pdacl, char *end_of_acl,
|
||||
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
|
||||
struct smb_fattr *fattr)
|
||||
static int parse_dacl(struct mnt_idmap *idmap,
|
||||
struct smb_acl *pdacl, char *end_of_acl,
|
||||
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
|
||||
struct smb_fattr *fattr)
|
||||
{
|
||||
int i, ret;
|
||||
u16 num_aces = 0;
|
||||
|
|
@ -400,13 +400,13 @@ static void parse_dacl(struct mnt_idmap *idmap,
|
|||
bool owner_found = false, group_found = false, others_found = false;
|
||||
|
||||
if (!pdacl)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
/* validate that we do not go past end of acl */
|
||||
if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) ||
|
||||
end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
|
||||
pr_err("ACL too small to parse DACL\n");
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ksmbd_debug(SMB, "DACL revision %d size %d num aces %d\n",
|
||||
|
|
@ -418,31 +418,31 @@ static void parse_dacl(struct mnt_idmap *idmap,
|
|||
|
||||
num_aces = le16_to_cpu(pdacl->num_aces);
|
||||
if (num_aces <= 0)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
dacl_size = le16_to_cpu(pdacl->size);
|
||||
if (dacl_size < sizeof(struct smb_acl))
|
||||
return;
|
||||
return -EINVAL;
|
||||
|
||||
if (num_aces > (dacl_size - sizeof(struct smb_acl)) /
|
||||
(offsetof(struct smb_ace, sid) +
|
||||
offsetof(struct smb_sid, sub_auth) + sizeof(__le16)))
|
||||
return;
|
||||
return -EINVAL;
|
||||
|
||||
ret = init_acl_state(&acl_state, num_aces);
|
||||
if (ret)
|
||||
return;
|
||||
return ret;
|
||||
ret = init_acl_state(&default_acl_state, num_aces);
|
||||
if (ret) {
|
||||
free_acl_state(&acl_state);
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ppace = kmalloc_objs(struct smb_ace *, num_aces, KSMBD_DEFAULT_GFP);
|
||||
if (!ppace) {
|
||||
free_acl_state(&default_acl_state);
|
||||
free_acl_state(&acl_state);
|
||||
return;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -451,8 +451,10 @@ static void parse_dacl(struct mnt_idmap *idmap,
|
|||
* user/group/other have no permissions
|
||||
*/
|
||||
for (i = 0; i < num_aces; ++i) {
|
||||
if (end_of_acl - acl_base < acl_size)
|
||||
break;
|
||||
if (end_of_acl - acl_base < acl_size) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ppace[i] = (struct smb_ace *)(acl_base + acl_size);
|
||||
acl_base = (char *)ppace[i];
|
||||
|
|
@ -465,8 +467,10 @@ static void parse_dacl(struct mnt_idmap *idmap,
|
|||
(end_of_acl - acl_base <
|
||||
acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) ||
|
||||
(le16_to_cpu(ppace[i]->size) <
|
||||
acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth))
|
||||
break;
|
||||
acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
acl_size = le16_to_cpu(ppace[i]->size);
|
||||
ppace[i]->access_req =
|
||||
|
|
@ -524,8 +528,8 @@ static void parse_dacl(struct mnt_idmap *idmap,
|
|||
temp_fattr.cf_uid = INVALID_UID;
|
||||
ret = sid_to_id(idmap, &ppace[i]->sid, SIDOWNER, &temp_fattr);
|
||||
if (ret || uid_eq(temp_fattr.cf_uid, INVALID_UID)) {
|
||||
pr_err("%s: Error %d mapping Owner SID to uid\n",
|
||||
__func__, ret);
|
||||
pr_err_ratelimited("%s: Error %d mapping Owner SID to uid\n",
|
||||
__func__, ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -541,7 +545,6 @@ static void parse_dacl(struct mnt_idmap *idmap,
|
|||
((acl_mode & 0700) >> 6) | 0004;
|
||||
}
|
||||
}
|
||||
kfree(ppace);
|
||||
|
||||
if (owner_found) {
|
||||
/* The owner must be set to at least read-only. */
|
||||
|
|
@ -584,10 +587,12 @@ static void parse_dacl(struct mnt_idmap *idmap,
|
|||
fattr->cf_acls =
|
||||
posix_acl_alloc(acl_state.users->n +
|
||||
acl_state.groups->n + 4, KSMBD_DEFAULT_GFP);
|
||||
if (fattr->cf_acls) {
|
||||
cf_pace = fattr->cf_acls->a_entries;
|
||||
posix_state_to_acl(&acl_state, cf_pace);
|
||||
if (!fattr->cf_acls) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
cf_pace = fattr->cf_acls->a_entries;
|
||||
posix_state_to_acl(&acl_state, cf_pace);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -598,14 +603,20 @@ static void parse_dacl(struct mnt_idmap *idmap,
|
|||
fattr->cf_dacls =
|
||||
posix_acl_alloc(default_acl_state.users->n +
|
||||
default_acl_state.groups->n + 4, KSMBD_DEFAULT_GFP);
|
||||
if (fattr->cf_dacls) {
|
||||
cf_pdace = fattr->cf_dacls->a_entries;
|
||||
posix_state_to_acl(&default_acl_state, cf_pdace);
|
||||
if (!fattr->cf_dacls) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
cf_pdace = fattr->cf_dacls->a_entries;
|
||||
posix_state_to_acl(&default_acl_state, cf_pdace);
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
kfree(ppace);
|
||||
free_acl_state(&acl_state);
|
||||
free_acl_state(&default_acl_state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
|
||||
|
|
@ -966,8 +977,10 @@ int parse_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd,
|
|||
if (dacloffset < sizeof(struct smb_ntsd))
|
||||
return -EINVAL;
|
||||
|
||||
parse_dacl(idmap, dacl_ptr, end_of_acl,
|
||||
owner_sid_ptr, group_sid_ptr, fattr);
|
||||
rc = parse_dacl(idmap, dacl_ptr, end_of_acl,
|
||||
owner_sid_ptr, group_sid_ptr, fattr);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -532,14 +532,21 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
|
|||
if (entry->msg_sz < sizeof(struct ksmbd_share_config_response))
|
||||
return -EINVAL;
|
||||
|
||||
if (resp->payload_sz) {
|
||||
if (resp->payload_sz < resp->veto_list_sz)
|
||||
return -EINVAL;
|
||||
if (strnlen(resp->share_name, sizeof(resp->share_name)) ==
|
||||
sizeof(resp->share_name))
|
||||
return -EINVAL;
|
||||
|
||||
if (check_add_overflow(sizeof(struct ksmbd_share_config_response),
|
||||
resp->payload_sz, &msg_sz))
|
||||
return -EINVAL;
|
||||
}
|
||||
if (resp->veto_list_sz > resp->payload_sz)
|
||||
return -EINVAL;
|
||||
|
||||
if (resp->flags != KSMBD_SHARE_FLAG_INVALID &&
|
||||
!(resp->flags & KSMBD_SHARE_FLAG_PIPE) &&
|
||||
resp->payload_sz <= resp->veto_list_sz)
|
||||
return -EINVAL;
|
||||
|
||||
if (check_add_overflow(sizeof(struct ksmbd_share_config_response),
|
||||
resp->payload_sz, &msg_sz))
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
case KSMBD_EVENT_LOGIN_REQUEST_EXT:
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ struct tcp_transport {
|
|||
static const struct ksmbd_transport_ops ksmbd_tcp_transport_ops;
|
||||
|
||||
static void tcp_stop_kthread(struct task_struct *kthread);
|
||||
static void ksmbd_tcp_stop_listener(struct interface *iface);
|
||||
static struct interface *alloc_iface(char *ifname);
|
||||
static void ksmbd_tcp_disconnect(struct ksmbd_transport *t);
|
||||
|
||||
|
|
@ -321,13 +322,20 @@ static int ksmbd_tcp_run_kthread(struct interface *iface)
|
|||
int rc;
|
||||
struct task_struct *kthread;
|
||||
|
||||
kthread = kthread_run(ksmbd_kthread_fn, (void *)iface, "ksmbd-%s",
|
||||
iface->name);
|
||||
kthread = kthread_create(ksmbd_kthread_fn, (void *)iface, "ksmbd-%s",
|
||||
iface->name);
|
||||
if (IS_ERR(kthread)) {
|
||||
rc = PTR_ERR(kthread);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* The listener can exit after its socket is shutdown, so keep the
|
||||
* task_struct alive until the caller has stopped it.
|
||||
*/
|
||||
get_task_struct(kthread);
|
||||
iface->ksmbd_kthread = kthread;
|
||||
wake_up_process(kthread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -598,12 +606,7 @@ 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;
|
||||
sock_release(iface->ksmbd_socket);
|
||||
iface->ksmbd_socket = NULL;
|
||||
|
||||
ksmbd_tcp_stop_listener(iface);
|
||||
iface->state = IFACE_STATE_DOWN;
|
||||
break;
|
||||
}
|
||||
|
|
@ -631,11 +634,25 @@ static void tcp_stop_kthread(struct task_struct *kthread)
|
|||
if (!kthread)
|
||||
return;
|
||||
|
||||
ret = kthread_stop(kthread);
|
||||
ret = kthread_stop_put(kthread);
|
||||
if (ret)
|
||||
pr_err("failed to stop forker thread\n");
|
||||
}
|
||||
|
||||
static void ksmbd_tcp_stop_listener(struct interface *iface)
|
||||
{
|
||||
if (iface->ksmbd_socket)
|
||||
kernel_sock_shutdown(iface->ksmbd_socket, SHUT_RDWR);
|
||||
|
||||
tcp_stop_kthread(iface->ksmbd_kthread);
|
||||
iface->ksmbd_kthread = NULL;
|
||||
|
||||
if (iface->ksmbd_socket) {
|
||||
sock_release(iface->ksmbd_socket);
|
||||
iface->ksmbd_socket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ksmbd_tcp_destroy(void)
|
||||
{
|
||||
struct interface *iface, *tmp;
|
||||
|
|
@ -643,6 +660,7 @@ void ksmbd_tcp_destroy(void)
|
|||
unregister_netdevice_notifier(&ksmbd_netdev_notifier);
|
||||
|
||||
list_for_each_entry_safe(iface, tmp, &iface_list, entry) {
|
||||
ksmbd_tcp_stop_listener(iface);
|
||||
list_del(&iface->entry);
|
||||
kfree(iface->name);
|
||||
kfree(iface);
|
||||
|
|
|
|||
|
|
@ -846,12 +846,25 @@ static void set_close_state_blocked_works(struct ksmbd_file *fp)
|
|||
spin_lock(&fp->f_lock);
|
||||
list_for_each_entry(cancel_work, &fp->blocked_works,
|
||||
fp_entry) {
|
||||
cancel_work->state = KSMBD_WORK_CLOSED;
|
||||
cancel_work->cancel_fn(cancel_work->cancel_argv);
|
||||
if (xchg(&cancel_work->state, KSMBD_WORK_CLOSED) ==
|
||||
KSMBD_WORK_ACTIVE)
|
||||
cancel_work->cancel_fn(cancel_work->cancel_argv);
|
||||
}
|
||||
spin_unlock(&fp->f_lock);
|
||||
}
|
||||
|
||||
void ksmbd_wake_session_blocked_works(struct ksmbd_session *sess)
|
||||
{
|
||||
struct ksmbd_file_table *ft = &sess->file_table;
|
||||
struct ksmbd_file *fp;
|
||||
unsigned int id;
|
||||
|
||||
read_lock(&ft->lock);
|
||||
idr_for_each_entry(ft->idr, fp, id)
|
||||
set_close_state_blocked_works(fp);
|
||||
read_unlock(&ft->lock);
|
||||
}
|
||||
|
||||
int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
|
||||
{
|
||||
struct ksmbd_file *fp;
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@ void ksmbd_stop_durable_scavenger(void);
|
|||
bool ksmbd_durable_scavenger_active(void);
|
||||
void ksmbd_close_tree_conn_fds(struct ksmbd_work *work);
|
||||
void ksmbd_close_session_fds(struct ksmbd_work *work);
|
||||
void ksmbd_wake_session_blocked_works(struct ksmbd_session *sess);
|
||||
int ksmbd_close_inode_fds(struct ksmbd_work *work, struct inode *inode);
|
||||
int ksmbd_init_global_file_table(void);
|
||||
void ksmbd_free_global_file_table(void);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user