summaryrefslogtreecommitdiffstats
path: root/fs/smb/server
diff options
context:
space:
mode:
Diffstat (limited to 'fs/smb/server')
-rw-r--r--fs/smb/server/auth.c14
-rw-r--r--fs/smb/server/ksmbd_netlink.h3
-rw-r--r--fs/smb/server/mgmt/ksmbd_ida.c21
-rw-r--r--fs/smb/server/mgmt/share_config.c7
-rw-r--r--fs/smb/server/misc.c1
-rw-r--r--fs/smb/server/server.c13
-rw-r--r--fs/smb/server/smb2ops.c10
-rw-r--r--fs/smb/server/smb2pdu.c7
-rw-r--r--fs/smb/server/transport_ipc.c37
-rw-r--r--fs/smb/server/transport_tcp.c2
-rw-r--r--fs/smb/server/vfs.c38
11 files changed, 106 insertions, 47 deletions
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index 229a652787..09b2003963 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/ksmbd_netlink.h b/fs/smb/server/ksmbd_netlink.h
index 0ebf91ffa2..4464a62228 100644
--- a/fs/smb/server/ksmbd_netlink.h
+++ b/fs/smb/server/ksmbd_netlink.h
@@ -166,7 +166,8 @@ struct ksmbd_share_config_response {
__u16 force_uid;
__u16 force_gid;
__s8 share_name[KSMBD_REQ_MAX_SHARE_NAME];
- __u32 reserved[112]; /* Reserved room */
+ __u32 reserved[111]; /* Reserved room */
+ __u32 payload_sz;
__u32 veto_list_sz;
__s8 ____payload[];
};
diff --git a/fs/smb/server/mgmt/ksmbd_ida.c b/fs/smb/server/mgmt/ksmbd_ida.c
index 54194d959a..a18e27e9e0 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/mgmt/share_config.c b/fs/smb/server/mgmt/share_config.c
index 328a412259..a2f0a2edce 100644
--- a/fs/smb/server/mgmt/share_config.c
+++ b/fs/smb/server/mgmt/share_config.c
@@ -158,7 +158,12 @@ static struct ksmbd_share_config *share_config_request(struct unicode_map *um,
share->name = kstrdup(name, GFP_KERNEL);
if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
- share->path = kstrdup(ksmbd_share_config_path(resp),
+ int path_len = PATH_MAX;
+
+ if (resp->payload_sz)
+ path_len = resp->payload_sz - resp->veto_list_sz;
+
+ share->path = kstrndup(ksmbd_share_config_path(resp), path_len,
GFP_KERNEL);
if (share->path)
share->path_sz = strlen(share->path);
diff --git a/fs/smb/server/misc.c b/fs/smb/server/misc.c
index 9e8afaa686..1a5faa6f6e 100644
--- a/fs/smb/server/misc.c
+++ b/fs/smb/server/misc.c
@@ -261,6 +261,7 @@ out_ascii:
/**
* ksmbd_extract_sharename() - get share name from tree connect request
+ * @um: pointer to a unicode_map structure for character encoding handling
* @treename: buffer containing tree name and share name
*
* Return: share name on success, otherwise error
diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c
index 3079e607c5..2bbc3c3316 100644
--- a/fs/smb/server/server.c
+++ b/fs/smb/server/server.c
@@ -167,20 +167,17 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
int rc;
bool is_chained = false;
- if (conn->ops->allocate_rsp_buf(work))
- return;
-
if (conn->ops->is_transform_hdr &&
conn->ops->is_transform_hdr(work->request_buf)) {
rc = conn->ops->decrypt_req(work);
- if (rc < 0) {
- conn->ops->set_rsp_status(work, STATUS_DATA_ERROR);
- goto send;
- }
-
+ if (rc < 0)
+ return;
work->encrypted = true;
}
+ if (conn->ops->allocate_rsp_buf(work))
+ return;
+
rc = conn->ops->init_rsp_hdr(work);
if (rc) {
/* either uid or tid is not correct */
diff --git a/fs/smb/server/smb2ops.c b/fs/smb/server/smb2ops.c
index 27a9dce3e0..8600f32c98 100644
--- a/fs/smb/server/smb2ops.c
+++ b/fs/smb/server/smb2ops.c
@@ -228,6 +228,11 @@ void init_smb3_0_server(struct ksmbd_conn *conn)
conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)
conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
+ if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION ||
+ (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) &&
+ conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION))
+ conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
+
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL;
}
@@ -275,11 +280,6 @@ int init_smb3_11_server(struct ksmbd_conn *conn)
conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING |
SMB2_GLOBAL_CAP_DIRECTORY_LEASING;
- if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION ||
- (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) &&
- conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION))
- conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
-
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL;
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 88db6e207e..8ae0c4d5ab 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -535,6 +535,10 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work)
if (cmd == SMB2_QUERY_INFO_HE) {
struct smb2_query_info_req *req;
+ if (get_rfc1002_len(work->request_buf) <
+ offsetof(struct smb2_query_info_req, OutputBufferLength))
+ return -EINVAL;
+
req = smb2_get_msg(work->request_buf);
if ((req->InfoType == SMB2_O_INFO_FILE &&
(req->FileInfoClass == FILE_FULL_EA_INFORMATION ||
@@ -5632,8 +5636,9 @@ 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);
+ if (!rc)
+ smb_break_all_levII_oplock(work, fp, 0);
out:
kfree(new_name);
return rc;
diff --git a/fs/smb/server/transport_ipc.c b/fs/smb/server/transport_ipc.c
index f29bb03f0d..8752ac82c5 100644
--- a/fs/smb/server/transport_ipc.c
+++ b/fs/smb/server/transport_ipc.c
@@ -65,6 +65,7 @@ struct ipc_msg_table_entry {
struct hlist_node ipc_table_hlist;
void *response;
+ unsigned int msg_sz;
};
static struct delayed_work ipc_timer_work;
@@ -275,6 +276,7 @@ static int handle_response(int type, void *payload, size_t sz)
}
memcpy(entry->response, payload, sz);
+ entry->msg_sz = sz;
wake_up_interruptible(&entry->wait);
ret = 0;
break;
@@ -453,6 +455,34 @@ out:
return ret;
}
+static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
+{
+ unsigned int msg_sz = entry->msg_sz;
+
+ if (entry->type == KSMBD_EVENT_RPC_REQUEST) {
+ struct ksmbd_rpc_command *resp = entry->response;
+
+ msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz;
+ } else if (entry->type == KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST) {
+ struct ksmbd_spnego_authen_response *resp = entry->response;
+
+ msg_sz = sizeof(struct ksmbd_spnego_authen_response) +
+ resp->session_key_len + resp->spnego_blob_len;
+ } else if (entry->type == KSMBD_EVENT_SHARE_CONFIG_REQUEST) {
+ struct ksmbd_share_config_response *resp = entry->response;
+
+ if (resp->payload_sz) {
+ if (resp->payload_sz < resp->veto_list_sz)
+ return -EINVAL;
+
+ msg_sz = sizeof(struct ksmbd_share_config_response) +
+ resp->payload_sz;
+ }
+ }
+
+ return entry->msg_sz != msg_sz ? -EINVAL : 0;
+}
+
static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle)
{
struct ipc_msg_table_entry entry;
@@ -477,6 +507,13 @@ static void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle
ret = wait_event_interruptible_timeout(entry.wait,
entry.response != NULL,
IPC_WAIT_TIMEOUT);
+ if (entry.response) {
+ ret = ipc_validate_msg(&entry);
+ if (ret) {
+ kvfree(entry.response);
+ entry.response = NULL;
+ }
+ }
out:
down_write(&ipc_msg_table_lock);
hash_del(&entry.ipc_table_hlist);
diff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c
index 9d4222154d..002a3f0dc7 100644
--- a/fs/smb/server/transport_tcp.c
+++ b/fs/smb/server/transport_tcp.c
@@ -365,6 +365,7 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig,
* @t: TCP transport instance
* @buf: buffer to store read data from socket
* @to_read: number of bytes to read from socket
+ * @max_retries: number of retries if reading from socket fails
*
* Return: on success return number of bytes read from socket,
* otherwise return error number
@@ -416,6 +417,7 @@ static void tcp_destroy_socket(struct socket *ksmbd_socket)
/**
* create_socket - create socket for ksmbd/0
+ * @iface: interface to bind the created socket to
*
* Return: 0 on success, error number otherwise
*/
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index a8936aba77..d7906efaa9 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
*
@@ -715,6 +720,10 @@ retry:
goto out2;
trap = lock_rename_child(old_child, new_path.dentry);
+ if (IS_ERR(trap)) {
+ err = PTR_ERR(trap);
+ goto out_drop_write;
+ }
old_parent = dget(old_child->d_parent);
if (d_unhashed(old_child)) {
@@ -745,10 +754,15 @@ retry:
goto out4;
}
+ /*
+ * explicitly handle file overwrite case, for compatibility with
+ * filesystems that may not support rename flags (e.g: fuse)
+ */
if ((flags & RENAME_NOREPLACE) && d_is_positive(new_dentry)) {
err = -EEXIST;
goto out4;
}
+ flags &= ~(RENAME_NOREPLACE);
if (old_child == trap) {
err = -EINVAL;
@@ -777,6 +791,7 @@ out4:
out3:
dput(old_parent);
unlock_rename(old_parent, new_path.dentry);
+out_drop_write:
mnt_drop_write(old_path->mnt);
out2:
path_put(&new_path);
@@ -795,7 +810,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
@@ -838,7 +853,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
*/
@@ -947,7 +961,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)
{
@@ -1159,6 +1173,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
*/
@@ -1189,6 +1204,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
@@ -1636,6 +1652,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)
{