summaryrefslogtreecommitdiff
path: root/fs/smb/server
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-01-12 07:27:41 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2024-01-12 07:27:41 +0300
commit6a31658aa1c0b757df652f6fcf3a001f90fda302 (patch)
treeb73279e4168c1953c5e06bfc01d29f8c52c03b0f /fs/smb/server
parent488926926a1653adfda3f662355907c896524487 (diff)
parent8fb7b723924cc9306bc161f45496497aec733904 (diff)
downloadlinux-6a31658aa1c0b757df652f6fcf3a001f90fda302.tar.xz
Merge tag '6.8-rc-smb-server-fixes' of git://git.samba.org/ksmbd
Pull smb server updates from Steve French: - memory allocation fix - three lease fixes, including important rename fix - read only share fix - thread freeze fix - three cleanup fixes (two kernel doc related) - locking fix in setting EAs - packet header validation fix * tag '6.8-rc-smb-server-fixes' of git://git.samba.org/ksmbd: ksmbd: Add missing set_freezable() for freezable kthread ksmbd: free ppace array on error in parse_dacl ksmbd: send lease break notification on FILE_RENAME_INFORMATION ksmbd: don't allow O_TRUNC open on read-only share ksmbd: vfs: fix all kernel-doc warnings ksmbd: auth: fix most kernel-doc warnings ksmbd: Remove usage of the deprecated ida_simple_xx() API ksmbd: don't increment epoch if current state and request state are same ksmbd: fix potential circular locking issue in smb2_set_ea() ksmbd: set v2 lease version on lease upgrade ksmbd: validate the zero field of packet header
Diffstat (limited to 'fs/smb/server')
-rw-r--r--fs/smb/server/auth.c14
-rw-r--r--fs/smb/server/connection.c1
-rw-r--r--fs/smb/server/mgmt/ksmbd_ida.c21
-rw-r--r--fs/smb/server/oplock.c16
-rw-r--r--fs/smb/server/smb2pdu.c31
-rw-r--r--fs/smb/server/smb_common.c6
-rw-r--r--fs/smb/server/smbacl.c11
-rw-r--r--fs/smb/server/vfs.c28
8 files changed, 70 insertions, 58 deletions
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index 229a6527870d..09b20039636e 100644
--- a/fs/smb/server/auth.c
+++ b/fs/smb/server/auth.c
@@ -208,10 +208,12 @@ out:
/**
* ksmbd_auth_ntlmv2() - NTLMv2 authentication handler
- * @sess: session of connection
+ * @conn: connection
+ * @sess: session of connection
* @ntlmv2: NTLMv2 challenge response
* @blen: NTLMv2 blob length
* @domain_name: domain name
+ * @cryptkey: session crypto key
*
* Return: 0 on success, error number on error
*/
@@ -294,7 +296,8 @@ out:
* ksmbd_decode_ntlmssp_auth_blob() - helper function to construct
* authenticate blob
* @authblob: authenticate blob source pointer
- * @usr: user details
+ * @blob_len: length of the @authblob message
+ * @conn: connection
* @sess: session of connection
*
* Return: 0 on success, error number on error
@@ -376,8 +379,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
* ksmbd_decode_ntlmssp_neg_blob() - helper function to construct
* negotiate blob
* @negblob: negotiate blob source pointer
- * @rsp: response header pointer to be updated
- * @sess: session of connection
+ * @blob_len: length of the @authblob message
+ * @conn: connection
*
*/
int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob,
@@ -403,8 +406,7 @@ int ksmbd_decode_ntlmssp_neg_blob(struct negotiate_message *negblob,
* ksmbd_build_ntlmssp_challenge_blob() - helper function to construct
* challenge blob
* @chgblob: challenge blob source pointer to initialize
- * @rsp: response header pointer to be updated
- * @sess: session of connection
+ * @conn: connection
*
*/
unsigned int
diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c
index b6fa1e285c40..d311c2ee10bd 100644
--- a/fs/smb/server/connection.c
+++ b/fs/smb/server/connection.c
@@ -284,6 +284,7 @@ int ksmbd_conn_handler_loop(void *p)
goto out;
conn->last_active = jiffies;
+ set_freezable();
while (ksmbd_conn_alive(conn)) {
if (try_to_freeze())
continue;
diff --git a/fs/smb/server/mgmt/ksmbd_ida.c b/fs/smb/server/mgmt/ksmbd_ida.c
index 54194d959a5e..a18e27e9e0cd 100644
--- a/fs/smb/server/mgmt/ksmbd_ida.c
+++ b/fs/smb/server/mgmt/ksmbd_ida.c
@@ -5,42 +5,33 @@
#include "ksmbd_ida.h"
-static inline int __acquire_id(struct ida *ida, int from, int to)
-{
- return ida_simple_get(ida, from, to, GFP_KERNEL);
-}
-
int ksmbd_acquire_smb2_tid(struct ida *ida)
{
- int id;
-
- id = __acquire_id(ida, 1, 0xFFFFFFFF);
-
- return id;
+ return ida_alloc_range(ida, 1, 0xFFFFFFFE, GFP_KERNEL);
}
int ksmbd_acquire_smb2_uid(struct ida *ida)
{
int id;
- id = __acquire_id(ida, 1, 0);
+ id = ida_alloc_min(ida, 1, GFP_KERNEL);
if (id == 0xFFFE)
- id = __acquire_id(ida, 1, 0);
+ id = ida_alloc_min(ida, 1, GFP_KERNEL);
return id;
}
int ksmbd_acquire_async_msg_id(struct ida *ida)
{
- return __acquire_id(ida, 1, 0);
+ return ida_alloc_min(ida, 1, GFP_KERNEL);
}
int ksmbd_acquire_id(struct ida *ida)
{
- return __acquire_id(ida, 0, 0);
+ return ida_alloc(ida, GFP_KERNEL);
}
void ksmbd_release_id(struct ida *ida, int id)
{
- ida_simple_remove(ida, id);
+ ida_free(ida, id);
}
diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
index 562b180459a1..001926d3b348 100644
--- a/fs/smb/server/oplock.c
+++ b/fs/smb/server/oplock.c
@@ -105,7 +105,7 @@ static int alloc_lease(struct oplock_info *opinfo, struct lease_ctx_info *lctx)
lease->is_dir = lctx->is_dir;
memcpy(lease->parent_lease_key, lctx->parent_lease_key, SMB2_LEASE_KEY_SIZE);
lease->version = lctx->version;
- lease->epoch = le16_to_cpu(lctx->epoch);
+ lease->epoch = le16_to_cpu(lctx->epoch) + 1;
INIT_LIST_HEAD(&opinfo->lease_entry);
opinfo->o_lease = lease;
@@ -546,6 +546,7 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,
atomic_read(&ci->sop_count)) == 1) {
if (lease->state != SMB2_LEASE_NONE_LE &&
lease->state == (lctx->req_state & lease->state)) {
+ lease->epoch++;
lease->state |= lctx->req_state;
if (lctx->req_state &
SMB2_LEASE_WRITE_CACHING_LE)
@@ -556,13 +557,17 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,
atomic_read(&ci->sop_count)) > 1) {
if (lctx->req_state ==
(SMB2_LEASE_READ_CACHING_LE |
- SMB2_LEASE_HANDLE_CACHING_LE))
+ SMB2_LEASE_HANDLE_CACHING_LE)) {
+ lease->epoch++;
lease->state = lctx->req_state;
+ }
}
if (lctx->req_state && lease->state ==
- SMB2_LEASE_NONE_LE)
+ SMB2_LEASE_NONE_LE) {
+ lease->epoch++;
lease_none_upgrade(opinfo, lctx->req_state);
+ }
}
read_lock(&ci->m_lock);
}
@@ -1035,7 +1040,8 @@ static void copy_lease(struct oplock_info *op1, struct oplock_info *op2)
SMB2_LEASE_KEY_SIZE);
lease2->duration = lease1->duration;
lease2->flags = lease1->flags;
- lease2->epoch = lease1->epoch++;
+ lease2->epoch = lease1->epoch;
+ lease2->version = lease1->version;
}
static int add_lease_global_list(struct oplock_info *opinfo)
@@ -1447,7 +1453,7 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
memcpy(buf->lcontext.LeaseKey, lease->lease_key,
SMB2_LEASE_KEY_SIZE);
buf->lcontext.LeaseFlags = lease->flags;
- buf->lcontext.Epoch = cpu_to_le16(++lease->epoch);
+ buf->lcontext.Epoch = cpu_to_le16(lease->epoch);
buf->lcontext.LeaseState = lease->state;
memcpy(buf->lcontext.ParentLeaseKey, lease->parent_lease_key,
SMB2_LEASE_KEY_SIZE);
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 652ab429bf2e..3143819935dc 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -2311,11 +2311,12 @@ out:
* @eabuf: set info command buffer
* @buf_len: set info command buffer length
* @path: dentry path for get ea
+ * @get_write: get write access to a mount
*
* Return: 0 on success, otherwise error
*/
static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
- const struct path *path)
+ const struct path *path, bool get_write)
{
struct mnt_idmap *idmap = mnt_idmap(path->mnt);
char *attr_name = NULL, *value;
@@ -2971,7 +2972,7 @@ int smb2_open(struct ksmbd_work *work)
&may_flags);
if (!test_tree_conn_flag(tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
- if (open_flags & O_CREAT) {
+ if (open_flags & (O_CREAT | O_TRUNC)) {
ksmbd_debug(SMB,
"User does not have write permission\n");
rc = -EACCES;
@@ -3003,7 +3004,7 @@ int smb2_open(struct ksmbd_work *work)
rc = smb2_set_ea(&ea_buf->ea,
le32_to_cpu(ea_buf->ccontext.DataLength),
- &path);
+ &path, false);
if (rc == -EOPNOTSUPP)
rc = 0;
else if (rc)
@@ -5568,6 +5569,7 @@ static int smb2_rename(struct ksmbd_work *work,
if (!file_info->ReplaceIfExists)
flags = RENAME_NOREPLACE;
+ smb_break_all_levII_oplock(work, fp, 0);
rc = ksmbd_vfs_rename(work, &fp->filp->f_path, new_name, flags);
out:
kfree(new_name);
@@ -5943,12 +5945,6 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
}
case FILE_RENAME_INFORMATION:
{
- if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
- ksmbd_debug(SMB,
- "User does not have write permission\n");
- return -EACCES;
- }
-
if (buf_len < sizeof(struct smb2_file_rename_info))
return -EINVAL;
@@ -5968,12 +5964,6 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
}
case FILE_DISPOSITION_INFORMATION:
{
- if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
- ksmbd_debug(SMB,
- "User does not have write permission\n");
- return -EACCES;
- }
-
if (buf_len < sizeof(struct smb2_file_disposition_info))
return -EINVAL;
@@ -5992,7 +5982,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
return -EINVAL;
return smb2_set_ea((struct smb2_ea_info *)req->Buffer,
- buf_len, &fp->filp->f_path);
+ buf_len, &fp->filp->f_path, true);
}
case FILE_POSITION_INFORMATION:
{
@@ -6035,7 +6025,7 @@ int smb2_set_info(struct ksmbd_work *work)
{
struct smb2_set_info_req *req;
struct smb2_set_info_rsp *rsp;
- struct ksmbd_file *fp;
+ struct ksmbd_file *fp = NULL;
int rc = 0;
unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
@@ -6055,6 +6045,13 @@ int smb2_set_info(struct ksmbd_work *work)
rsp = smb2_get_msg(work->response_buf);
}
+ if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
+ ksmbd_debug(SMB, "User does not have write permission\n");
+ pr_err("User does not have write permission\n");
+ rc = -EACCES;
+ goto err_out;
+ }
+
if (!has_file_id(id)) {
id = req->VolatileFileId;
pid = req->PersistentFileId;
diff --git a/fs/smb/server/smb_common.c b/fs/smb/server/smb_common.c
index 6691ae68af0c..7c98bf699772 100644
--- a/fs/smb/server/smb_common.c
+++ b/fs/smb/server/smb_common.c
@@ -158,8 +158,12 @@ int ksmbd_verify_smb_message(struct ksmbd_work *work)
*/
bool ksmbd_smb_request(struct ksmbd_conn *conn)
{
- __le32 *proto = (__le32 *)smb2_get_msg(conn->request_buf);
+ __le32 *proto;
+ if (conn->request_buf[0] != 0)
+ return false;
+
+ proto = (__le32 *)smb2_get_msg(conn->request_buf);
if (*proto == SMB2_COMPRESSION_TRANSFORM_ID) {
pr_err_ratelimited("smb2 compression not support yet");
return false;
diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
index 1164365533f0..1c9775f1efa5 100644
--- a/fs/smb/server/smbacl.c
+++ b/fs/smb/server/smbacl.c
@@ -401,10 +401,6 @@ static void parse_dacl(struct mnt_idmap *idmap,
if (num_aces > ULONG_MAX / sizeof(struct smb_ace *))
return;
- ppace = kmalloc_array(num_aces, sizeof(struct smb_ace *), GFP_KERNEL);
- if (!ppace)
- return;
-
ret = init_acl_state(&acl_state, num_aces);
if (ret)
return;
@@ -414,6 +410,13 @@ static void parse_dacl(struct mnt_idmap *idmap,
return;
}
+ ppace = kmalloc_array(num_aces, sizeof(struct smb_ace *), GFP_KERNEL);
+ if (!ppace) {
+ free_acl_state(&default_acl_state);
+ free_acl_state(&acl_state);
+ return;
+ }
+
/*
* reset rwx permissions for user/group/other.
* Also, if num_aces is 0 i.e. DACL has no ACEs,
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index b6904a9b05f6..a6961bfe3e13 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -49,6 +49,10 @@ static void ksmbd_vfs_inherit_owner(struct ksmbd_work *work,
/**
* ksmbd_vfs_lock_parent() - lock parent dentry if it is stable
+ * @parent: parent dentry
+ * @child: child dentry
+ *
+ * Returns: %0 on success, %-ENOENT if the parent dentry is not stable
*/
int ksmbd_vfs_lock_parent(struct dentry *parent, struct dentry *child)
{
@@ -360,7 +364,7 @@ out:
/**
* ksmbd_vfs_read() - vfs helper for smb file read
* @work: smb work
- * @fid: file id of open file
+ * @fp: ksmbd file pointer
* @count: read byte count
* @pos: file pos
* @rbuf: read data buffer
@@ -474,7 +478,7 @@ out:
/**
* ksmbd_vfs_write() - vfs helper for smb file write
* @work: work
- * @fid: file id of open file
+ * @fp: ksmbd file pointer
* @buf: buf containing data for writing
* @count: read byte count
* @pos: file pos
@@ -545,10 +549,8 @@ out:
/**
* ksmbd_vfs_getattr() - vfs helper for smb getattr
- * @work: work
- * @fid: file id of open file
- * @attrs: inode attributes
- *
+ * @path: path of dentry
+ * @stat: pointer to returned kernel stat structure
* Return: 0 on success, otherwise error
*/
int ksmbd_vfs_getattr(const struct path *path, struct kstat *stat)
@@ -565,6 +567,7 @@ int ksmbd_vfs_getattr(const struct path *path, struct kstat *stat)
* ksmbd_vfs_fsync() - vfs helper for smb fsync
* @work: work
* @fid: file id of open file
+ * @p_id: persistent file id
*
* Return: 0 on success, otherwise error
*/
@@ -587,7 +590,8 @@ int ksmbd_vfs_fsync(struct ksmbd_work *work, u64 fid, u64 p_id)
/**
* ksmbd_vfs_remove_file() - vfs helper for smb rmdir or unlink
- * @name: directory or file name that is relative to share
+ * @work: work
+ * @path: path of dentry
*
* Return: 0 on success, otherwise error
*/
@@ -623,6 +627,7 @@ out_err:
/**
* ksmbd_vfs_link() - vfs helper for creating smb hardlink
+ * @work: work
* @oldname: source file name
* @newname: hardlink name that is relative to share
*
@@ -800,7 +805,7 @@ revert_fsids:
/**
* ksmbd_vfs_truncate() - vfs helper for smb file truncate
* @work: work
- * @fid: file id of old file
+ * @fp: ksmbd file pointer
* @size: truncate to given size
*
* Return: 0 on success, otherwise error
@@ -843,7 +848,6 @@ int ksmbd_vfs_truncate(struct ksmbd_work *work,
* ksmbd_vfs_listxattr() - vfs helper for smb list extended attributes
* @dentry: dentry of file for listing xattrs
* @list: destination buffer
- * @size: destination buffer length
*
* Return: xattr list length on success, otherwise error
*/
@@ -952,7 +956,7 @@ int ksmbd_vfs_setxattr(struct mnt_idmap *idmap,
/**
* ksmbd_vfs_set_fadvise() - convert smb IO caching options to linux options
* @filp: file pointer for IO
- * @options: smb IO options
+ * @option: smb IO options
*/
void ksmbd_vfs_set_fadvise(struct file *filp, __le32 option)
{
@@ -1164,6 +1168,7 @@ static bool __caseless_lookup(struct dir_context *ctx, const char *name,
* @dir: path info
* @name: filename to lookup
* @namelen: filename length
+ * @um: &struct unicode_map to use
*
* Return: 0 on success, otherwise error
*/
@@ -1194,6 +1199,7 @@ static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name,
/**
* ksmbd_vfs_kern_path_locked() - lookup a file and get path info
+ * @work: work
* @name: file path that is relative to share
* @flags: lookup flags
* @parent_path: if lookup succeed, return parent_path info
@@ -1641,6 +1647,8 @@ int ksmbd_vfs_get_dos_attrib_xattr(struct mnt_idmap *idmap,
* ksmbd_vfs_init_kstat() - convert unix stat information to smb stat format
* @p: destination buffer
* @ksmbd_kstat: ksmbd kstat wrapper
+ *
+ * Returns: pointer to the converted &struct file_directory_info
*/
void *ksmbd_vfs_init_kstat(char **p, struct ksmbd_kstat *ksmbd_kstat)
{