11 ksmbd server fixes

-----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmWfZIYACgkQiiy9cAdy
 T1Gijgv+MH40buaJETR2FjRxzUiC92FFafGcX+fh5dLM22Sxb9AW+cNzOf/CSqNE
 0AKpdhh+MVq0xiYwaXrrGGUfpUOZ3fwTHNJjpCt5o34b8U6IrHIah96noCRhDwQm
 pE1Loi5TyWYRYsCjajau+tIi9+lgROkJ9eM34bx2dkkDw5ng4MQAygqJDwDM1n+i
 N/O3vRqG3ZUrK5h7v9kVBdFZlkiiVm8cjNH86prfecnT6TTa/6QZoNd9kQAyvGe2
 hWhW4J70y+H3JHcaBeGp11wcLcyBeFwBdqeo+os5EUPN/BbWaXuUqktBKvfnHIWA
 ucwrAMNVVK82JhudlkIGuYVgEOrLDrZsWjIJmDajFtJuO3Yo9VLkeZKcMRhPj45H
 kodPbCfPxNXg/y2fn1P3nCyiRSHHFb0QFEvK5JZV0Zwv5yPeziA/5e+6lu6OWNW7
 VYQb2ZdOzuNW6aXHXnPRQQDSbVFsgD5dVxqYA9cugvtKAslUb9Q6z4kNkCFbYq/F
 xJ0VH0K5
 =UhAE
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2024-01-11 20:27:41 -08:00
commit 6a31658aa1
8 changed files with 70 additions and 58 deletions

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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)
{