Skip to content

Commit 1ae78a1

Browse files
committed
Merge tag '6.4-rc-ksmbd-server-fixes' of git://git.samba.org/ksmbd
Pull ksmbd server updates from Steve French: - SMB3.1.1 negotiate context fixes and cleanup - new lock_rename_child VFS helper - ksmbd fix to avoid unlink race and to use the new VFS helper to avoid rename race * tag '6.4-rc-ksmbd-server-fixes' of git://git.samba.org/ksmbd: ksmbd: fix racy issue from using ->d_parent and ->d_name ksmbd: remove unused compression negotiate ctx packing ksmbd: avoid duplicate negotiate ctx offset increments ksmbd: set NegotiateContextCount once instead of every inc fs: introduce lock_rename_child() helper ksmbd: remove internal.h include
2 parents 4e1c80a + 74d7970 commit 1ae78a1

7 files changed

Lines changed: 357 additions & 443 deletions

File tree

fs/internal.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,6 @@ extern int finish_clean_context(struct fs_context *fc);
5959
*/
6060
extern int filename_lookup(int dfd, struct filename *name, unsigned flags,
6161
struct path *path, struct path *root);
62-
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
63-
const char *, unsigned int, struct path *);
6462
int do_rmdir(int dfd, struct filename *name);
6563
int do_unlinkat(int dfd, struct filename *name);
6664
int may_linkat(struct mnt_idmap *idmap, const struct path *link);

fs/ksmbd/smb2pdu.c

Lines changed: 49 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -756,19 +756,6 @@ static void build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt,
756756
pneg_ctxt->Ciphers[0] = cipher_type;
757757
}
758758

759-
static void build_compression_ctxt(struct smb2_compression_capabilities_context *pneg_ctxt,
760-
__le16 comp_algo)
761-
{
762-
pneg_ctxt->ContextType = SMB2_COMPRESSION_CAPABILITIES;
763-
pneg_ctxt->DataLength =
764-
cpu_to_le16(sizeof(struct smb2_compression_capabilities_context)
765-
- sizeof(struct smb2_neg_context));
766-
pneg_ctxt->Reserved = cpu_to_le32(0);
767-
pneg_ctxt->CompressionAlgorithmCount = cpu_to_le16(1);
768-
pneg_ctxt->Flags = cpu_to_le32(0);
769-
pneg_ctxt->CompressionAlgorithms[0] = comp_algo;
770-
}
771-
772759
static void build_sign_cap_ctxt(struct smb2_signing_capabilities *pneg_ctxt,
773760
__le16 sign_algo)
774761
{
@@ -808,7 +795,7 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn,
808795
struct smb2_negotiate_rsp *rsp,
809796
void *smb2_buf_len)
810797
{
811-
char *pneg_ctxt = (char *)rsp +
798+
char * const pneg_ctxt = (char *)rsp +
812799
le32_to_cpu(rsp->NegotiateContextOffset);
813800
int neg_ctxt_cnt = 1;
814801
int ctxt_size;
@@ -817,61 +804,46 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn,
817804
"assemble SMB2_PREAUTH_INTEGRITY_CAPABILITIES context\n");
818805
build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt,
819806
conn->preauth_info->Preauth_HashId);
820-
rsp->NegotiateContextCount = cpu_to_le16(neg_ctxt_cnt);
821807
inc_rfc1001_len(smb2_buf_len, AUTH_GSS_PADDING);
822808
ctxt_size = sizeof(struct smb2_preauth_neg_context);
823-
/* Round to 8 byte boundary */
824-
pneg_ctxt += round_up(sizeof(struct smb2_preauth_neg_context), 8);
825809

826810
if (conn->cipher_type) {
811+
/* Round to 8 byte boundary */
827812
ctxt_size = round_up(ctxt_size, 8);
828813
ksmbd_debug(SMB,
829814
"assemble SMB2_ENCRYPTION_CAPABILITIES context\n");
830-
build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt,
815+
build_encrypt_ctxt((struct smb2_encryption_neg_context *)
816+
(pneg_ctxt + ctxt_size),
831817
conn->cipher_type);
832-
rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt);
818+
neg_ctxt_cnt++;
833819
ctxt_size += sizeof(struct smb2_encryption_neg_context) + 2;
834-
/* Round to 8 byte boundary */
835-
pneg_ctxt +=
836-
round_up(sizeof(struct smb2_encryption_neg_context) + 2,
837-
8);
838820
}
839821

840-
if (conn->compress_algorithm) {
841-
ctxt_size = round_up(ctxt_size, 8);
842-
ksmbd_debug(SMB,
843-
"assemble SMB2_COMPRESSION_CAPABILITIES context\n");
844-
/* Temporarily set to SMB3_COMPRESS_NONE */
845-
build_compression_ctxt((struct smb2_compression_capabilities_context *)pneg_ctxt,
846-
conn->compress_algorithm);
847-
rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt);
848-
ctxt_size += sizeof(struct smb2_compression_capabilities_context) + 2;
849-
/* Round to 8 byte boundary */
850-
pneg_ctxt += round_up(sizeof(struct smb2_compression_capabilities_context) + 2,
851-
8);
852-
}
822+
/* compression context not yet supported */
823+
WARN_ON(conn->compress_algorithm != SMB3_COMPRESS_NONE);
853824

854825
if (conn->posix_ext_supported) {
855826
ctxt_size = round_up(ctxt_size, 8);
856827
ksmbd_debug(SMB,
857828
"assemble SMB2_POSIX_EXTENSIONS_AVAILABLE context\n");
858-
build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
859-
rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt);
829+
build_posix_ctxt((struct smb2_posix_neg_context *)
830+
(pneg_ctxt + ctxt_size));
831+
neg_ctxt_cnt++;
860832
ctxt_size += sizeof(struct smb2_posix_neg_context);
861-
/* Round to 8 byte boundary */
862-
pneg_ctxt += round_up(sizeof(struct smb2_posix_neg_context), 8);
863833
}
864834

865835
if (conn->signing_negotiated) {
866836
ctxt_size = round_up(ctxt_size, 8);
867837
ksmbd_debug(SMB,
868838
"assemble SMB2_SIGNING_CAPABILITIES context\n");
869-
build_sign_cap_ctxt((struct smb2_signing_capabilities *)pneg_ctxt,
839+
build_sign_cap_ctxt((struct smb2_signing_capabilities *)
840+
(pneg_ctxt + ctxt_size),
870841
conn->signing_algorithm);
871-
rsp->NegotiateContextCount = cpu_to_le16(++neg_ctxt_cnt);
842+
neg_ctxt_cnt++;
872843
ctxt_size += sizeof(struct smb2_signing_capabilities) + 2;
873844
}
874845

846+
rsp->NegotiateContextCount = cpu_to_le16(neg_ctxt_cnt);
875847
inc_rfc1001_len(smb2_buf_len, ctxt_size);
876848
}
877849

@@ -2436,7 +2408,7 @@ static int smb2_creat(struct ksmbd_work *work, struct path *path, char *name,
24362408
return rc;
24372409
}
24382410

2439-
rc = ksmbd_vfs_kern_path(work, name, 0, path, 0);
2411+
rc = ksmbd_vfs_kern_path_locked(work, name, 0, path, 0);
24402412
if (rc) {
24412413
pr_err("cannot get linux path (%s), err = %d\n",
24422414
name, rc);
@@ -2727,8 +2699,10 @@ int smb2_open(struct ksmbd_work *work)
27272699
goto err_out1;
27282700
}
27292701

2730-
rc = ksmbd_vfs_kern_path(work, name, LOOKUP_NO_SYMLINKS, &path, 1);
2702+
rc = ksmbd_vfs_kern_path_locked(work, name, LOOKUP_NO_SYMLINKS, &path, 1);
27312703
if (!rc) {
2704+
file_present = true;
2705+
27322706
if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) {
27332707
/*
27342708
* If file exists with under flags, return access
@@ -2737,34 +2711,30 @@ int smb2_open(struct ksmbd_work *work)
27372711
if (req->CreateDisposition == FILE_OVERWRITE_IF_LE ||
27382712
req->CreateDisposition == FILE_OPEN_IF_LE) {
27392713
rc = -EACCES;
2740-
path_put(&path);
27412714
goto err_out;
27422715
}
27432716

27442717
if (!test_tree_conn_flag(tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
27452718
ksmbd_debug(SMB,
27462719
"User does not have write permission\n");
27472720
rc = -EACCES;
2748-
path_put(&path);
27492721
goto err_out;
27502722
}
27512723
} else if (d_is_symlink(path.dentry)) {
27522724
rc = -EACCES;
2753-
path_put(&path);
27542725
goto err_out;
27552726
}
2756-
}
27572727

2758-
if (rc) {
2728+
file_present = true;
2729+
idmap = mnt_idmap(path.mnt);
2730+
} else {
27592731
if (rc != -ENOENT)
27602732
goto err_out;
27612733
ksmbd_debug(SMB, "can not get linux path for %s, rc = %d\n",
27622734
name, rc);
27632735
rc = 0;
2764-
} else {
2765-
file_present = true;
2766-
idmap = mnt_idmap(path.mnt);
27672736
}
2737+
27682738
if (stream_name) {
27692739
if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) {
27702740
if (s_type == DATA_STREAM) {
@@ -2892,8 +2862,9 @@ int smb2_open(struct ksmbd_work *work)
28922862

28932863
if ((daccess & FILE_DELETE_LE) ||
28942864
(req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) {
2895-
rc = ksmbd_vfs_may_delete(idmap,
2896-
path.dentry);
2865+
rc = inode_permission(idmap,
2866+
d_inode(path.dentry->d_parent),
2867+
MAY_EXEC | MAY_WRITE);
28972868
if (rc)
28982869
goto err_out;
28992870
}
@@ -3264,10 +3235,13 @@ int smb2_open(struct ksmbd_work *work)
32643235
}
32653236

32663237
err_out:
3267-
if (file_present || created)
3268-
path_put(&path);
3238+
if (file_present || created) {
3239+
inode_unlock(d_inode(path.dentry->d_parent));
3240+
dput(path.dentry);
3241+
}
32693242
ksmbd_revert_fsids(work);
32703243
err_out1:
3244+
32713245
if (rc) {
32723246
if (rc == -EINVAL)
32733247
rsp->hdr.Status = STATUS_INVALID_PARAMETER;
@@ -5418,44 +5392,19 @@ int smb2_echo(struct ksmbd_work *work)
54185392

54195393
static int smb2_rename(struct ksmbd_work *work,
54205394
struct ksmbd_file *fp,
5421-
struct mnt_idmap *idmap,
54225395
struct smb2_file_rename_info *file_info,
54235396
struct nls_table *local_nls)
54245397
{
54255398
struct ksmbd_share_config *share = fp->tcon->share_conf;
5426-
char *new_name = NULL, *abs_oldname = NULL, *old_name = NULL;
5427-
char *pathname = NULL;
5428-
struct path path;
5429-
bool file_present = true;
5430-
int rc;
5399+
char *new_name = NULL;
5400+
int rc, flags = 0;
54315401

54325402
ksmbd_debug(SMB, "setting FILE_RENAME_INFO\n");
5433-
pathname = kmalloc(PATH_MAX, GFP_KERNEL);
5434-
if (!pathname)
5435-
return -ENOMEM;
5436-
5437-
abs_oldname = file_path(fp->filp, pathname, PATH_MAX);
5438-
if (IS_ERR(abs_oldname)) {
5439-
rc = -EINVAL;
5440-
goto out;
5441-
}
5442-
old_name = strrchr(abs_oldname, '/');
5443-
if (old_name && old_name[1] != '\0') {
5444-
old_name++;
5445-
} else {
5446-
ksmbd_debug(SMB, "can't get last component in path %s\n",
5447-
abs_oldname);
5448-
rc = -ENOENT;
5449-
goto out;
5450-
}
5451-
54525403
new_name = smb2_get_name(file_info->FileName,
54535404
le32_to_cpu(file_info->FileNameLength),
54545405
local_nls);
5455-
if (IS_ERR(new_name)) {
5456-
rc = PTR_ERR(new_name);
5457-
goto out;
5458-
}
5406+
if (IS_ERR(new_name))
5407+
return PTR_ERR(new_name);
54595408

54605409
if (strchr(new_name, ':')) {
54615410
int s_type;
@@ -5481,7 +5430,7 @@ static int smb2_rename(struct ksmbd_work *work,
54815430
if (rc)
54825431
goto out;
54835432

5484-
rc = ksmbd_vfs_setxattr(idmap,
5433+
rc = ksmbd_vfs_setxattr(file_mnt_idmap(fp->filp),
54855434
fp->filp->f_path.dentry,
54865435
xattr_stream_name,
54875436
NULL, 0, 0);
@@ -5496,47 +5445,18 @@ static int smb2_rename(struct ksmbd_work *work,
54965445
}
54975446

54985447
ksmbd_debug(SMB, "new name %s\n", new_name);
5499-
rc = ksmbd_vfs_kern_path(work, new_name, LOOKUP_NO_SYMLINKS, &path, 1);
5500-
if (rc) {
5501-
if (rc != -ENOENT)
5502-
goto out;
5503-
file_present = false;
5504-
} else {
5505-
path_put(&path);
5506-
}
5507-
55085448
if (ksmbd_share_veto_filename(share, new_name)) {
55095449
rc = -ENOENT;
55105450
ksmbd_debug(SMB, "Can't rename vetoed file: %s\n", new_name);
55115451
goto out;
55125452
}
55135453

5514-
if (file_info->ReplaceIfExists) {
5515-
if (file_present) {
5516-
rc = ksmbd_vfs_remove_file(work, new_name);
5517-
if (rc) {
5518-
if (rc != -ENOTEMPTY)
5519-
rc = -EINVAL;
5520-
ksmbd_debug(SMB, "cannot delete %s, rc %d\n",
5521-
new_name, rc);
5522-
goto out;
5523-
}
5524-
}
5525-
} else {
5526-
if (file_present &&
5527-
strncmp(old_name, path.dentry->d_name.name, strlen(old_name))) {
5528-
rc = -EEXIST;
5529-
ksmbd_debug(SMB,
5530-
"cannot rename already existing file\n");
5531-
goto out;
5532-
}
5533-
}
5454+
if (!file_info->ReplaceIfExists)
5455+
flags = RENAME_NOREPLACE;
55345456

5535-
rc = ksmbd_vfs_fp_rename(work, fp, new_name);
5457+
rc = ksmbd_vfs_rename(work, &fp->filp->f_path, new_name, flags);
55365458
out:
5537-
kfree(pathname);
5538-
if (!IS_ERR(new_name))
5539-
kfree(new_name);
5459+
kfree(new_name);
55405460
return rc;
55415461
}
55425462

@@ -5576,18 +5496,17 @@ static int smb2_create_link(struct ksmbd_work *work,
55765496
}
55775497

55785498
ksmbd_debug(SMB, "target name is %s\n", target_name);
5579-
rc = ksmbd_vfs_kern_path(work, link_name, LOOKUP_NO_SYMLINKS, &path, 0);
5499+
rc = ksmbd_vfs_kern_path_locked(work, link_name, LOOKUP_NO_SYMLINKS,
5500+
&path, 0);
55805501
if (rc) {
55815502
if (rc != -ENOENT)
55825503
goto out;
55835504
file_present = false;
5584-
} else {
5585-
path_put(&path);
55865505
}
55875506

55885507
if (file_info->ReplaceIfExists) {
55895508
if (file_present) {
5590-
rc = ksmbd_vfs_remove_file(work, link_name);
5509+
rc = ksmbd_vfs_remove_file(work, &path);
55915510
if (rc) {
55925511
rc = -EINVAL;
55935512
ksmbd_debug(SMB, "cannot delete %s\n",
@@ -5607,6 +5526,10 @@ static int smb2_create_link(struct ksmbd_work *work,
56075526
if (rc)
56085527
rc = -EINVAL;
56095528
out:
5529+
if (file_present) {
5530+
inode_unlock(d_inode(path.dentry->d_parent));
5531+
path_put(&path);
5532+
}
56105533
if (!IS_ERR(link_name))
56115534
kfree(link_name);
56125535
kfree(pathname);
@@ -5784,12 +5707,6 @@ static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,
57845707
struct smb2_file_rename_info *rename_info,
57855708
unsigned int buf_len)
57865709
{
5787-
struct mnt_idmap *idmap;
5788-
struct ksmbd_file *parent_fp;
5789-
struct dentry *parent;
5790-
struct dentry *dentry = fp->filp->f_path.dentry;
5791-
int ret;
5792-
57935710
if (!(fp->daccess & FILE_DELETE_LE)) {
57945711
pr_err("no right to delete : 0x%x\n", fp->daccess);
57955712
return -EACCES;
@@ -5799,32 +5716,10 @@ static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,
57995716
le32_to_cpu(rename_info->FileNameLength))
58005717
return -EINVAL;
58015718

5802-
idmap = file_mnt_idmap(fp->filp);
5803-
if (ksmbd_stream_fd(fp))
5804-
goto next;
5805-
5806-
parent = dget_parent(dentry);
5807-
ret = ksmbd_vfs_lock_parent(idmap, parent, dentry);
5808-
if (ret) {
5809-
dput(parent);
5810-
return ret;
5811-
}
5812-
5813-
parent_fp = ksmbd_lookup_fd_inode(d_inode(parent));
5814-
inode_unlock(d_inode(parent));
5815-
dput(parent);
5719+
if (!le32_to_cpu(rename_info->FileNameLength))
5720+
return -EINVAL;
58165721

5817-
if (parent_fp) {
5818-
if (parent_fp->daccess & FILE_DELETE_LE) {
5819-
pr_err("parent dir is opened with delete access\n");
5820-
ksmbd_fd_put(work, parent_fp);
5821-
return -ESHARE;
5822-
}
5823-
ksmbd_fd_put(work, parent_fp);
5824-
}
5825-
next:
5826-
return smb2_rename(work, fp, idmap, rename_info,
5827-
work->conn->local_nls);
5722+
return smb2_rename(work, fp, rename_info, work->conn->local_nls);
58285723
}
58295724

58305725
static int set_file_disposition_info(struct ksmbd_file *fp,

0 commit comments

Comments
 (0)