diff mbox series

ksmbd: use LOOKUP_NO_SYMLINKS flags for default lookup

Message ID 20210919021315.642856-2-linkinjeon@kernel.org
State New
Headers show
Series ksmbd: use LOOKUP_NO_SYMLINKS flags for default lookup | expand

Commit Message

Namjae Jeon Sept. 19, 2021, 2:13 a.m. UTC
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(-)
diff mbox series

Patch

diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
index 592d489277e8..afc508c2656d 100644
--- a/fs/ksmbd/smb2pdu.c
+++ b/fs/ksmbd/smb2pdu.c
@@ -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
diff --git a/fs/ksmbd/vfs.c b/fs/ksmbd/vfs.c
index b047f2980d96..53047f013371 100644
--- a/fs/ksmbd/vfs.c
+++ b/fs/ksmbd/vfs.c
@@ -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);