@@ -2661,11 +2661,17 @@ int smb2_open(struct ksmbd_work *work)
}
if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) {
- /*
- * On delete request, instead of following up, need to
- * look the current entity
- */
- rc = ksmbd_vfs_kern_path(name, 0, &path, 1);
+ if (test_share_config_flag(work->tcon->share_conf,
+ KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS)) {
+ /*
+ * On delete request, instead of following up, need to
+ * look the current entity
+ */
+ rc = ksmbd_vfs_kern_path(name, 0, &path, 1);
+ } else {
+ rc = ksmbd_vfs_kern_path(name, LOOKUP_NO_SYMLINKS, &path, 1);
+ }
+
if (!rc) {
/*
* If file exists with under flags, return access
@@ -2698,7 +2704,8 @@ int smb2_open(struct ksmbd_work *work)
rc = ksmbd_vfs_kern_path(name, 0, &path, 1);
}
} else {
- rc = ksmbd_vfs_kern_path(name, 0, &path, 1);
+ rc = ksmbd_vfs_kern_path(name, LOOKUP_NO_SYMLINKS,
+ &path, 1);
if (!rc && d_is_symlink(path.dentry)) {
rc = -EACCES;
path_put(&path);
@@ -4788,7 +4795,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
struct path path;
int rc = 0, len;
int fs_infoclass_size = 0;
- int lookup_flags = 0;
+ int lookup_flags = LOOKUP_NO_SYMLINKS;
if (test_share_config_flag(share, KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS))
lookup_flags = LOOKUP_FOLLOW;
@@ -5300,7 +5307,7 @@ static int smb2_rename(struct ksmbd_work *work,
char *pathname = NULL;
struct path path;
bool file_present = true;
- int rc;
+ int rc, lookup_flags = LOOKUP_NO_SYMLINKS;
ksmbd_debug(SMB, "setting FILE_RENAME_INFO\n");
pathname = kmalloc(PATH_MAX, GFP_KERNEL);
@@ -5369,8 +5376,11 @@ static int smb2_rename(struct ksmbd_work *work,
goto out;
}
+ if (test_share_config_flag(share, KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS))
+ lookup_flags = LOOKUP_FOLLOW;
+
ksmbd_debug(SMB, "new name %s\n", new_name);
- rc = ksmbd_vfs_kern_path(new_name, 0, &path, 1);
+ rc = ksmbd_vfs_kern_path(new_name, lookup_flags, &path, 1);
if (rc)
file_present = false;
else
@@ -5420,7 +5430,7 @@ static int smb2_create_link(struct ksmbd_work *work,
char *link_name = NULL, *target_name = NULL, *pathname = NULL;
struct path path;
bool file_present = true;
- int rc;
+ int rc, lookup_flags = LOOKUP_NO_SYMLINKS;
if (buf_len < sizeof(struct smb2_file_link_info) +
le32_to_cpu(file_info->FileNameLength))
@@ -5447,8 +5457,11 @@ static int smb2_create_link(struct ksmbd_work *work,
goto out;
}
+ if (test_share_config_flag(share, KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS))
+ lookup_flags = LOOKUP_FOLLOW;
+
ksmbd_debug(SMB, "target name is %s\n", target_name);
- rc = ksmbd_vfs_kern_path(link_name, 0, &path, 0);
+ rc = ksmbd_vfs_kern_path(link_name, lookup_flags, &path, 0);
if (rc)
file_present = false;
else
@@ -164,9 +164,13 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode)
{
struct path path;
struct dentry *dentry;
- int err;
+ int err, lookup_flags = LOOKUP_NO_SYMLINKS;
+
+ if (test_share_config_flag(work->tcon->share_conf,
+ KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS))
+ lookup_flags = LOOKUP_FOLLOW;
- dentry = kern_path_create(AT_FDCWD, name, &path, 0);
+ dentry = kern_path_create(AT_FDCWD, name, &path, lookup_flags);
if (IS_ERR(dentry)) {
err = PTR_ERR(dentry);
if (err != -ENOENT)
@@ -201,9 +205,14 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode)
struct user_namespace *user_ns;
struct path path;
struct dentry *dentry;
- int err;
+ int err, lookup_flags = LOOKUP_NO_SYMLINKS;
- dentry = kern_path_create(AT_FDCWD, name, &path, LOOKUP_DIRECTORY);
+ if (test_share_config_flag(work->tcon->share_conf,
+ KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS))
+ lookup_flags = LOOKUP_FOLLOW;
+
+ dentry = kern_path_create(AT_FDCWD, name, &path,
+ lookup_flags | LOOKUP_DIRECTORY);
if (IS_ERR(dentry)) {
err = PTR_ERR(dentry);
if (err != -EEXIST)
@@ -588,7 +597,7 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name)
struct path path;
struct dentry *parent;
int err;
- int flags = 0;
+ int flags = LOOKUP_NO_SYMLINKS;
if (ksmbd_override_fsids(work))
return -ENOMEM;
@@ -652,7 +661,7 @@ int ksmbd_vfs_link(struct ksmbd_work *work, const char *oldname,
struct path oldpath, newpath;
struct dentry *dentry;
int err;
- int flags = 0;
+ int flags = LOOKUP_NO_SYMLINKS;
if (ksmbd_override_fsids(work))
return -ENOMEM;
@@ -788,7 +797,7 @@ int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
struct dentry *src_dent, *trap_dent, *src_child;
char *dst_name;
int err;
- int flags;
+ int flags = LOOKUP_NO_SYMLINKS;
dst_name = extract_last_component(newname);
if (!dst_name)
@@ -800,7 +809,8 @@ int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
flags = LOOKUP_DIRECTORY;
if (test_share_config_flag(work->tcon->share_conf,
KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS))
- flags |= LOOKUP_FOLLOW;
+ flags = LOOKUP_FOLLOW;
+ flags |= LOOKUP_DIRECTORY;
err = kern_path(newname, flags, &dst_path);
if (err) {
@@ -861,7 +871,13 @@ int ksmbd_vfs_truncate(struct ksmbd_work *work, const char *name,
int err = 0;
if (name) {
- err = kern_path(name, 0, &path);
+ int flags = LOOKUP_NO_SYMLINKS;
+
+ if (test_share_config_flag(work->tcon->share_conf,
+ KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS))
+ flags = LOOKUP_FOLLOW;
+
+ err = kern_path(name, flags, &path);
if (err) {
pr_err("cannot get linux path for %s, err %d\n",
name, err);
Use LOOKUP_NO_SYMLINKS flags for default lookup to prohibit the middle of symlink component lookup. Test result: # smbclient -Ulinkinjeon%1234 //172.30.1.42/share -c "get hacked/passwd passwd" NT_STATUS_OBJECT_NAME_NOT_FOUND opening remote file \hacked\passwd Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com> Cc: Ralph Böhme <slow@samba.org> Cc: Steve French <smfrench@gmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> --- fs/ksmbd/smb2pdu.c | 35 ++++++++++++++++++++++++----------- fs/ksmbd/vfs.c | 34 +++++++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 20 deletions(-)