Commit 4ea47798 authored by Namjae Jeon's avatar Namjae Jeon Committed by Steve French
Browse files

ksmbd: remove follow symlinks support



Use  LOOKUP_NO_SYMLINKS flags for default lookup to prohibit the middle of
symlink component lookup and remove follow symlinks parameter support.
We re-implement it as reparse point later.

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: Ralph Böhme <slow@samba.org>
Cc: Steve French <smfrench@gmail.com>
Acked-by: default avatarRonnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 18a015bc
Loading
Loading
Loading
Loading
+10 −33
Original line number Diff line number Diff line
@@ -2632,13 +2632,9 @@ int smb2_open(struct ksmbd_work *work)
		goto err_out1;
	}

	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);
	rc = ksmbd_vfs_kern_path(name, LOOKUP_NO_SYMLINKS, &path, 1);
	if (!rc) {
		if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) {
			/*
			 * If file exists with under flags, return access
			 * denied error.
@@ -2657,27 +2653,12 @@ int smb2_open(struct ksmbd_work *work)
				path_put(&path);
				goto err_out;
			}
		}
	} else {
		if (test_share_config_flag(work->tcon->share_conf,
					   KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS)) {
			/*
			 * Use LOOKUP_FOLLOW to follow the path of
			 * symlink in path buildup
			 */
			rc = ksmbd_vfs_kern_path(name, LOOKUP_FOLLOW, &path, 1);
			if (rc) { /* Case for broken link ?*/
				rc = ksmbd_vfs_kern_path(name, 0, &path, 1);
			}
		} else {
			rc = ksmbd_vfs_kern_path(name, 0, &path, 1);
			if (!rc && d_is_symlink(path.dentry)) {
		} else if (d_is_symlink(path.dentry)) {
			rc = -EACCES;
			path_put(&path);
			goto err_out;
		}
	}
	}

	if (rc) {
		if (rc == -EACCES) {
@@ -4751,12 +4732,8 @@ 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;

	if (test_share_config_flag(share, KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS))
		lookup_flags = LOOKUP_FOLLOW;

	rc = ksmbd_vfs_kern_path(share->path, lookup_flags, &path, 0);
	rc = ksmbd_vfs_kern_path(share->path, LOOKUP_NO_SYMLINKS, &path, 0);
	if (rc) {
		pr_err("cannot create vfs path\n");
		return -EIO;
@@ -5333,7 +5310,7 @@ static int smb2_rename(struct ksmbd_work *work,
	}

	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_NO_SYMLINKS, &path, 1);
	if (rc)
		file_present = false;
	else
@@ -5407,7 +5384,7 @@ static int smb2_create_link(struct ksmbd_work *work,
	}

	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_NO_SYMLINKS, &path, 0);
	if (rc)
		file_present = false;
	else
+9 −23
Original line number Diff line number Diff line
@@ -166,7 +166,7 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode)
	struct dentry *dentry;
	int err;

	dentry = kern_path_create(AT_FDCWD, name, &path, 0);
	dentry = kern_path_create(AT_FDCWD, name, &path, LOOKUP_NO_SYMLINKS);
	if (IS_ERR(dentry)) {
		err = PTR_ERR(dentry);
		if (err != -ENOENT)
@@ -203,7 +203,8 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode)
	struct dentry *dentry;
	int err;

	dentry = kern_path_create(AT_FDCWD, name, &path, LOOKUP_DIRECTORY);
	dentry = kern_path_create(AT_FDCWD, name, &path,
				  LOOKUP_NO_SYMLINKS | LOOKUP_DIRECTORY);
	if (IS_ERR(dentry)) {
		err = PTR_ERR(dentry);
		if (err != -EEXIST)
@@ -588,16 +589,11 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name)
	struct path path;
	struct dentry *parent;
	int err;
	int flags = 0;

	if (ksmbd_override_fsids(work))
		return -ENOMEM;

	if (test_share_config_flag(work->tcon->share_conf,
				   KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS))
		flags = LOOKUP_FOLLOW;

	err = kern_path(name, flags, &path);
	err = kern_path(name, LOOKUP_NO_SYMLINKS, &path);
	if (err) {
		ksmbd_debug(VFS, "can't get %s, err %d\n", name, err);
		ksmbd_revert_fsids(work);
@@ -652,16 +648,11 @@ int ksmbd_vfs_link(struct ksmbd_work *work, const char *oldname,
	struct path oldpath, newpath;
	struct dentry *dentry;
	int err;
	int flags = 0;

	if (ksmbd_override_fsids(work))
		return -ENOMEM;

	if (test_share_config_flag(work->tcon->share_conf,
				   KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS))
		flags = LOOKUP_FOLLOW;

	err = kern_path(oldname, flags, &oldpath);
	err = kern_path(oldname, LOOKUP_NO_SYMLINKS, &oldpath);
	if (err) {
		pr_err("cannot get linux path for %s, err = %d\n",
		       oldname, err);
@@ -669,7 +660,7 @@ int ksmbd_vfs_link(struct ksmbd_work *work, const char *oldname,
	}

	dentry = kern_path_create(AT_FDCWD, newname, &newpath,
				  flags | LOOKUP_REVAL);
				  LOOKUP_NO_SYMLINKS | LOOKUP_REVAL);
	if (IS_ERR(dentry)) {
		err = PTR_ERR(dentry);
		pr_err("path create err for %s, err %d\n", newname, err);
@@ -788,7 +779,6 @@ 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;

	dst_name = extract_last_component(newname);
	if (!dst_name)
@@ -797,12 +787,8 @@ int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
	src_dent_parent = dget_parent(fp->filp->f_path.dentry);
	src_dent = fp->filp->f_path.dentry;

	flags = LOOKUP_DIRECTORY;
	if (test_share_config_flag(work->tcon->share_conf,
				   KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS))
		flags |= LOOKUP_FOLLOW;

	err = kern_path(newname, flags, &dst_path);
	err = kern_path(newname, LOOKUP_NO_SYMLINKS | LOOKUP_DIRECTORY,
			&dst_path);
	if (err) {
		ksmbd_debug(VFS, "Cannot get path for %s [%d]\n", newname, err);
		goto out;
@@ -861,7 +847,7 @@ int ksmbd_vfs_truncate(struct ksmbd_work *work, const char *name,
	int err = 0;

	if (name) {
		err = kern_path(name, 0, &path);
		err = kern_path(name, LOOKUP_NO_SYMLINKS, &path);
		if (err) {
			pr_err("cannot get linux path for %s, err %d\n",
			       name, err);