linux-cifs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC][PATCHSET] hopefully saner handling of pathnames in cifs
@ 2021-03-20  4:31 Al Viro
  2021-03-20  4:32 ` [PATCH 1/7] cifs: don't cargo-cult strndup() Al Viro
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Al Viro @ 2021-03-20  4:31 UTC (permalink / raw)
  To: linux-cifs; +Cc: Steve French, linux-fsdevel

	Patch series (#work.cifs in vfs.git) tries to clean the things
up in and around build_path_from_dentry().  Part of that is constifying
the pointers around that stuff, then it lifts the allocations into
callers and finally switches build_path_from_dentry() to using
dentry_path_raw() instead of open-coding it.  Handling of ->d_name
and friends is subtle enough, and it would be better to have fewer
places besides fs/d_path.c that need to mess with those...

	Help with review and testing would be very much appreciated -
there's a plenty of mount options/server combinations ;-/

	For those who prefer to look at it in git, it lives in
git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git #work.cifs;
individual patches go in followups.

Shortlog:
Al Viro (7):
      cifs: don't cargo-cult strndup()
      cifs: constify get_normalized_path() properly
      cifs: constify path argument of ->make_node()
      cifs: constify pathname arguments in a bunch of helpers
      cifs: make build_path_from_dentry() return const char *
      cifs: allocate buffer in the caller of build_path_from_dentry()
      cifs: switch build_path_from_dentry() to using dentry_path_raw()

1) a bunch of kstrdup() calls got cargo-culted as kstrndup().
This is unidiomatic *and* pointless - it's not any "safer"
that way (pass it a non-NUL-terminated array, and strlen()
will barf same as kstrdup()) and it's actually a pessimization.
Converted to plain kstrdup() calls.

2) constifying pathnames: get_normalized_path() gets a
constant string and, on success, returns either that string
or its modified copy.  It is declared with the wrong prototype -
int get_normalized_path(const char *path, char **npath)
so the caller might get a non-const alias of the original const
string.  Fortunately, none of the callers actually use that
alias to modify the string, so it's not an active bug - just
the wrong typization.

3) constifying pathnames: ->make_node().  Unlike the rest of
methods that take pathname as an argument, it has that argument
declared as char *, not const char *.  Pure misannotation,
since all instances never modify that actual string (or pass it 
to anything that might do the same).

4) constifying pathnames: a bunch of helpers.  Several functions
have pathname argument declared as char *, when const char *
would be fine - they neither modify the string nor pass it to
anything that might.

5) constifying pathnames: build_path_from_dentry().
That's the main source of pathnames; all callers are actually
treating the string it returns as constant one.  Declare it
to return const char * and adjust the callers.

6) take buffer allocation out of build_path_from_dentry().
Trying to do exact-sized allocation is pointless - allocated
object are short-lived anyway (the caller is always the one
to free the string it gets from build_path_from_dentry()).
As the matter of fact, we are in the same situation as with
pathname arguments of syscalls - short-lived allocations
limited to 4Kb and freed before the caller returns to userland.
So we can just do allocations from names_cachep and do that
in the caller; that way we don't need to bother with GFP_ATOMIC
allocations.  Moreover, having the caller do allocations will
permit us to switch build_path_from_dentry() to use of dentry_path_raw()
(in the next commit).

7) build_path_from_dentry() essentially open-codes dentry_path_raw();
the difference is that it wants to put the result in the beginning
of the buffer (which we don't need anymore, since the caller knows
what to free anyway) _and_ we might want '\\' for component separator
instead of the normal '/'.  It's easier to use dentry_path_raw()
and (optionally) post-process the result, replacing all '/' with
'\\'.  Note that the last part needs profiling - I would expect it
to be noise (we have just formed the string and it's all in hot cache),
but that needs to be verified.

Diffstat:
 fs/cifs/cifs_dfs_ref.c |  14 +++--
 fs/cifs/cifsglob.h     |   2 +-
 fs/cifs/cifsproto.h    |  19 +++++--
 fs/cifs/connect.c      |   9 +--
 fs/cifs/dfs_cache.c    |  41 +++++++-------
 fs/cifs/dir.c          | 148 ++++++++++++++++++-------------------------------
 fs/cifs/file.c         |  79 +++++++++++++-------------
 fs/cifs/fs_context.c   |   2 +-
 fs/cifs/inode.c        | 110 ++++++++++++++++++------------------
 fs/cifs/ioctl.c        |  13 +++--
 fs/cifs/link.c         |  46 +++++++++------
 fs/cifs/misc.c         |   2 +-
 fs/cifs/readdir.c      |  15 ++---
 fs/cifs/smb1ops.c      |   6 +-
 fs/cifs/smb2ops.c      |  19 ++++---
 fs/cifs/unc.c          |   4 +-
 fs/cifs/xattr.c        |  40 +++++++------
 17 files changed, 278 insertions(+), 291 deletions(-)

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/7] cifs: don't cargo-cult strndup()
  2021-03-20  4:31 [RFC][PATCHSET] hopefully saner handling of pathnames in cifs Al Viro
@ 2021-03-20  4:32 ` Al Viro
  2021-03-20  4:32   ` [PATCH 2/7] cifs: constify get_normalized_path() properly Al Viro
                     ` (5 more replies)
  2021-03-21 19:58 ` [RFC][PATCHSET] hopefully saner handling of pathnames in cifs Steve French
  2021-03-22 12:25 ` Jeff Layton
  2 siblings, 6 replies; 17+ messages in thread
From: Al Viro @ 2021-03-20  4:32 UTC (permalink / raw)
  To: linux-cifs; +Cc: Steve French, linux-fsdevel

strndup(s, strlen(s)) is a highly unidiomatic way to spell strdup(s);
it's *NOT* safer in any way, since strlen() is just as sensitive to
NUL-termination as strdup() is.

strndup() is for situations when you need a copy of a known-sized
substring, not a magic security juju to drive the bad spirits away.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/cifs/cifs_dfs_ref.c |  2 +-
 fs/cifs/connect.c      |  9 +++------
 fs/cifs/dfs_cache.c    | 18 +++++++++---------
 fs/cifs/fs_context.c   |  2 +-
 fs/cifs/misc.c         |  2 +-
 fs/cifs/smb1ops.c      |  4 +---
 fs/cifs/unc.c          |  4 +---
 7 files changed, 17 insertions(+), 24 deletions(-)

diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index 6b1ce4efb591..ecee2864972d 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -270,7 +270,7 @@ static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt,
 	char *mountdata;
 	char *devname;
 
-	devname = kstrndup(fullpath, strlen(fullpath), GFP_KERNEL);
+	devname = kstrdup(fullpath, GFP_KERNEL);
 	if (!devname)
 		return ERR_PTR(-ENOMEM);
 
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 112692300fb6..6d77b945218b 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1770,9 +1770,7 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
 	 * for the request.
 	 */
 	if (is_domain && ses->domainName) {
-		ctx->domainname = kstrndup(ses->domainName,
-					   strlen(ses->domainName),
-					   GFP_KERNEL);
+		ctx->domainname = kstrdup(ses->domainName, GFP_KERNEL);
 		if (!ctx->domainname) {
 			cifs_dbg(FYI, "Unable to allocate %zd bytes for domain\n",
 				 len);
@@ -3411,8 +3409,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
 			goto error;
 	}
 	/* Save mount options */
-	mntdata = kstrndup(cifs_sb->ctx->mount_options,
-			   strlen(cifs_sb->ctx->mount_options), GFP_KERNEL);
+	mntdata = kstrdup(cifs_sb->ctx->mount_options, GFP_KERNEL);
 	if (!mntdata) {
 		rc = -ENOMEM;
 		goto error;
@@ -3485,7 +3482,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
 	 * links, the prefix path is included in both and may be changed during reconnect.  See
 	 * cifs_tree_connect().
 	 */
-	cifs_sb->origin_fullpath = kstrndup(full_path, strlen(full_path), GFP_KERNEL);
+	cifs_sb->origin_fullpath = kstrdup(full_path, GFP_KERNEL);
 	if (!cifs_sb->origin_fullpath) {
 		rc = -ENOMEM;
 		goto error;
diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c
index 098b4bc8da59..e4617ccf0a23 100644
--- a/fs/cifs/dfs_cache.c
+++ b/fs/cifs/dfs_cache.c
@@ -89,7 +89,7 @@ static int get_normalized_path(const char *path, char **npath)
 	if (*path == '\\') {
 		*npath = (char *)path;
 	} else {
-		*npath = kstrndup(path, strlen(path), GFP_KERNEL);
+		*npath = kstrdup(path, GFP_KERNEL);
 		if (!*npath)
 			return -ENOMEM;
 		convert_delimiter(*npath, '\\');
@@ -358,7 +358,7 @@ static struct cache_dfs_tgt *alloc_target(const char *name, int path_consumed)
 	t = kmalloc(sizeof(*t), GFP_ATOMIC);
 	if (!t)
 		return ERR_PTR(-ENOMEM);
-	t->name = kstrndup(name, strlen(name), GFP_ATOMIC);
+	t->name = kstrdup(name, GFP_ATOMIC);
 	if (!t->name) {
 		kfree(t);
 		return ERR_PTR(-ENOMEM);
@@ -419,7 +419,7 @@ static struct cache_entry *alloc_cache_entry(const char *path,
 	if (!ce)
 		return ERR_PTR(-ENOMEM);
 
-	ce->path = kstrndup(path, strlen(path), GFP_KERNEL);
+	ce->path = kstrdup(path, GFP_KERNEL);
 	if (!ce->path) {
 		kmem_cache_free(cache_slab, ce);
 		return ERR_PTR(-ENOMEM);
@@ -531,7 +531,7 @@ static struct cache_entry *lookup_cache_entry(const char *path, unsigned int *ha
 	char *s, *e;
 	char sep;
 
-	npath = kstrndup(path, strlen(path), GFP_KERNEL);
+	npath = kstrdup(path, GFP_KERNEL);
 	if (!npath)
 		return ERR_PTR(-ENOMEM);
 
@@ -641,7 +641,7 @@ static int __update_cache_entry(const char *path,
 
 	if (ce->tgthint) {
 		s = ce->tgthint->name;
-		th = kstrndup(s, strlen(s), GFP_ATOMIC);
+		th = kstrdup(s, GFP_ATOMIC);
 		if (!th)
 			return -ENOMEM;
 	}
@@ -786,11 +786,11 @@ static int setup_referral(const char *path, struct cache_entry *ce,
 
 	memset(ref, 0, sizeof(*ref));
 
-	ref->path_name = kstrndup(path, strlen(path), GFP_ATOMIC);
+	ref->path_name = kstrdup(path, GFP_ATOMIC);
 	if (!ref->path_name)
 		return -ENOMEM;
 
-	ref->node_name = kstrndup(target, strlen(target), GFP_ATOMIC);
+	ref->node_name = kstrdup(target, GFP_ATOMIC);
 	if (!ref->node_name) {
 		rc = -ENOMEM;
 		goto err_free_path;
@@ -828,7 +828,7 @@ static int get_targets(struct cache_entry *ce, struct dfs_cache_tgt_list *tl)
 			goto err_free_it;
 		}
 
-		it->it_name = kstrndup(t->name, strlen(t->name), GFP_ATOMIC);
+		it->it_name = kstrdup(t->name, GFP_ATOMIC);
 		if (!it->it_name) {
 			kfree(it);
 			rc = -ENOMEM;
@@ -1166,7 +1166,7 @@ int dfs_cache_add_vol(char *mntdata, struct smb3_fs_context *ctx, const char *fu
 	if (!vi)
 		return -ENOMEM;
 
-	vi->fullpath = kstrndup(fullpath, strlen(fullpath), GFP_KERNEL);
+	vi->fullpath = kstrdup(fullpath, GFP_KERNEL);
 	if (!vi->fullpath) {
 		rc = -ENOMEM;
 		goto err_free_vi;
diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c
index 892f51a21278..472b543adc45 100644
--- a/fs/cifs/fs_context.c
+++ b/fs/cifs/fs_context.c
@@ -430,7 +430,7 @@ int smb3_parse_opt(const char *options, const char *key, char **val)
 			if (nval == p)
 				continue;
 			*nval++ = 0;
-			*val = kstrndup(nval, strlen(nval), GFP_KERNEL);
+			*val = kstrdup(nval, GFP_KERNEL);
 			rc = !*val ? -ENOMEM : 0;
 			goto out;
 		}
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 82e176720ca6..c15a90e422be 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -1180,7 +1180,7 @@ int update_super_prepath(struct cifs_tcon *tcon, char *prefix)
 	kfree(cifs_sb->prepath);
 
 	if (prefix && *prefix) {
-		cifs_sb->prepath = kstrndup(prefix, strlen(prefix), GFP_ATOMIC);
+		cifs_sb->prepath = kstrdup(prefix, GFP_ATOMIC);
 		if (!cifs_sb->prepath) {
 			rc = -ENOMEM;
 			goto out;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index e31b939e628c..85fa254c7a6b 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -926,9 +926,7 @@ cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon,
 			  0);
 
 	if (!rc) {
-		*symlinkinfo = kstrndup(referral.node_name,
-					strlen(referral.node_name),
-					GFP_KERNEL);
+		*symlinkinfo = kstrdup(referral.node_name, GFP_KERNEL);
 		free_dfs_info_param(&referral);
 		if (!*symlinkinfo)
 			rc = -ENOMEM;
diff --git a/fs/cifs/unc.c b/fs/cifs/unc.c
index 394aa00cea40..f6fc5e343ea4 100644
--- a/fs/cifs/unc.c
+++ b/fs/cifs/unc.c
@@ -50,7 +50,6 @@ char *extract_sharename(const char *unc)
 {
 	const char *src;
 	char *delim, *dst;
-	int len;
 
 	/* skip double chars at the beginning */
 	src = unc + 2;
@@ -60,10 +59,9 @@ char *extract_sharename(const char *unc)
 	if (!delim)
 		return ERR_PTR(-EINVAL);
 	delim++;
-	len = strlen(delim);
 
 	/* caller has to free the memory */
-	dst = kstrndup(delim, len, GFP_KERNEL);
+	dst = kstrdup(delim, GFP_KERNEL);
 	if (!dst)
 		return ERR_PTR(-ENOMEM);
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 2/7] cifs: constify get_normalized_path() properly
  2021-03-20  4:32 ` [PATCH 1/7] cifs: don't cargo-cult strndup() Al Viro
@ 2021-03-20  4:32   ` Al Viro
  2021-03-20  4:33   ` [PATCH 3/7] cifs: constify path argument of ->make_node() Al Viro
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Al Viro @ 2021-03-20  4:32 UTC (permalink / raw)
  To: linux-cifs; +Cc: Steve French, linux-fsdevel

As it is, it takes const char * and, in some cases, stores it in
caller's variable that is plain char *.  Fortunately, none of the
callers actually proceeded to modify the string via now-non-const
alias, but that's trouble waiting to happen.

It's easy to do properly, anyway...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/cifs/dfs_cache.c | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c
index e4617ccf0a23..b1fa30fefe1f 100644
--- a/fs/cifs/dfs_cache.c
+++ b/fs/cifs/dfs_cache.c
@@ -81,23 +81,24 @@ static void refresh_cache_worker(struct work_struct *work);
 
 static DECLARE_DELAYED_WORK(refresh_task, refresh_cache_worker);
 
-static int get_normalized_path(const char *path, char **npath)
+static int get_normalized_path(const char *path, const char **npath)
 {
 	if (!path || strlen(path) < 3 || (*path != '\\' && *path != '/'))
 		return -EINVAL;
 
 	if (*path == '\\') {
-		*npath = (char *)path;
+		*npath = path;
 	} else {
-		*npath = kstrdup(path, GFP_KERNEL);
-		if (!*npath)
+		char *s = kstrdup(path, GFP_KERNEL);
+		if (!s)
 			return -ENOMEM;
-		convert_delimiter(*npath, '\\');
+		convert_delimiter(s, '\\');
+		*npath = s;
 	}
 	return 0;
 }
 
-static inline void free_normalized_path(const char *path, char *npath)
+static inline void free_normalized_path(const char *path, const char *npath)
 {
 	if (path != npath)
 		kfree(npath);
@@ -882,7 +883,7 @@ int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
 		   struct dfs_cache_tgt_list *tgt_list)
 {
 	int rc;
-	char *npath;
+	const char *npath;
 	struct cache_entry *ce;
 
 	rc = get_normalized_path(path, &npath);
@@ -936,7 +937,7 @@ int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref,
 			 struct dfs_cache_tgt_list *tgt_list)
 {
 	int rc;
-	char *npath;
+	const char *npath;
 	struct cache_entry *ce;
 
 	rc = get_normalized_path(path, &npath);
@@ -991,7 +992,7 @@ int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
 			     const struct dfs_cache_tgt_iterator *it)
 {
 	int rc;
-	char *npath;
+	const char *npath;
 	struct cache_entry *ce;
 	struct cache_dfs_tgt *t;
 
@@ -1053,7 +1054,7 @@ int dfs_cache_noreq_update_tgthint(const char *path,
 				   const struct dfs_cache_tgt_iterator *it)
 {
 	int rc;
-	char *npath;
+	const char *npath;
 	struct cache_entry *ce;
 	struct cache_dfs_tgt *t;
 
@@ -1111,7 +1112,7 @@ int dfs_cache_get_tgt_referral(const char *path,
 			       struct dfs_info3_param *ref)
 {
 	int rc;
-	char *npath;
+	const char *npath;
 	struct cache_entry *ce;
 
 	if (!it || !ref)
@@ -1484,7 +1485,7 @@ static int refresh_tcon(struct vol_info *vi, struct cifs_tcon *tcon)
 {
 	int rc = 0;
 	unsigned int xid;
-	char *path, *npath;
+	const char *path, *npath;
 	struct cache_entry *ce;
 	struct cifs_ses *root_ses = NULL, *ses;
 	struct dfs_info3_param *refs = NULL;
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 3/7] cifs: constify path argument of ->make_node()
  2021-03-20  4:32 ` [PATCH 1/7] cifs: don't cargo-cult strndup() Al Viro
  2021-03-20  4:32   ` [PATCH 2/7] cifs: constify get_normalized_path() properly Al Viro
@ 2021-03-20  4:33   ` Al Viro
  2021-03-20  4:33   ` [PATCH 4/7] cifs: constify pathname arguments in a bunch of helpers Al Viro
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Al Viro @ 2021-03-20  4:33 UTC (permalink / raw)
  To: linux-cifs; +Cc: Steve French, linux-fsdevel

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/cifs/cifsglob.h | 2 +-
 fs/cifs/smb1ops.c  | 2 +-
 fs/cifs/smb2ops.c  | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3de3c5908a72..cc328cd7867c 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -495,7 +495,7 @@ struct smb_version_operations {
 			 struct inode *inode,
 			 struct dentry *dentry,
 			 struct cifs_tcon *tcon,
-			 char *full_path,
+			 const char *full_path,
 			 umode_t mode,
 			 dev_t device_number);
 	/* version specific fiemap implementation */
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 85fa254c7a6b..3b83839fc2c2 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -1025,7 +1025,7 @@ cifs_can_echo(struct TCP_Server_Info *server)
 static int
 cifs_make_node(unsigned int xid, struct inode *inode,
 	       struct dentry *dentry, struct cifs_tcon *tcon,
-	       char *full_path, umode_t mode, dev_t dev)
+	       const char *full_path, umode_t mode, dev_t dev)
 {
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct inode *newinode = NULL;
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index f5087295424c..372ed85472b1 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -4955,7 +4955,7 @@ smb2_next_header(char *buf)
 static int
 smb2_make_node(unsigned int xid, struct inode *inode,
 	       struct dentry *dentry, struct cifs_tcon *tcon,
-	       char *full_path, umode_t mode, dev_t dev)
+	       const char *full_path, umode_t mode, dev_t dev)
 {
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	int rc = -EPERM;
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 4/7] cifs: constify pathname arguments in a bunch of helpers
  2021-03-20  4:32 ` [PATCH 1/7] cifs: don't cargo-cult strndup() Al Viro
  2021-03-20  4:32   ` [PATCH 2/7] cifs: constify get_normalized_path() properly Al Viro
  2021-03-20  4:33   ` [PATCH 3/7] cifs: constify path argument of ->make_node() Al Viro
@ 2021-03-20  4:33   ` Al Viro
  2021-03-20  4:33   ` [PATCH 5/7] cifs: make build_path_from_dentry() return const char * Al Viro
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Al Viro @ 2021-03-20  4:33 UTC (permalink / raw)
  To: linux-cifs; +Cc: Steve French, linux-fsdevel

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/cifs/cifsproto.h | 4 ++--
 fs/cifs/file.c      | 4 ++--
 fs/cifs/inode.c     | 4 ++--
 fs/cifs/readdir.c   | 4 ++--
 fs/cifs/xattr.c     | 4 ++--
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 75ce6f742b8d..ef6bc1a80c9a 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -184,7 +184,7 @@ extern struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid,
 					      struct file *file,
 					      struct tcon_link *tlink,
 					      __u32 oplock);
-extern int cifs_posix_open(char *full_path, struct inode **inode,
+extern int cifs_posix_open(const char *full_path, struct inode **inode,
 			   struct super_block *sb, int mode,
 			   unsigned int f_flags, __u32 *oplock, __u16 *netfid,
 			   unsigned int xid);
@@ -207,7 +207,7 @@ extern int cifs_get_inode_info_unix(struct inode **pinode,
 			const unsigned char *search_path,
 			struct super_block *sb, unsigned int xid);
 extern int cifs_set_file_info(struct inode *inode, struct iattr *attrs,
-			      unsigned int xid, char *full_path, __u32 dosattr);
+			      unsigned int xid, const char *full_path, __u32 dosattr);
 extern int cifs_rename_pending_delete(const char *full_path,
 				      struct dentry *dentry,
 				      const unsigned int xid);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 26de4329d161..db0a42006995 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -112,7 +112,7 @@ static inline int cifs_get_disposition(unsigned int flags)
 		return FILE_OPEN;
 }
 
-int cifs_posix_open(char *full_path, struct inode **pinode,
+int cifs_posix_open(const char *full_path, struct inode **pinode,
 			struct super_block *sb, int mode, unsigned int f_flags,
 			__u32 *poplock, __u16 *pnetfid, unsigned int xid)
 {
@@ -174,7 +174,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
 }
 
 static int
-cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
+cifs_nt_open(const char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
 	     struct cifs_tcon *tcon, unsigned int f_flags, __u32 *oplock,
 	     struct cifs_fid *fid, unsigned int xid)
 {
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 7c61bc9573c0..d61dd8b48959 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1408,7 +1408,7 @@ struct inode *cifs_root_iget(struct super_block *sb)
 
 int
 cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
-		   char *full_path, __u32 dosattr)
+		   const char *full_path, __u32 dosattr)
 {
 	bool set_time = false;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -2522,7 +2522,7 @@ void cifs_setsize(struct inode *inode, loff_t offset)
 
 static int
 cifs_set_file_size(struct inode *inode, struct iattr *attrs,
-		   unsigned int xid, char *full_path)
+		   unsigned int xid, const char *full_path)
 {
 	int rc;
 	struct cifsFileInfo *open_file;
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 80bf4c6f4c7b..7225b2cae3e6 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -384,7 +384,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
 
 static int
 initiate_cifs_search(const unsigned int xid, struct file *file,
-		     char *full_path)
+		     const char *full_path)
 {
 	__u16 search_flags;
 	int rc = 0;
@@ -704,7 +704,7 @@ static int cifs_save_resume_key(const char *current_entry,
  */
 static int
 find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
-		struct file *file, char *full_path,
+		struct file *file, const char *full_path,
 		char **current_entry, int *num_to_ret)
 {
 	__u16 search_flags;
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 41a611e76bb7..bac05dd6c5b3 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -53,7 +53,7 @@ enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT,
 	XATTR_CIFS_NTSD, XATTR_CIFS_NTSD_FULL };
 
 static int cifs_attrib_set(unsigned int xid, struct cifs_tcon *pTcon,
-			   struct inode *inode, char *full_path,
+			   struct inode *inode, const char *full_path,
 			   const void *value, size_t size)
 {
 	ssize_t rc = -EOPNOTSUPP;
@@ -77,7 +77,7 @@ static int cifs_attrib_set(unsigned int xid, struct cifs_tcon *pTcon,
 }
 
 static int cifs_creation_time_set(unsigned int xid, struct cifs_tcon *pTcon,
-				  struct inode *inode, char *full_path,
+				  struct inode *inode, const char *full_path,
 				  const void *value, size_t size)
 {
 	ssize_t rc = -EOPNOTSUPP;
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 5/7] cifs: make build_path_from_dentry() return const char *
  2021-03-20  4:32 ` [PATCH 1/7] cifs: don't cargo-cult strndup() Al Viro
                     ` (2 preceding siblings ...)
  2021-03-20  4:33   ` [PATCH 4/7] cifs: constify pathname arguments in a bunch of helpers Al Viro
@ 2021-03-20  4:33   ` Al Viro
  2021-03-20  4:33   ` [PATCH 6/7] cifs: allocate buffer in the caller of build_path_from_dentry() Al Viro
  2021-03-20  4:33   ` [PATCH 7/7] cifs: switch build_path_from_dentry() to using dentry_path_raw() Al Viro
  5 siblings, 0 replies; 17+ messages in thread
From: Al Viro @ 2021-03-20  4:33 UTC (permalink / raw)
  To: linux-cifs; +Cc: Steve French, linux-fsdevel

... and adjust the callers.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/cifs/cifsproto.h |  2 +-
 fs/cifs/dir.c       |  8 ++++----
 fs/cifs/file.c      |  8 ++++----
 fs/cifs/inode.c     | 16 ++++++++--------
 fs/cifs/ioctl.c     |  2 +-
 fs/cifs/link.c      |  8 ++++----
 fs/cifs/readdir.c   |  2 +-
 fs/cifs/smb2ops.c   |  2 +-
 fs/cifs/xattr.c     |  6 +++---
 9 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index ef6bc1a80c9a..50894e576e13 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -69,7 +69,7 @@ extern int init_cifs_idmap(void);
 extern void exit_cifs_idmap(void);
 extern int init_cifs_spnego(void);
 extern void exit_cifs_spnego(void);
-extern char *build_path_from_dentry(struct dentry *);
+extern const char *build_path_from_dentry(struct dentry *);
 extern char *build_path_from_dentry_optional_prefix(struct dentry *direntry,
 						    bool prefix);
 extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index a3fb81e0ba17..01e26f811885 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -78,7 +78,7 @@ cifs_build_path_to_root(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_s
 }
 
 /* Note: caller must free return buffer */
-char *
+const char *
 build_path_from_dentry(struct dentry *direntry)
 {
 	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
@@ -233,7 +233,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 	int desired_access;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct cifs_tcon *tcon = tlink_tcon(tlink);
-	char *full_path = NULL;
+	const char *full_path = NULL;
 	FILE_ALL_INFO *buf = NULL;
 	struct inode *newinode = NULL;
 	int disposition;
@@ -619,7 +619,7 @@ int cifs_mknod(struct user_namespace *mnt_userns, struct inode *inode,
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
-	char *full_path = NULL;
+	const char *full_path = NULL;
 
 	if (!old_valid_dev(device_number))
 		return -EINVAL;
@@ -660,7 +660,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
 	struct inode *newInode = NULL;
-	char *full_path = NULL;
+	const char *full_path = NULL;
 
 	xid = get_xid();
 
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index db0a42006995..f4946c06a00c 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -529,7 +529,7 @@ int cifs_open(struct inode *inode, struct file *file)
 	struct cifs_tcon *tcon;
 	struct tcon_link *tlink;
 	struct cifsFileInfo *cfile = NULL;
-	char *full_path = NULL;
+	const char *full_path = NULL;
 	bool posix_open_ok = false;
 	struct cifs_fid fid;
 	struct cifs_pending_open open;
@@ -688,7 +688,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
 	struct TCP_Server_Info *server;
 	struct cifsInodeInfo *cinode;
 	struct inode *inode;
-	char *full_path = NULL;
+	const char *full_path = NULL;
 	int desired_access;
 	int disposition = FILE_OPEN;
 	int create_options = CREATE_NOT_DIR;
@@ -2071,7 +2071,7 @@ cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
 	struct list_head *tmp;
 	struct cifsFileInfo *cfile;
 	struct cifsInodeInfo *cinode;
-	char *full_path;
+	const char *full_path;
 
 	*ret_file = NULL;
 
@@ -2106,7 +2106,7 @@ cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
 	struct list_head *tmp;
 	struct cifsFileInfo *cfile;
 	struct cifsInodeInfo *cinode;
-	char *full_path;
+	const char *full_path;
 
 	*ret_file = NULL;
 
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index d61dd8b48959..a6d3b8e7ca70 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1609,7 +1609,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 {
 	int rc = 0;
 	unsigned int xid;
-	char *full_path = NULL;
+	const char *full_path = NULL;
 	struct inode *inode = d_inode(dentry);
 	struct cifsInodeInfo *cifs_inode;
 	struct super_block *sb = dir->i_sb;
@@ -1866,7 +1866,7 @@ int cifs_mkdir(struct user_namespace *mnt_userns, struct inode *inode,
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
 	struct TCP_Server_Info *server;
-	char *full_path;
+	const char *full_path;
 
 	cifs_dbg(FYI, "In cifs_mkdir, mode = %04ho inode = 0x%p\n",
 		 mode, inode);
@@ -1938,7 +1938,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
 	struct TCP_Server_Info *server;
-	char *full_path = NULL;
+	const char *full_path = NULL;
 	struct cifsInodeInfo *cifsInode;
 
 	cifs_dbg(FYI, "cifs_rmdir, inode = 0x%p\n", inode);
@@ -2072,8 +2072,8 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir,
 	     struct dentry *source_dentry, struct inode *target_dir,
 	     struct dentry *target_dentry, unsigned int flags)
 {
-	char *from_name = NULL;
-	char *to_name = NULL;
+	const char *from_name = NULL;
+	const char *to_name = NULL;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
@@ -2317,7 +2317,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
 	int rc = 0;
 	struct inode *inode = d_inode(dentry);
 	struct super_block *sb = dentry->d_sb;
-	char *full_path = NULL;
+	const char *full_path = NULL;
 	int count = 0;
 
 	if (inode == NULL)
@@ -2605,7 +2605,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 {
 	int rc;
 	unsigned int xid;
-	char *full_path = NULL;
+	const char *full_path = NULL;
 	struct inode *inode = d_inode(direntry);
 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -2756,7 +2756,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifsFileInfo *wfile;
 	struct cifs_tcon *tcon;
-	char *full_path = NULL;
+	const char *full_path = NULL;
 	int rc = -EACCES;
 	__u32 dosattr = 0;
 	__u64 mode = NO_CHANGE_64;
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index dcde44ff6cf9..aba573dd86ac 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -42,7 +42,7 @@ static long cifs_ioctl_query_info(unsigned int xid, struct file *filep,
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 	struct dentry *dentry = filep->f_path.dentry;
-	unsigned char *path;
+	const unsigned char *path;
 	__le16 *utf16_path = NULL, root_path;
 	int rc = 0;
 
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 7c5878a645d9..18e0e31a6d39 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -510,8 +510,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
 {
 	int rc = -EACCES;
 	unsigned int xid;
-	char *from_name = NULL;
-	char *to_name = NULL;
+	const char *from_name = NULL;
+	const char *to_name = NULL;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
@@ -600,7 +600,7 @@ cifs_get_link(struct dentry *direntry, struct inode *inode,
 {
 	int rc = -ENOMEM;
 	unsigned int xid;
-	char *full_path = NULL;
+	const char *full_path = NULL;
 	char *target_path = NULL;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct tcon_link *tlink = NULL;
@@ -669,7 +669,7 @@ cifs_symlink(struct user_namespace *mnt_userns, struct inode *inode,
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
-	char *full_path = NULL;
+	const char *full_path = NULL;
 	struct inode *newinode = NULL;
 
 	xid = get_xid();
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 7225b2cae3e6..67c3177a1fda 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -942,7 +942,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
 	char *tmp_buf = NULL;
 	char *end_of_smb;
 	unsigned int max_len;
-	char *full_path = NULL;
+	const char *full_path = NULL;
 
 	xid = get_xid();
 
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 372ed85472b1..6a31b3dfebcd 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -2209,7 +2209,7 @@ smb3_notify(const unsigned int xid, struct file *pfile,
 	struct cifs_open_parms oparms;
 	struct cifs_fid fid;
 	struct cifs_tcon *tcon;
-	unsigned char *path = NULL;
+	const unsigned char *path = NULL;
 	__le16 *utf16_path = NULL;
 	u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 	int rc = 0;
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index bac05dd6c5b3..0195a9be3d28 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -112,7 +112,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
-	char *full_path;
+	const char *full_path;
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
@@ -297,7 +297,7 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
-	char *full_path;
+	const char *full_path;
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
@@ -414,7 +414,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
-	char *full_path;
+	const char *full_path;
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 		return -EOPNOTSUPP;
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 6/7] cifs: allocate buffer in the caller of build_path_from_dentry()
  2021-03-20  4:32 ` [PATCH 1/7] cifs: don't cargo-cult strndup() Al Viro
                     ` (3 preceding siblings ...)
  2021-03-20  4:33   ` [PATCH 5/7] cifs: make build_path_from_dentry() return const char * Al Viro
@ 2021-03-20  4:33   ` Al Viro
  2021-03-20  4:33   ` [PATCH 7/7] cifs: switch build_path_from_dentry() to using dentry_path_raw() Al Viro
  5 siblings, 0 replies; 17+ messages in thread
From: Al Viro @ 2021-03-20  4:33 UTC (permalink / raw)
  To: linux-cifs; +Cc: Steve French, linux-fsdevel

build_path_from_dentry() open-codes dentry_path_raw().  The reason
we can't use dentry_path_raw() in there (and postprocess the
result as needed) is that the callers of build_path_from_dentry()
expect that the object to be freed on cleanup and the string to
be used are at the same address.  That's painful, since the path
is naturally built end-to-beginning - we start at the leaf and
go through the ancestors, accumulating the pathname.

Life would be easier if we left the buffer allocation to callers.
It wouldn't be exact-sized buffer, but none of the callers keep
the result for long - it's always freed before the caller returns.
So there's no need to do exact-sized allocation; better use
__getname()/__putname(), same as we do for pathname arguments
of syscalls.  What's more, there's no need to do allocation under
spinlocks, so GFP_ATOMIC is not needed.

Next patch will replace the open-coded dentry_path_raw() (in
build_path_from_dentry_optional_prefix()) with calling the real
thing.  This patch only introduces wrappers for allocating/freeing
the buffers and switches to new calling conventions:
	build_path_from_dentry(dentry, buf)
expects buf to be address of a page-sized object or NULL,
return value is a pathname built inside that buffer on success,
ERR_PTR(-ENOMEM) if buf is NULL and ERR_PTR(-ENAMETOOLONG) if
the pathname won't fit into page.  Note that we don't need to
check for failure when allocating the buffer in the caller -
build_path_from_dentry() will do the right thing.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/cifs/cifs_dfs_ref.c |  12 ++++--
 fs/cifs/cifsproto.h    |  15 ++++++-
 fs/cifs/dir.c          |  69 ++++++++++++++++----------------
 fs/cifs/file.c         |  75 +++++++++++++++++------------------
 fs/cifs/inode.c        | 104 +++++++++++++++++++++++++------------------------
 fs/cifs/ioctl.c        |  11 ++++--
 fs/cifs/link.c         |  46 +++++++++++++---------
 fs/cifs/readdir.c      |  11 +++---
 fs/cifs/smb2ops.c      |  17 ++++----
 fs/cifs/xattr.c        |  30 ++++++++------
 10 files changed, 212 insertions(+), 178 deletions(-)

diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index ecee2864972d..c87c37cf2914 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -302,6 +302,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
 	struct cifs_sb_info *cifs_sb;
 	struct cifs_ses *ses;
 	struct cifs_tcon *tcon;
+	void *page;
 	char *full_path, *root_path;
 	unsigned int xid;
 	int rc;
@@ -324,10 +325,13 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
 		goto cdda_exit;
 	}
 
+	page = alloc_dentry_path();
 	/* always use tree name prefix */
-	full_path = build_path_from_dentry_optional_prefix(mntpt, true);
-	if (full_path == NULL)
-		goto cdda_exit;
+	full_path = build_path_from_dentry_optional_prefix(mntpt, page, true);
+	if (IS_ERR(full_path)) {
+		mnt = ERR_CAST(full_path);
+		goto free_full_path;
+	}
 
 	convert_delimiter(full_path, '\\');
 
@@ -385,7 +389,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
 free_root_path:
 	kfree(root_path);
 free_full_path:
-	kfree(full_path);
+	free_dentry_path(page);
 cdda_exit:
 	cifs_dbg(FYI, "leaving %s\n" , __func__);
 	return mnt;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 50894e576e13..9d8ba7975753 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -69,9 +69,20 @@ extern int init_cifs_idmap(void);
 extern void exit_cifs_idmap(void);
 extern int init_cifs_spnego(void);
 extern void exit_cifs_spnego(void);
-extern const char *build_path_from_dentry(struct dentry *);
+extern const char *build_path_from_dentry(struct dentry *, void *);
 extern char *build_path_from_dentry_optional_prefix(struct dentry *direntry,
-						    bool prefix);
+						    void *page, bool prefix);
+static inline void *alloc_dentry_path(void)
+{
+	return __getname();
+}
+
+static inline void free_dentry_path(void *page)
+{
+	if (page)
+		__putname(page);
+}
+
 extern char *cifs_build_path_to_root(struct smb3_fs_context *ctx,
 				     struct cifs_sb_info *cifs_sb,
 				     struct cifs_tcon *tcon,
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 01e26f811885..6e855f004f50 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -79,29 +79,33 @@ cifs_build_path_to_root(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_s
 
 /* Note: caller must free return buffer */
 const char *
-build_path_from_dentry(struct dentry *direntry)
+build_path_from_dentry(struct dentry *direntry, void *page)
 {
 	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 	bool prefix = tcon->Flags & SMB_SHARE_IS_IN_DFS;
 
-	return build_path_from_dentry_optional_prefix(direntry,
+	return build_path_from_dentry_optional_prefix(direntry, page,
 						      prefix);
 }
 
 char *
-build_path_from_dentry_optional_prefix(struct dentry *direntry, bool prefix)
+build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
+				       bool prefix)
 {
 	struct dentry *temp;
 	int namelen;
 	int dfsplen;
 	int pplen = 0;
-	char *full_path;
+	char *full_path = page;
 	char dirsep;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 	unsigned seq;
 
+	if (unlikely(!page))
+		return ERR_PTR(-ENOMEM);
+
 	dirsep = CIFS_DIR_SEP(cifs_sb);
 	if (prefix)
 		dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
@@ -118,17 +122,12 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, bool prefix)
 	for (temp = direntry; !IS_ROOT(temp);) {
 		namelen += (1 + temp->d_name.len);
 		temp = temp->d_parent;
-		if (temp == NULL) {
-			cifs_dbg(VFS, "corrupt dentry\n");
-			rcu_read_unlock();
-			return NULL;
-		}
 	}
 	rcu_read_unlock();
 
-	full_path = kmalloc(namelen+1, GFP_ATOMIC);
-	if (full_path == NULL)
-		return full_path;
+	if (namelen >= PAGE_SIZE)
+		return ERR_PTR(-ENAMETOOLONG);
+
 	full_path[namelen] = 0;	/* trailing null */
 	rcu_read_lock();
 	for (temp = direntry; !IS_ROOT(temp);) {
@@ -145,12 +144,6 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, bool prefix)
 		}
 		spin_unlock(&temp->d_lock);
 		temp = temp->d_parent;
-		if (temp == NULL) {
-			cifs_dbg(VFS, "corrupt dentry\n");
-			rcu_read_unlock();
-			kfree(full_path);
-			return NULL;
-		}
 	}
 	rcu_read_unlock();
 	if (namelen != dfsplen + pplen || read_seqretry(&rename_lock, seq)) {
@@ -159,7 +152,6 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, bool prefix)
 		/* presumably this is only possible if racing with a rename
 		of one of the parent directories  (we can not lock the dentries
 		above us to prevent this, but retrying should be harmless) */
-		kfree(full_path);
 		goto cifs_bp_rename_retry;
 	}
 	/* DIR_SEP already set for byte  0 / vs \ but not for
@@ -233,7 +225,8 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 	int desired_access;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct cifs_tcon *tcon = tlink_tcon(tlink);
-	const char *full_path = NULL;
+	const char *full_path;
+	void *page = alloc_dentry_path();
 	FILE_ALL_INFO *buf = NULL;
 	struct inode *newinode = NULL;
 	int disposition;
@@ -244,9 +237,11 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 	if (tcon->ses->server->oplocks)
 		*oplock = REQ_OPLOCK;
 
-	full_path = build_path_from_dentry(direntry);
-	if (!full_path)
-		return -ENOMEM;
+	full_path = build_path_from_dentry(direntry, page);
+	if (IS_ERR(full_path)) {
+		free_dentry_path(page);
+		return PTR_ERR(full_path);
+	}
 
 	if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
 	    (CIFS_UNIX_POSIX_PATH_OPS_CAP &
@@ -448,7 +443,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 
 out:
 	kfree(buf);
-	kfree(full_path);
+	free_dentry_path(page);
 	return rc;
 
 out_err:
@@ -619,7 +614,8 @@ int cifs_mknod(struct user_namespace *mnt_userns, struct inode *inode,
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
-	const char *full_path = NULL;
+	const char *full_path;
+	void *page;
 
 	if (!old_valid_dev(device_number))
 		return -EINVAL;
@@ -629,13 +625,13 @@ int cifs_mknod(struct user_namespace *mnt_userns, struct inode *inode,
 	if (IS_ERR(tlink))
 		return PTR_ERR(tlink);
 
+	page = alloc_dentry_path();
 	tcon = tlink_tcon(tlink);
-
 	xid = get_xid();
 
-	full_path = build_path_from_dentry(direntry);
-	if (full_path == NULL) {
-		rc = -ENOMEM;
+	full_path = build_path_from_dentry(direntry, page);
+	if (IS_ERR(full_path)) {
+		rc = PTR_ERR(full_path);
 		goto mknod_out;
 	}
 
@@ -644,7 +640,7 @@ int cifs_mknod(struct user_namespace *mnt_userns, struct inode *inode,
 					       device_number);
 
 mknod_out:
-	kfree(full_path);
+	free_dentry_path(page);
 	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
@@ -660,7 +656,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
 	struct inode *newInode = NULL;
-	const char *full_path = NULL;
+	const char *full_path;
+	void *page;
 
 	xid = get_xid();
 
@@ -687,11 +684,13 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 	/* can not grab the rename sem here since it would
 	deadlock in the cases (beginning of sys_rename itself)
 	in which we already have the sb rename sem */
-	full_path = build_path_from_dentry(direntry);
-	if (full_path == NULL) {
+	page = alloc_dentry_path();
+	full_path = build_path_from_dentry(direntry, page);
+	if (IS_ERR(full_path)) {
 		cifs_put_tlink(tlink);
 		free_xid(xid);
-		return ERR_PTR(-ENOMEM);
+		free_dentry_path(page);
+		return ERR_CAST(full_path);
 	}
 
 	if (d_really_is_positive(direntry)) {
@@ -727,7 +726,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 		}
 		newInode = ERR_PTR(rc);
 	}
-	kfree(full_path);
+	free_dentry_path(page);
 	cifs_put_tlink(tlink);
 	free_xid(xid);
 	return d_splice_alias(newInode, direntry);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index f4946c06a00c..16e115c4cf25 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -529,7 +529,8 @@ int cifs_open(struct inode *inode, struct file *file)
 	struct cifs_tcon *tcon;
 	struct tcon_link *tlink;
 	struct cifsFileInfo *cfile = NULL;
-	const char *full_path = NULL;
+	void *page;
+	const char *full_path;
 	bool posix_open_ok = false;
 	struct cifs_fid fid;
 	struct cifs_pending_open open;
@@ -545,9 +546,10 @@ int cifs_open(struct inode *inode, struct file *file)
 	tcon = tlink_tcon(tlink);
 	server = tcon->ses->server;
 
-	full_path = build_path_from_dentry(file_dentry(file));
-	if (full_path == NULL) {
-		rc = -ENOMEM;
+	page = alloc_dentry_path();
+	full_path = build_path_from_dentry(file_dentry(file), page);
+	if (IS_ERR(full_path)) {
+		rc = PTR_ERR(full_path);
 		goto out;
 	}
 
@@ -639,7 +641,7 @@ int cifs_open(struct inode *inode, struct file *file)
 	}
 
 out:
-	kfree(full_path);
+	free_dentry_path(page);
 	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
@@ -688,7 +690,8 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
 	struct TCP_Server_Info *server;
 	struct cifsInodeInfo *cinode;
 	struct inode *inode;
-	const char *full_path = NULL;
+	void *page;
+	const char *full_path;
 	int desired_access;
 	int disposition = FILE_OPEN;
 	int create_options = CREATE_NOT_DIR;
@@ -698,9 +701,8 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
 	mutex_lock(&cfile->fh_mutex);
 	if (!cfile->invalidHandle) {
 		mutex_unlock(&cfile->fh_mutex);
-		rc = 0;
 		free_xid(xid);
-		return rc;
+		return 0;
 	}
 
 	inode = d_inode(cfile->dentry);
@@ -714,12 +716,13 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
 	 * called and if the server was down that means we end up here, and we
 	 * can never tell if the caller already has the rename_sem.
 	 */
-	full_path = build_path_from_dentry(cfile->dentry);
-	if (full_path == NULL) {
-		rc = -ENOMEM;
+	page = alloc_dentry_path();
+	full_path = build_path_from_dentry(cfile->dentry, page);
+	if (IS_ERR(full_path)) {
 		mutex_unlock(&cfile->fh_mutex);
+		free_dentry_path(page);
 		free_xid(xid);
-		return rc;
+		return PTR_ERR(full_path);
 	}
 
 	cifs_dbg(FYI, "inode = 0x%p file flags 0x%x for %s\n",
@@ -837,7 +840,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
 		cifs_relock_file(cfile);
 
 reopen_error_exit:
-	kfree(full_path);
+	free_dentry_path(page);
 	free_xid(xid);
 	return rc;
 }
@@ -2068,34 +2071,31 @@ cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
 		       int flags,
 		       struct cifsFileInfo **ret_file)
 {
-	struct list_head *tmp;
 	struct cifsFileInfo *cfile;
-	struct cifsInodeInfo *cinode;
-	const char *full_path;
+	void *page = alloc_dentry_path();
 
 	*ret_file = NULL;
 
 	spin_lock(&tcon->open_file_lock);
-	list_for_each(tmp, &tcon->openFileList) {
-		cfile = list_entry(tmp, struct cifsFileInfo,
-			     tlist);
-		full_path = build_path_from_dentry(cfile->dentry);
-		if (full_path == NULL) {
+	list_for_each_entry(cfile, &tcon->openFileList, tlist) {
+		struct cifsInodeInfo *cinode;
+		const char *full_path = build_path_from_dentry(cfile->dentry, page);
+		if (IS_ERR(full_path)) {
 			spin_unlock(&tcon->open_file_lock);
-			return -ENOMEM;
+			free_dentry_path(page);
+			return PTR_ERR(full_path);
 		}
-		if (strcmp(full_path, name)) {
-			kfree(full_path);
+		if (strcmp(full_path, name))
 			continue;
-		}
 
-		kfree(full_path);
 		cinode = CIFS_I(d_inode(cfile->dentry));
 		spin_unlock(&tcon->open_file_lock);
+		free_dentry_path(page);
 		return cifs_get_writable_file(cinode, flags, ret_file);
 	}
 
 	spin_unlock(&tcon->open_file_lock);
+	free_dentry_path(page);
 	return -ENOENT;
 }
 
@@ -2103,35 +2103,32 @@ int
 cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
 		       struct cifsFileInfo **ret_file)
 {
-	struct list_head *tmp;
 	struct cifsFileInfo *cfile;
-	struct cifsInodeInfo *cinode;
-	const char *full_path;
+	void *page = alloc_dentry_path();
 
 	*ret_file = NULL;
 
 	spin_lock(&tcon->open_file_lock);
-	list_for_each(tmp, &tcon->openFileList) {
-		cfile = list_entry(tmp, struct cifsFileInfo,
-			     tlist);
-		full_path = build_path_from_dentry(cfile->dentry);
-		if (full_path == NULL) {
+	list_for_each_entry(cfile, &tcon->openFileList, tlist) {
+		struct cifsInodeInfo *cinode;
+		const char *full_path = build_path_from_dentry(cfile->dentry, page);
+		if (IS_ERR(full_path)) {
 			spin_unlock(&tcon->open_file_lock);
-			return -ENOMEM;
+			free_dentry_path(page);
+			return PTR_ERR(full_path);
 		}
-		if (strcmp(full_path, name)) {
-			kfree(full_path);
+		if (strcmp(full_path, name))
 			continue;
-		}
 
-		kfree(full_path);
 		cinode = CIFS_I(d_inode(cfile->dentry));
 		spin_unlock(&tcon->open_file_lock);
+		free_dentry_path(page);
 		*ret_file = find_readable_file(cinode, 0);
 		return *ret_file ? 0 : -ENOENT;
 	}
 
 	spin_unlock(&tcon->open_file_lock);
+	free_dentry_path(page);
 	return -ENOENT;
 }
 
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index a6d3b8e7ca70..74d1a10e360b 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1609,7 +1609,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 {
 	int rc = 0;
 	unsigned int xid;
-	const char *full_path = NULL;
+	const char *full_path;
+	void *page;
 	struct inode *inode = d_inode(dentry);
 	struct cifsInodeInfo *cifs_inode;
 	struct super_block *sb = dir->i_sb;
@@ -1629,6 +1630,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 	server = tcon->ses->server;
 
 	xid = get_xid();
+	page = alloc_dentry_path();
 
 	if (tcon->nodelete) {
 		rc = -EACCES;
@@ -1637,9 +1639,9 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 
 	/* Unlink can be called from rename so we can not take the
 	 * sb->s_vfs_rename_mutex here */
-	full_path = build_path_from_dentry(dentry);
-	if (full_path == NULL) {
-		rc = -ENOMEM;
+	full_path = build_path_from_dentry(dentry, page);
+	if (IS_ERR(full_path)) {
+		rc = PTR_ERR(full_path);
 		goto unlink_out;
 	}
 
@@ -1713,7 +1715,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 	cifs_inode = CIFS_I(dir);
 	CIFS_I(dir)->time = 0;	/* force revalidate of dir as well */
 unlink_out:
-	kfree(full_path);
+	free_dentry_path(page);
 	kfree(attrs);
 	free_xid(xid);
 	cifs_put_tlink(tlink);
@@ -1867,6 +1869,7 @@ int cifs_mkdir(struct user_namespace *mnt_userns, struct inode *inode,
 	struct cifs_tcon *tcon;
 	struct TCP_Server_Info *server;
 	const char *full_path;
+	void *page;
 
 	cifs_dbg(FYI, "In cifs_mkdir, mode = %04ho inode = 0x%p\n",
 		 mode, inode);
@@ -1879,9 +1882,10 @@ int cifs_mkdir(struct user_namespace *mnt_userns, struct inode *inode,
 
 	xid = get_xid();
 
-	full_path = build_path_from_dentry(direntry);
-	if (full_path == NULL) {
-		rc = -ENOMEM;
+	page = alloc_dentry_path();
+	full_path = build_path_from_dentry(direntry, page);
+	if (IS_ERR(full_path)) {
+		rc = PTR_ERR(full_path);
 		goto mkdir_out;
 	}
 
@@ -1924,7 +1928,7 @@ int cifs_mkdir(struct user_namespace *mnt_userns, struct inode *inode,
 	 * attributes are invalid now.
 	 */
 	CIFS_I(inode)->time = 0;
-	kfree(full_path);
+	free_dentry_path(page);
 	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
@@ -1938,16 +1942,17 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
 	struct TCP_Server_Info *server;
-	const char *full_path = NULL;
+	const char *full_path;
+	void *page = alloc_dentry_path();
 	struct cifsInodeInfo *cifsInode;
 
 	cifs_dbg(FYI, "cifs_rmdir, inode = 0x%p\n", inode);
 
 	xid = get_xid();
 
-	full_path = build_path_from_dentry(direntry);
-	if (full_path == NULL) {
-		rc = -ENOMEM;
+	full_path = build_path_from_dentry(direntry, page);
+	if (IS_ERR(full_path)) {
+		rc = PTR_ERR(full_path);
 		goto rmdir_exit;
 	}
 
@@ -1997,7 +2002,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
 		current_time(inode);
 
 rmdir_exit:
-	kfree(full_path);
+	free_dentry_path(page);
 	free_xid(xid);
 	return rc;
 }
@@ -2072,8 +2077,8 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir,
 	     struct dentry *source_dentry, struct inode *target_dir,
 	     struct dentry *target_dentry, unsigned int flags)
 {
-	const char *from_name = NULL;
-	const char *to_name = NULL;
+	const char *from_name, *to_name;
+	void *page1, *page2;
 	struct cifs_sb_info *cifs_sb;
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
@@ -2091,21 +2096,19 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir,
 		return PTR_ERR(tlink);
 	tcon = tlink_tcon(tlink);
 
+	page1 = alloc_dentry_path();
+	page2 = alloc_dentry_path();
 	xid = get_xid();
 
-	/*
-	 * we already have the rename sem so we do not need to
-	 * grab it again here to protect the path integrity
-	 */
-	from_name = build_path_from_dentry(source_dentry);
-	if (from_name == NULL) {
-		rc = -ENOMEM;
+	from_name = build_path_from_dentry(source_dentry, page1);
+	if (IS_ERR(from_name)) {
+		rc = PTR_ERR(from_name);
 		goto cifs_rename_exit;
 	}
 
-	to_name = build_path_from_dentry(target_dentry);
-	if (to_name == NULL) {
-		rc = -ENOMEM;
+	to_name = build_path_from_dentry(target_dentry, page2);
+	if (IS_ERR(to_name)) {
+		rc = PTR_ERR(to_name);
 		goto cifs_rename_exit;
 	}
 
@@ -2177,8 +2180,8 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir,
 
 cifs_rename_exit:
 	kfree(info_buf_source);
-	kfree(from_name);
-	kfree(to_name);
+	free_dentry_path(page2);
+	free_dentry_path(page1);
 	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
@@ -2317,7 +2320,8 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
 	int rc = 0;
 	struct inode *inode = d_inode(dentry);
 	struct super_block *sb = dentry->d_sb;
-	const char *full_path = NULL;
+	const char *full_path;
+	void *page;
 	int count = 0;
 
 	if (inode == NULL)
@@ -2328,11 +2332,10 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
 
 	xid = get_xid();
 
-	/* can not safely grab the rename sem here if rename calls revalidate
-	   since that would deadlock */
-	full_path = build_path_from_dentry(dentry);
-	if (full_path == NULL) {
-		rc = -ENOMEM;
+	page = alloc_dentry_path();
+	full_path = build_path_from_dentry(dentry, page);
+	if (IS_ERR(full_path)) {
+		rc = PTR_ERR(full_path);
 		goto out;
 	}
 
@@ -2351,7 +2354,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
 	if (rc == -EAGAIN && count++ < 10)
 		goto again;
 out:
-	kfree(full_path);
+	free_dentry_path(page);
 	free_xid(xid);
 
 	return rc;
@@ -2605,7 +2608,8 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 {
 	int rc;
 	unsigned int xid;
-	const char *full_path = NULL;
+	const char *full_path;
+	void *page = alloc_dentry_path();
 	struct inode *inode = d_inode(direntry);
 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -2626,9 +2630,9 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 	if (rc < 0)
 		goto out;
 
-	full_path = build_path_from_dentry(direntry);
-	if (full_path == NULL) {
-		rc = -ENOMEM;
+	full_path = build_path_from_dentry(direntry, page);
+	if (IS_ERR(full_path)) {
+		rc = PTR_ERR(full_path);
 		goto out;
 	}
 
@@ -2740,7 +2744,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 		cifsInode->time = 0;
 out:
 	kfree(args);
-	kfree(full_path);
+	free_dentry_path(page);
 	free_xid(xid);
 	return rc;
 }
@@ -2756,7 +2760,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
 	struct cifsFileInfo *wfile;
 	struct cifs_tcon *tcon;
-	const char *full_path = NULL;
+	const char *full_path;
+	void *page = alloc_dentry_path();
 	int rc = -EACCES;
 	__u32 dosattr = 0;
 	__u64 mode = NO_CHANGE_64;
@@ -2770,16 +2775,13 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 		attrs->ia_valid |= ATTR_FORCE;
 
 	rc = setattr_prepare(&init_user_ns, direntry, attrs);
-	if (rc < 0) {
-		free_xid(xid);
-		return rc;
-	}
+	if (rc < 0)
+		goto cifs_setattr_exit;
 
-	full_path = build_path_from_dentry(direntry);
-	if (full_path == NULL) {
-		rc = -ENOMEM;
-		free_xid(xid);
-		return rc;
+	full_path = build_path_from_dentry(direntry, page);
+	if (IS_ERR(full_path)) {
+		rc = PTR_ERR(full_path);
+		goto cifs_setattr_exit;
 	}
 
 	/*
@@ -2929,8 +2931,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 	mark_inode_dirty(inode);
 
 cifs_setattr_exit:
-	kfree(full_path);
 	free_xid(xid);
+	free_dentry_path(page);
 	return rc;
 }
 
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index aba573dd86ac..08d99fec593e 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -43,12 +43,15 @@ static long cifs_ioctl_query_info(unsigned int xid, struct file *filep,
 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 	struct dentry *dentry = filep->f_path.dentry;
 	const unsigned char *path;
+	void *page = alloc_dentry_path();
 	__le16 *utf16_path = NULL, root_path;
 	int rc = 0;
 
-	path = build_path_from_dentry(dentry);
-	if (path == NULL)
-		return -ENOMEM;
+	path = build_path_from_dentry(dentry, page);
+	if (IS_ERR(path)) {
+		free_dentry_path(page);
+		return PTR_ERR(path);
+	}
 
 	cifs_dbg(FYI, "%s %s\n", __func__, path);
 
@@ -73,7 +76,7 @@ static long cifs_ioctl_query_info(unsigned int xid, struct file *filep,
  ici_exit:
 	if (utf16_path != &root_path)
 		kfree(utf16_path);
-	kfree(path);
+	free_dentry_path(page);
 	return rc;
 }
 
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 18e0e31a6d39..616e1bc0cc0a 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -510,8 +510,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
 {
 	int rc = -EACCES;
 	unsigned int xid;
-	const char *from_name = NULL;
-	const char *to_name = NULL;
+	const char *from_name, *to_name;
+	void *page1, *page2;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct tcon_link *tlink;
 	struct cifs_tcon *tcon;
@@ -524,11 +524,17 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
 	tcon = tlink_tcon(tlink);
 
 	xid = get_xid();
+	page1 = alloc_dentry_path();
+	page2 = alloc_dentry_path();
 
-	from_name = build_path_from_dentry(old_file);
-	to_name = build_path_from_dentry(direntry);
-	if ((from_name == NULL) || (to_name == NULL)) {
-		rc = -ENOMEM;
+	from_name = build_path_from_dentry(old_file, page1);
+	if (IS_ERR(from_name)) {
+		rc = PTR_ERR(from_name);
+		goto cifs_hl_exit;
+	}
+	to_name = build_path_from_dentry(direntry, page2);
+	if (IS_ERR(to_name)) {
+		rc = PTR_ERR(to_name);
 		goto cifs_hl_exit;
 	}
 
@@ -587,8 +593,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
 	}
 
 cifs_hl_exit:
-	kfree(from_name);
-	kfree(to_name);
+	free_dentry_path(page1);
+	free_dentry_path(page2);
 	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
@@ -600,7 +606,8 @@ cifs_get_link(struct dentry *direntry, struct inode *inode,
 {
 	int rc = -ENOMEM;
 	unsigned int xid;
-	const char *full_path = NULL;
+	const char *full_path;
+	void *page;
 	char *target_path = NULL;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct tcon_link *tlink = NULL;
@@ -620,11 +627,13 @@ cifs_get_link(struct dentry *direntry, struct inode *inode,
 	tcon = tlink_tcon(tlink);
 	server = tcon->ses->server;
 
-	full_path = build_path_from_dentry(direntry);
-	if (!full_path) {
+	page = alloc_dentry_path();
+	full_path = build_path_from_dentry(direntry, page);
+	if (IS_ERR(full_path)) {
 		free_xid(xid);
 		cifs_put_tlink(tlink);
-		return ERR_PTR(-ENOMEM);
+		free_dentry_path(page);
+		return ERR_CAST(full_path);
 	}
 
 	cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, inode);
@@ -649,7 +658,7 @@ cifs_get_link(struct dentry *direntry, struct inode *inode,
 						&target_path, reparse_point);
 	}
 
-	kfree(full_path);
+	free_dentry_path(page);
 	free_xid(xid);
 	cifs_put_tlink(tlink);
 	if (rc != 0) {
@@ -669,7 +678,8 @@ cifs_symlink(struct user_namespace *mnt_userns, struct inode *inode,
 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
-	const char *full_path = NULL;
+	const char *full_path;
+	void *page = alloc_dentry_path();
 	struct inode *newinode = NULL;
 
 	xid = get_xid();
@@ -681,9 +691,9 @@ cifs_symlink(struct user_namespace *mnt_userns, struct inode *inode,
 	}
 	pTcon = tlink_tcon(tlink);
 
-	full_path = build_path_from_dentry(direntry);
-	if (full_path == NULL) {
-		rc = -ENOMEM;
+	full_path = build_path_from_dentry(direntry, page);
+	if (IS_ERR(full_path)) {
+		rc = PTR_ERR(full_path);
 		goto symlink_exit;
 	}
 
@@ -719,7 +729,7 @@ cifs_symlink(struct user_namespace *mnt_userns, struct inode *inode,
 		}
 	}
 symlink_exit:
-	kfree(full_path);
+	free_dentry_path(page);
 	cifs_put_tlink(tlink);
 	free_xid(xid);
 	return rc;
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 67c3177a1fda..7531e8905881 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -942,13 +942,14 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
 	char *tmp_buf = NULL;
 	char *end_of_smb;
 	unsigned int max_len;
-	const char *full_path = NULL;
+	const char *full_path;
+	void *page = alloc_dentry_path();
 
 	xid = get_xid();
 
-	full_path = build_path_from_dentry(file_dentry(file));
-	if (full_path == NULL) {
-		rc = -ENOMEM;
+	full_path = build_path_from_dentry(file_dentry(file), page);
+	if (IS_ERR(full_path)) {
+		rc = PTR_ERR(full_path);
 		goto rddir2_exit;
 	}
 
@@ -1043,7 +1044,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
 	kfree(tmp_buf);
 
 rddir2_exit:
-	kfree(full_path);
+	free_dentry_path(page);
 	free_xid(xid);
 	return rc;
 }
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 6a31b3dfebcd..8e1cb4db4615 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -2205,20 +2205,21 @@ smb3_notify(const unsigned int xid, struct file *pfile,
 	struct smb3_notify notify;
 	struct dentry *dentry = pfile->f_path.dentry;
 	struct inode *inode = file_inode(pfile);
-	struct cifs_sb_info *cifs_sb;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 	struct cifs_open_parms oparms;
 	struct cifs_fid fid;
 	struct cifs_tcon *tcon;
-	const unsigned char *path = NULL;
+	const unsigned char *path;
+	void *page = alloc_dentry_path();
 	__le16 *utf16_path = NULL;
 	u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 	int rc = 0;
 
-	path = build_path_from_dentry(dentry);
-	if (path == NULL)
-		return -ENOMEM;
-
-	cifs_sb = CIFS_SB(inode->i_sb);
+	path = build_path_from_dentry(dentry, page);
+	if (IS_ERR(path)) {
+		rc = PTR_ERR(path);
+		goto notify_exit;
+	}
 
 	utf16_path = cifs_convert_path_to_utf16(path + 1, cifs_sb);
 	if (utf16_path == NULL) {
@@ -2252,7 +2253,7 @@ smb3_notify(const unsigned int xid, struct file *pfile,
 	cifs_dbg(FYI, "change notify for path %s rc %d\n", path, rc);
 
 notify_exit:
-	kfree(path);
+	free_dentry_path(page);
 	kfree(utf16_path);
 	return rc;
 }
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 0195a9be3d28..e351b945135b 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -113,6 +113,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
 	const char *full_path;
+	void *page;
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
@@ -120,10 +121,11 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
 	pTcon = tlink_tcon(tlink);
 
 	xid = get_xid();
+	page = alloc_dentry_path();
 
-	full_path = build_path_from_dentry(dentry);
-	if (full_path == NULL) {
-		rc = -ENOMEM;
+	full_path = build_path_from_dentry(dentry, page);
+	if (IS_ERR(full_path)) {
+		rc = PTR_ERR(full_path);
 		goto out;
 	}
 	/* return dos attributes as pseudo xattr */
@@ -235,7 +237,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
 	}
 
 out:
-	kfree(full_path);
+	free_dentry_path(page);
 	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
@@ -298,6 +300,7 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
 	const char *full_path;
+	void *page;
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
@@ -305,10 +308,11 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
 	pTcon = tlink_tcon(tlink);
 
 	xid = get_xid();
+	page = alloc_dentry_path();
 
-	full_path = build_path_from_dentry(dentry);
-	if (full_path == NULL) {
-		rc = -ENOMEM;
+	full_path = build_path_from_dentry(dentry, page);
+	if (IS_ERR(full_path)) {
+		rc = PTR_ERR(full_path);
 		goto out;
 	}
 
@@ -401,7 +405,7 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
 		rc = -EOPNOTSUPP;
 
 out:
-	kfree(full_path);
+	free_dentry_path(page);
 	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
@@ -415,6 +419,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 	struct tcon_link *tlink;
 	struct cifs_tcon *pTcon;
 	const char *full_path;
+	void *page;
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 		return -EOPNOTSUPP;
@@ -425,10 +430,11 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 	pTcon = tlink_tcon(tlink);
 
 	xid = get_xid();
+	page = alloc_dentry_path();
 
-	full_path = build_path_from_dentry(direntry);
-	if (full_path == NULL) {
-		rc = -ENOMEM;
+	full_path = build_path_from_dentry(direntry, page);
+	if (IS_ERR(full_path)) {
+		rc = PTR_ERR(full_path);
 		goto list_ea_exit;
 	}
 	/* return dos attributes as pseudo xattr */
@@ -442,7 +448,7 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
 		rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
 				full_path, NULL, data, buf_size, cifs_sb);
 list_ea_exit:
-	kfree(full_path);
+	free_dentry_path(page);
 	free_xid(xid);
 	cifs_put_tlink(tlink);
 	return rc;
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 7/7] cifs: switch build_path_from_dentry() to using dentry_path_raw()
  2021-03-20  4:32 ` [PATCH 1/7] cifs: don't cargo-cult strndup() Al Viro
                     ` (4 preceding siblings ...)
  2021-03-20  4:33   ` [PATCH 6/7] cifs: allocate buffer in the caller of build_path_from_dentry() Al Viro
@ 2021-03-20  4:33   ` Al Viro
  5 siblings, 0 replies; 17+ messages in thread
From: Al Viro @ 2021-03-20  4:33 UTC (permalink / raw)
  To: linux-cifs; +Cc: Steve French, linux-fsdevel

The cost is that we might need to flip '/' to '\\' in more than
just the prefix.  Needs profiling, but I suspect that we won't
get slowdown on that.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/cifs/dir.c | 83 +++++++++++++++--------------------------------------------
 1 file changed, 21 insertions(+), 62 deletions(-)

diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 6e855f004f50..3febf667d119 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -93,20 +93,16 @@ char *
 build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
 				       bool prefix)
 {
-	struct dentry *temp;
-	int namelen;
 	int dfsplen;
 	int pplen = 0;
-	char *full_path = page;
-	char dirsep;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
-	unsigned seq;
+	char dirsep = CIFS_DIR_SEP(cifs_sb);
+	char *s;
 
 	if (unlikely(!page))
 		return ERR_PTR(-ENOMEM);
 
-	dirsep = CIFS_DIR_SEP(cifs_sb);
 	if (prefix)
 		dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
 	else
@@ -115,74 +111,37 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
 		pplen = cifs_sb->prepath ? strlen(cifs_sb->prepath) + 1 : 0;
 
-cifs_bp_rename_retry:
-	namelen = dfsplen + pplen;
-	seq = read_seqbegin(&rename_lock);
-	rcu_read_lock();
-	for (temp = direntry; !IS_ROOT(temp);) {
-		namelen += (1 + temp->d_name.len);
-		temp = temp->d_parent;
-	}
-	rcu_read_unlock();
-
-	if (namelen >= PAGE_SIZE)
+	s = dentry_path_raw(direntry, page, PAGE_SIZE);
+	if (IS_ERR(s))
+		return s;
+	if (s < (char *)page + pplen + dfsplen)
 		return ERR_PTR(-ENAMETOOLONG);
-
-	full_path[namelen] = 0;	/* trailing null */
-	rcu_read_lock();
-	for (temp = direntry; !IS_ROOT(temp);) {
-		spin_lock(&temp->d_lock);
-		namelen -= 1 + temp->d_name.len;
-		if (namelen < 0) {
-			spin_unlock(&temp->d_lock);
-			break;
-		} else {
-			full_path[namelen] = dirsep;
-			strncpy(full_path + namelen + 1, temp->d_name.name,
-				temp->d_name.len);
-			cifs_dbg(FYI, "name: %s\n", full_path + namelen);
-		}
-		spin_unlock(&temp->d_lock);
-		temp = temp->d_parent;
-	}
-	rcu_read_unlock();
-	if (namelen != dfsplen + pplen || read_seqretry(&rename_lock, seq)) {
-		cifs_dbg(FYI, "did not end path lookup where expected. namelen=%ddfsplen=%d\n",
-			 namelen, dfsplen);
-		/* presumably this is only possible if racing with a rename
-		of one of the parent directories  (we can not lock the dentries
-		above us to prevent this, but retrying should be harmless) */
-		goto cifs_bp_rename_retry;
-	}
-	/* DIR_SEP already set for byte  0 / vs \ but not for
-	   subsequent slashes in prepath which currently must
-	   be entered the right way - not sure if there is an alternative
-	   since the '\' is a valid posix character so we can not switch
-	   those safely to '/' if any are found in the middle of the prepath */
-	/* BB test paths to Windows with '/' in the midst of prepath */
-
 	if (pplen) {
-		int i;
-
 		cifs_dbg(FYI, "using cifs_sb prepath <%s>\n", cifs_sb->prepath);
-		memcpy(full_path+dfsplen+1, cifs_sb->prepath, pplen-1);
-		full_path[dfsplen] = dirsep;
-		for (i = 0; i < pplen-1; i++)
-			if (full_path[dfsplen+1+i] == '/')
-				full_path[dfsplen+1+i] = CIFS_DIR_SEP(cifs_sb);
+		s -= pplen;
+		memcpy(s + 1, cifs_sb->prepath, pplen - 1);
+		*s = '/';
 	}
+	if (dirsep != '/') {
+		/* BB test paths to Windows with '/' in the midst of prepath */
+		char *p;
 
+		for (p = s; *p; p++)
+			if (*p == '/')
+				*p = dirsep;
+	}
 	if (dfsplen) {
-		strncpy(full_path, tcon->treeName, dfsplen);
+		s -= dfsplen;
+		memcpy(page, tcon->treeName, dfsplen);
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
 			int i;
 			for (i = 0; i < dfsplen; i++) {
-				if (full_path[i] == '\\')
-					full_path[i] = '/';
+				if (s[i] == '\\')
+					s[i] = '/';
 			}
 		}
 	}
-	return full_path;
+	return s;
 }
 
 /*
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [RFC][PATCHSET] hopefully saner handling of pathnames in cifs
  2021-03-20  4:31 [RFC][PATCHSET] hopefully saner handling of pathnames in cifs Al Viro
  2021-03-20  4:32 ` [PATCH 1/7] cifs: don't cargo-cult strndup() Al Viro
@ 2021-03-21 19:58 ` Steve French
  2021-03-22  2:19   ` Steve French
  2021-03-22 12:25 ` Jeff Layton
  2 siblings, 1 reply; 17+ messages in thread
From: Steve French @ 2021-03-21 19:58 UTC (permalink / raw)
  To: Al Viro; +Cc: CIFS, Steve French, linux-fsdevel

WIll run the automated tests on these.

Also FYI - patches 2 and 6 had some checkpatch warnings (although fairly minor).

On Fri, Mar 19, 2021 at 11:36 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
>         Patch series (#work.cifs in vfs.git) tries to clean the things
> up in and around build_path_from_dentry().  Part of that is constifying
> the pointers around that stuff, then it lifts the allocations into
> callers and finally switches build_path_from_dentry() to using
> dentry_path_raw() instead of open-coding it.  Handling of ->d_name
> and friends is subtle enough, and it would be better to have fewer
> places besides fs/d_path.c that need to mess with those...
>
>         Help with review and testing would be very much appreciated -
> there's a plenty of mount options/server combinations ;-/
>
>         For those who prefer to look at it in git, it lives in
> git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git #work.cifs;
> individual patches go in followups.
>
> Shortlog:
> Al Viro (7):
>       cifs: don't cargo-cult strndup()
>       cifs: constify get_normalized_path() properly
>       cifs: constify path argument of ->make_node()
>       cifs: constify pathname arguments in a bunch of helpers
>       cifs: make build_path_from_dentry() return const char *
>       cifs: allocate buffer in the caller of build_path_from_dentry()
>       cifs: switch build_path_from_dentry() to using dentry_path_raw()
>
> 1) a bunch of kstrdup() calls got cargo-culted as kstrndup().
> This is unidiomatic *and* pointless - it's not any "safer"
> that way (pass it a non-NUL-terminated array, and strlen()
> will barf same as kstrdup()) and it's actually a pessimization.
> Converted to plain kstrdup() calls.
>
> 2) constifying pathnames: get_normalized_path() gets a
> constant string and, on success, returns either that string
> or its modified copy.  It is declared with the wrong prototype -
> int get_normalized_path(const char *path, char **npath)
> so the caller might get a non-const alias of the original const
> string.  Fortunately, none of the callers actually use that
> alias to modify the string, so it's not an active bug - just
> the wrong typization.
>
> 3) constifying pathnames: ->make_node().  Unlike the rest of
> methods that take pathname as an argument, it has that argument
> declared as char *, not const char *.  Pure misannotation,
> since all instances never modify that actual string (or pass it
> to anything that might do the same).
>
> 4) constifying pathnames: a bunch of helpers.  Several functions
> have pathname argument declared as char *, when const char *
> would be fine - they neither modify the string nor pass it to
> anything that might.
>
> 5) constifying pathnames: build_path_from_dentry().
> That's the main source of pathnames; all callers are actually
> treating the string it returns as constant one.  Declare it
> to return const char * and adjust the callers.
>
> 6) take buffer allocation out of build_path_from_dentry().
> Trying to do exact-sized allocation is pointless - allocated
> object are short-lived anyway (the caller is always the one
> to free the string it gets from build_path_from_dentry()).
> As the matter of fact, we are in the same situation as with
> pathname arguments of syscalls - short-lived allocations
> limited to 4Kb and freed before the caller returns to userland.
> So we can just do allocations from names_cachep and do that
> in the caller; that way we don't need to bother with GFP_ATOMIC
> allocations.  Moreover, having the caller do allocations will
> permit us to switch build_path_from_dentry() to use of dentry_path_raw()
> (in the next commit).
>
> 7) build_path_from_dentry() essentially open-codes dentry_path_raw();
> the difference is that it wants to put the result in the beginning
> of the buffer (which we don't need anymore, since the caller knows
> what to free anyway) _and_ we might want '\\' for component separator
> instead of the normal '/'.  It's easier to use dentry_path_raw()
> and (optionally) post-process the result, replacing all '/' with
> '\\'.  Note that the last part needs profiling - I would expect it
> to be noise (we have just formed the string and it's all in hot cache),
> but that needs to be verified.
>
> Diffstat:
>  fs/cifs/cifs_dfs_ref.c |  14 +++--
>  fs/cifs/cifsglob.h     |   2 +-
>  fs/cifs/cifsproto.h    |  19 +++++--
>  fs/cifs/connect.c      |   9 +--
>  fs/cifs/dfs_cache.c    |  41 +++++++-------
>  fs/cifs/dir.c          | 148 ++++++++++++++++++-------------------------------
>  fs/cifs/file.c         |  79 +++++++++++++-------------
>  fs/cifs/fs_context.c   |   2 +-
>  fs/cifs/inode.c        | 110 ++++++++++++++++++------------------
>  fs/cifs/ioctl.c        |  13 +++--
>  fs/cifs/link.c         |  46 +++++++++------
>  fs/cifs/misc.c         |   2 +-
>  fs/cifs/readdir.c      |  15 ++---
>  fs/cifs/smb1ops.c      |   6 +-
>  fs/cifs/smb2ops.c      |  19 ++++---
>  fs/cifs/unc.c          |   4 +-
>  fs/cifs/xattr.c        |  40 +++++++------
>  17 files changed, 278 insertions(+), 291 deletions(-)



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC][PATCHSET] hopefully saner handling of pathnames in cifs
  2021-03-21 19:58 ` [RFC][PATCHSET] hopefully saner handling of pathnames in cifs Steve French
@ 2021-03-22  2:19   ` Steve French
  2021-03-22  2:38     ` Al Viro
  0 siblings, 1 reply; 17+ messages in thread
From: Steve French @ 2021-03-22  2:19 UTC (permalink / raw)
  To: Al Viro; +Cc: CIFS, Steve French, linux-fsdevel

automated tests failed so will need to dig in a little more and see
what is going on

http://smb3-test-rhel-75.southcentralus.cloudapp.azure.com/#/builders/2/builds/533

On Sun, Mar 21, 2021 at 2:58 PM Steve French <smfrench@gmail.com> wrote:
>
> WIll run the automated tests on these.
>
> Also FYI - patches 2 and 6 had some checkpatch warnings (although fairly minor).
>
> On Fri, Mar 19, 2021 at 11:36 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
> >
> >         Patch series (#work.cifs in vfs.git) tries to clean the things
> > up in and around build_path_from_dentry().  Part of that is constifying
> > the pointers around that stuff, then it lifts the allocations into
> > callers and finally switches build_path_from_dentry() to using
> > dentry_path_raw() instead of open-coding it.  Handling of ->d_name
> > and friends is subtle enough, and it would be better to have fewer
> > places besides fs/d_path.c that need to mess with those...
> >
> >         Help with review and testing would be very much appreciated -
> > there's a plenty of mount options/server combinations ;-/
> >
> >         For those who prefer to look at it in git, it lives in
> > git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git #work.cifs;
> > individual patches go in followups.
> >
> > Shortlog:
> > Al Viro (7):
> >       cifs: don't cargo-cult strndup()
> >       cifs: constify get_normalized_path() properly
> >       cifs: constify path argument of ->make_node()
> >       cifs: constify pathname arguments in a bunch of helpers
> >       cifs: make build_path_from_dentry() return const char *
> >       cifs: allocate buffer in the caller of build_path_from_dentry()
> >       cifs: switch build_path_from_dentry() to using dentry_path_raw()
> >
> > 1) a bunch of kstrdup() calls got cargo-culted as kstrndup().
> > This is unidiomatic *and* pointless - it's not any "safer"
> > that way (pass it a non-NUL-terminated array, and strlen()
> > will barf same as kstrdup()) and it's actually a pessimization.
> > Converted to plain kstrdup() calls.
> >
> > 2) constifying pathnames: get_normalized_path() gets a
> > constant string and, on success, returns either that string
> > or its modified copy.  It is declared with the wrong prototype -
> > int get_normalized_path(const char *path, char **npath)
> > so the caller might get a non-const alias of the original const
> > string.  Fortunately, none of the callers actually use that
> > alias to modify the string, so it's not an active bug - just
> > the wrong typization.
> >
> > 3) constifying pathnames: ->make_node().  Unlike the rest of
> > methods that take pathname as an argument, it has that argument
> > declared as char *, not const char *.  Pure misannotation,
> > since all instances never modify that actual string (or pass it
> > to anything that might do the same).
> >
> > 4) constifying pathnames: a bunch of helpers.  Several functions
> > have pathname argument declared as char *, when const char *
> > would be fine - they neither modify the string nor pass it to
> > anything that might.
> >
> > 5) constifying pathnames: build_path_from_dentry().
> > That's the main source of pathnames; all callers are actually
> > treating the string it returns as constant one.  Declare it
> > to return const char * and adjust the callers.
> >
> > 6) take buffer allocation out of build_path_from_dentry().
> > Trying to do exact-sized allocation is pointless - allocated
> > object are short-lived anyway (the caller is always the one
> > to free the string it gets from build_path_from_dentry()).
> > As the matter of fact, we are in the same situation as with
> > pathname arguments of syscalls - short-lived allocations
> > limited to 4Kb and freed before the caller returns to userland.
> > So we can just do allocations from names_cachep and do that
> > in the caller; that way we don't need to bother with GFP_ATOMIC
> > allocations.  Moreover, having the caller do allocations will
> > permit us to switch build_path_from_dentry() to use of dentry_path_raw()
> > (in the next commit).
> >
> > 7) build_path_from_dentry() essentially open-codes dentry_path_raw();
> > the difference is that it wants to put the result in the beginning
> > of the buffer (which we don't need anymore, since the caller knows
> > what to free anyway) _and_ we might want '\\' for component separator
> > instead of the normal '/'.  It's easier to use dentry_path_raw()
> > and (optionally) post-process the result, replacing all '/' with
> > '\\'.  Note that the last part needs profiling - I would expect it
> > to be noise (we have just formed the string and it's all in hot cache),
> > but that needs to be verified.
> >
> > Diffstat:
> >  fs/cifs/cifs_dfs_ref.c |  14 +++--
> >  fs/cifs/cifsglob.h     |   2 +-
> >  fs/cifs/cifsproto.h    |  19 +++++--
> >  fs/cifs/connect.c      |   9 +--
> >  fs/cifs/dfs_cache.c    |  41 +++++++-------
> >  fs/cifs/dir.c          | 148 ++++++++++++++++++-------------------------------
> >  fs/cifs/file.c         |  79 +++++++++++++-------------
> >  fs/cifs/fs_context.c   |   2 +-
> >  fs/cifs/inode.c        | 110 ++++++++++++++++++------------------
> >  fs/cifs/ioctl.c        |  13 +++--
> >  fs/cifs/link.c         |  46 +++++++++------
> >  fs/cifs/misc.c         |   2 +-
> >  fs/cifs/readdir.c      |  15 ++---
> >  fs/cifs/smb1ops.c      |   6 +-
> >  fs/cifs/smb2ops.c      |  19 ++++---
> >  fs/cifs/unc.c          |   4 +-
> >  fs/cifs/xattr.c        |  40 +++++++------
> >  17 files changed, 278 insertions(+), 291 deletions(-)
>
>
>
> --
> Thanks,
>
> Steve



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC][PATCHSET] hopefully saner handling of pathnames in cifs
  2021-03-22  2:19   ` Steve French
@ 2021-03-22  2:38     ` Al Viro
  2021-03-22  3:36       ` Steve French
  2021-03-23  5:04       ` Steve French
  0 siblings, 2 replies; 17+ messages in thread
From: Al Viro @ 2021-03-22  2:38 UTC (permalink / raw)
  To: Steve French; +Cc: CIFS, Steve French, linux-fsdevel

On Sun, Mar 21, 2021 at 09:19:53PM -0500, Steve French wrote:
> automated tests failed so will need to dig in a little more and see
> what is going on
> 
> http://smb3-test-rhel-75.southcentralus.cloudapp.azure.com/#/builders/2/builds/533

<looks>

Oh, bugger...  I think I see a braino that might be responsible for that;
whether it's all that's going on or not, that's an obvious bug.  Incremental
for that one would be

diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 3febf667d119..ed16f75ac0fa 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -132,7 +132,7 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
 	}
 	if (dfsplen) {
 		s -= dfsplen;
-		memcpy(page, tcon->treeName, dfsplen);
+		memcpy(s, tcon->treeName, dfsplen);
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
 			int i;
 			for (i = 0; i < dfsplen; i++) {


Folded and force-pushed (same branch).  My apologies...

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [RFC][PATCHSET] hopefully saner handling of pathnames in cifs
  2021-03-22  2:38     ` Al Viro
@ 2021-03-22  3:36       ` Steve French
  2021-03-22  3:38         ` Steve French
  2021-03-23  5:04       ` Steve French
  1 sibling, 1 reply; 17+ messages in thread
From: Steve French @ 2021-03-22  3:36 UTC (permalink / raw)
  To: Al Viro; +Cc: CIFS, Steve French, linux-fsdevel

[-- Attachment #1: Type: text/plain, Size: 1376 bytes --]

FYI - on a loosely related point  about / to \ conversion, I had been
experimenting with moving the conversion of '/' to '\' later depending
on connection type (see attached WIP patch for example).


On Sun, Mar 21, 2021 at 9:40 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> On Sun, Mar 21, 2021 at 09:19:53PM -0500, Steve French wrote:
> > automated tests failed so will need to dig in a little more and see
> > what is going on
> >
> > http://smb3-test-rhel-75.southcentralus.cloudapp.azure.com/#/builders/2/builds/533
>
> <looks>
>
> Oh, bugger...  I think I see a braino that might be responsible for that;
> whether it's all that's going on or not, that's an obvious bug.  Incremental
> for that one would be
>
> diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
> index 3febf667d119..ed16f75ac0fa 100644
> --- a/fs/cifs/dir.c
> +++ b/fs/cifs/dir.c
> @@ -132,7 +132,7 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
>         }
>         if (dfsplen) {
>                 s -= dfsplen;
> -               memcpy(page, tcon->treeName, dfsplen);
> +               memcpy(s, tcon->treeName, dfsplen);
>                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
>                         int i;
>                         for (i = 0; i < dfsplen; i++) {
>
>
> Folded and force-pushed (same branch).  My apologies...



-- 
Thanks,

Steve

[-- Attachment #2: slash-v2.patch --]
[-- Type: text/x-patch, Size: 4497 bytes --]

diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
index 9bd03a231032..4c0cc0677d80 100644
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -98,6 +98,9 @@ convert_sfm_char(const __u16 src_char, char *target)
 	case SFM_PERIOD:
 		*target = '.';
 		break;
+	case SFM_SLASH:
+		*target = '\\';
+		break;
 	default:
 		return false;
 	}
@@ -401,6 +404,8 @@ static __le16 convert_to_sfu_char(char src_char)
 	return dest_char;
 }
 
+#define UCS2_SLASH 0x005C
+
 static __le16 convert_to_sfm_char(char src_char, bool end_of_string)
 {
 	__le16 dest_char;
@@ -431,6 +436,9 @@ static __le16 convert_to_sfm_char(char src_char, bool end_of_string)
 	case '|':
 		dest_char = cpu_to_le16(SFM_PIPE);
 		break;
+	case '\\':
+		dest_char = cpu_to_le16(SFM_SLASH);
+		break;
 	case '.':
 		if (end_of_string)
 			dest_char = cpu_to_le16(SFM_PERIOD);
@@ -443,6 +451,10 @@ static __le16 convert_to_sfm_char(char src_char, bool end_of_string)
 		else
 			dest_char = 0;
 		break;
+	case '/':
+
+		dest_char = cpu_to_le16(UCS2_SLASH);
+		break;
 	default:
 		dest_char = 0;
 	}
@@ -502,11 +516,7 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
 			dst_char = convert_to_sfm_char(src_char, end_of_string);
 		} else
 			dst_char = 0;
-		/*
-		 * FIXME: We can not handle remapping backslash (UNI_SLASH)
-		 * until all the calls to build_path_from_dentry are modified,
-		 * as they use backslash as separator.
-		 */
+
 		if (dst_char == 0) {
 			charlen = cp->char2uni(source + i, srclen - i, &tmp);
 			dst_char = cpu_to_le16(tmp);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3de3c5908a72..f0f96dddc483 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1430,10 +1430,10 @@ CIFS_FILE_SB(struct file *file)
 
 static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
 {
-	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+/*	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) */
 		return '/';
-	else
-		return '\\';
+/*	else
+		return '\\'; */
 }
 
 static inline void
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 97ac363b5df1..f534e2f991d9 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -209,12 +210,18 @@ check_name(struct dentry *direntry, struct cifs_tcon *tcon)
 		     le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength)))
 		return -ENAMETOOLONG;
 
-	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
-		for (i = 0; i < direntry->d_name.len; i++) {
-			if (direntry->d_name.name[i] == '\\') {
-				cifs_dbg(FYI, "Invalid file name\n");
-				return -EINVAL;
-			}
+	/*
+	 * SMB3.1.1 POSIX Extensions, CIFS Unix Extensions and SFM mappings
+	 * allow \ in paths (or in latter case remaps \ to 0xF026)
+	 */
+	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) ||
+	    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR))
+		return 0;
+		 
+	for (i = 0; i < direntry->d_name.len; i++) {
+		if (direntry->d_name.name[i] == '\\') {
+			cifs_dbg(FYI, "Invalid file name\n");
+			return -EINVAL;
 		}
 	}
 	return 0;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 82e176720ca6..9361644f7310 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -1186,7 +1186,7 @@ int update_super_prepath(struct cifs_tcon *tcon, char *prefix)
 			goto out;
 		}
 
-		convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
+		convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb)); /* BB Does this need to be changed for / ? */
 	} else
 		cifs_sb->prepath = NULL;
 
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 60d4bd1eae2b..ce4f00069653 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -476,13 +476,17 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
 	if (from[0] == '\\')
 		start_of_path = from + 1;
 
-	/* SMB311 POSIX extensions paths do not include leading slash */
-	else if (cifs_sb_master_tlink(cifs_sb) &&
-		 cifs_sb_master_tcon(cifs_sb)->posix_extensions &&
-		 (from[0] == '/')) {
-		start_of_path = from + 1;
-	} else
-		start_of_path = from;
+	start_of_path = from;
+	/*
+	 * Only old CIFS Unix extensions paths include leading slash
+	 * Need to skip if for SMB3.1.1 POSIX Extensions and SMB1/2/3
+	 */
+	if (from[0] == '/') {
+		if (((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == false) ||
+		    (cifs_sb_master_tlink(cifs_sb) &&
+		     (cifs_sb_master_tcon(cifs_sb)->posix_extensions)))
+			start_of_path = from + 1;
+	}
 
 	to = cifs_strndup_to_utf16(start_of_path, PATH_MAX, &len,
 				   cifs_sb->local_nls, map_type);

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [RFC][PATCHSET] hopefully saner handling of pathnames in cifs
  2021-03-22  3:36       ` Steve French
@ 2021-03-22  3:38         ` Steve French
  2021-03-22 13:15           ` Aurélien Aptel
  0 siblings, 1 reply; 17+ messages in thread
From: Steve French @ 2021-03-22  3:38 UTC (permalink / raw)
  To: Al Viro; +Cc: CIFS, Steve French, linux-fsdevel

Some additional context - currently because of the way cifs.ko handles
conversion of '/' we can't handle a filename with '\' in the filename
(although the protocol would support that via remapping into the UCS-2
remap range if we made a change to move slash conversion later).

On Sun, Mar 21, 2021 at 10:36 PM Steve French <smfrench@gmail.com> wrote:
>
> FYI - on a loosely related point  about / to \ conversion, I had been
> experimenting with moving the conversion of '/' to '\' later depending
> on connection type (see attached WIP patch for example).
>
>
> On Sun, Mar 21, 2021 at 9:40 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
> >
> > On Sun, Mar 21, 2021 at 09:19:53PM -0500, Steve French wrote:
> > > automated tests failed so will need to dig in a little more and see
> > > what is going on
> > >
> > > http://smb3-test-rhel-75.southcentralus.cloudapp.azure.com/#/builders/2/builds/533
> >
> > <looks>
> >
> > Oh, bugger...  I think I see a braino that might be responsible for that;
> > whether it's all that's going on or not, that's an obvious bug.  Incremental
> > for that one would be
> >
> > diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
> > index 3febf667d119..ed16f75ac0fa 100644
> > --- a/fs/cifs/dir.c
> > +++ b/fs/cifs/dir.c
> > @@ -132,7 +132,7 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
> >         }
> >         if (dfsplen) {
> >                 s -= dfsplen;
> > -               memcpy(page, tcon->treeName, dfsplen);
> > +               memcpy(s, tcon->treeName, dfsplen);
> >                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
> >                         int i;
> >                         for (i = 0; i < dfsplen; i++) {
> >
> >
> > Folded and force-pushed (same branch).  My apologies...
>
>
>
> --
> Thanks,
>
> Steve



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC][PATCHSET] hopefully saner handling of pathnames in cifs
  2021-03-20  4:31 [RFC][PATCHSET] hopefully saner handling of pathnames in cifs Al Viro
  2021-03-20  4:32 ` [PATCH 1/7] cifs: don't cargo-cult strndup() Al Viro
  2021-03-21 19:58 ` [RFC][PATCHSET] hopefully saner handling of pathnames in cifs Steve French
@ 2021-03-22 12:25 ` Jeff Layton
  2 siblings, 0 replies; 17+ messages in thread
From: Jeff Layton @ 2021-03-22 12:25 UTC (permalink / raw)
  To: Al Viro, linux-cifs; +Cc: Steve French, linux-fsdevel

On Sat, 2021-03-20 at 04:31 +0000, Al Viro wrote:
> 	Patch series (#work.cifs in vfs.git) tries to clean the things
> up in and around build_path_from_dentry().  Part of that is constifying
> the pointers around that stuff, then it lifts the allocations into
> callers and finally switches build_path_from_dentry() to using
> dentry_path_raw() instead of open-coding it.  Handling of ->d_name
> and friends is subtle enough, and it would be better to have fewer
> places besides fs/d_path.c that need to mess with those...
> 
> 	Help with review and testing would be very much appreciated -
> there's a plenty of mount options/server combinations ;-/
> 
> 	For those who prefer to look at it in git, it lives in
> git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.git #work.cifs;
> individual patches go in followups.
> 
> Shortlog:
> Al Viro (7):
>       cifs: don't cargo-cult strndup()
>       cifs: constify get_normalized_path() properly
>       cifs: constify path argument of ->make_node()
>       cifs: constify pathname arguments in a bunch of helpers
>       cifs: make build_path_from_dentry() return const char *
>       cifs: allocate buffer in the caller of build_path_from_dentry()
>       cifs: switch build_path_from_dentry() to using dentry_path_raw()
> 
> 1) a bunch of kstrdup() calls got cargo-culted as kstrndup().
> This is unidiomatic *and* pointless - it's not any "safer"
> that way (pass it a non-NUL-terminated array, and strlen()
> will barf same as kstrdup()) and it's actually a pessimization.
> Converted to plain kstrdup() calls.
> 
> 2) constifying pathnames: get_normalized_path() gets a
> constant string and, on success, returns either that string
> or its modified copy.  It is declared with the wrong prototype -
> int get_normalized_path(const char *path, char **npath)
> so the caller might get a non-const alias of the original const
> string.  Fortunately, none of the callers actually use that
> alias to modify the string, so it's not an active bug - just
> the wrong typization.
> 
> 3) constifying pathnames: ->make_node().  Unlike the rest of
> methods that take pathname as an argument, it has that argument
> declared as char *, not const char *.  Pure misannotation,
> since all instances never modify that actual string (or pass it 
> to anything that might do the same).
> 
> 4) constifying pathnames: a bunch of helpers.  Several functions
> have pathname argument declared as char *, when const char *
> would be fine - they neither modify the string nor pass it to
> anything that might.
> 
> 5) constifying pathnames: build_path_from_dentry().
> That's the main source of pathnames; all callers are actually
> treating the string it returns as constant one.  Declare it
> to return const char * and adjust the callers.
> 
> 6) take buffer allocation out of build_path_from_dentry().
> Trying to do exact-sized allocation is pointless - allocated
> object are short-lived anyway (the caller is always the one
> to free the string it gets from build_path_from_dentry()).
> As the matter of fact, we are in the same situation as with
> pathname arguments of syscalls - short-lived allocations
> limited to 4Kb and freed before the caller returns to userland.
> So we can just do allocations from names_cachep and do that
> in the caller; that way we don't need to bother with GFP_ATOMIC
> allocations.  Moreover, having the caller do allocations will
> permit us to switch build_path_from_dentry() to use of dentry_path_raw()
> (in the next commit).
> 
> 7) build_path_from_dentry() essentially open-codes dentry_path_raw();
> the difference is that it wants to put the result in the beginning
> of the buffer (which we don't need anymore, since the caller knows
> what to free anyway) _and_ we might want '\\' for component separator
> instead of the normal '/'.  It's easier to use dentry_path_raw()
> and (optionally) post-process the result, replacing all '/' with
> '\\'.  Note that the last part needs profiling - I would expect it
> to be noise (we have just formed the string and it's all in hot cache),
> but that needs to be verified.
> 
> Diffstat:
>  fs/cifs/cifs_dfs_ref.c |  14 +++--
>  fs/cifs/cifsglob.h     |   2 +-
>  fs/cifs/cifsproto.h    |  19 +++++--
>  fs/cifs/connect.c      |   9 +--
>  fs/cifs/dfs_cache.c    |  41 +++++++-------
>  fs/cifs/dir.c          | 148 ++++++++++++++++++-------------------------------
>  fs/cifs/file.c         |  79 +++++++++++++-------------
>  fs/cifs/fs_context.c   |   2 +-
>  fs/cifs/inode.c        | 110 ++++++++++++++++++------------------
>  fs/cifs/ioctl.c        |  13 +++--
>  fs/cifs/link.c         |  46 +++++++++------
>  fs/cifs/misc.c         |   2 +-
>  fs/cifs/readdir.c      |  15 ++---
>  fs/cifs/smb1ops.c      |   6 +-
>  fs/cifs/smb2ops.c      |  19 ++++---
>  fs/cifs/unc.c          |   4 +-
>  fs/cifs/xattr.c        |  40 +++++++------
>  17 files changed, 278 insertions(+), 291 deletions(-)


This all looks reasonable.

FWIW, we switched ceph to use a similar buffer allocation scheme for
built paths a couple of years ago. I left the allocation in the caller
there, and we just return the offset of the start of the string to the
caller (which we only use to free the buffer later). It works but it's a
bit klunky.

Acked-by: Jeff Layton <jlayton@kernel.org>


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC][PATCHSET] hopefully saner handling of pathnames in cifs
  2021-03-22  3:38         ` Steve French
@ 2021-03-22 13:15           ` Aurélien Aptel
  0 siblings, 0 replies; 17+ messages in thread
From: Aurélien Aptel @ 2021-03-22 13:15 UTC (permalink / raw)
  To: Steve French, Al Viro; +Cc: CIFS, Steve French, linux-fsdevel

Steve French <smfrench@gmail.com> writes:
> Some additional context - currently because of the way cifs.ko handles
> conversion of '/' we can't handle a filename with '\' in the filename
> (although the protocol would support that via remapping into the UCS-2
> remap range if we made a change to move slash conversion later).

Make sure to run the DFS tests before merging those patches as well. Lot
of path manipulation happening there.

Cheers,
-- 
Aurélien Aptel / SUSE Labs Samba Team
GPG: 1839 CB5F 9F5B FB9B AA97  8C99 03C8 A49B 521B D5D3
SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg, DE
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah HRB 247165 (AG München)


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC][PATCHSET] hopefully saner handling of pathnames in cifs
  2021-03-22  2:38     ` Al Viro
  2021-03-22  3:36       ` Steve French
@ 2021-03-23  5:04       ` Steve French
  2021-03-24 15:28         ` Al Viro
  1 sibling, 1 reply; 17+ messages in thread
From: Steve French @ 2021-03-23  5:04 UTC (permalink / raw)
  To: Al Viro; +Cc: CIFS, Steve French, linux-fsdevel

reran with the updated patch 7 and it failed (although I didn't have
time to dig much into it today) - see

http://smb3-test-rhel-75.southcentralus.cloudapp.azure.com/#/builders/2/builds/534

but it seems to run ok without patch 7 (just the first six patches)

http://smb3-test-rhel-75.southcentralus.cloudapp.azure.com/#/builders/2/builds/535

On Sun, Mar 21, 2021 at 9:40 PM Al Viro <viro@zeniv.linux.org.uk> wrote:
>
> On Sun, Mar 21, 2021 at 09:19:53PM -0500, Steve French wrote:
> > automated tests failed so will need to dig in a little more and see
> > what is going on
> >
> > http://smb3-test-rhel-75.southcentralus.cloudapp.azure.com/#/builders/2/builds/533
>
> <looks>
>
> Oh, bugger...  I think I see a braino that might be responsible for that;
> whether it's all that's going on or not, that's an obvious bug.  Incremental
> for that one would be
>
> diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
> index 3febf667d119..ed16f75ac0fa 100644
> --- a/fs/cifs/dir.c
> +++ b/fs/cifs/dir.c
> @@ -132,7 +132,7 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
>         }
>         if (dfsplen) {
>                 s -= dfsplen;
> -               memcpy(page, tcon->treeName, dfsplen);
> +               memcpy(s, tcon->treeName, dfsplen);
>                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
>                         int i;
>                         for (i = 0; i < dfsplen; i++) {
>
>
> Folded and force-pushed (same branch).  My apologies...



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC][PATCHSET] hopefully saner handling of pathnames in cifs
  2021-03-23  5:04       ` Steve French
@ 2021-03-24 15:28         ` Al Viro
  0 siblings, 0 replies; 17+ messages in thread
From: Al Viro @ 2021-03-24 15:28 UTC (permalink / raw)
  To: Steve French; +Cc: CIFS, Steve French, linux-fsdevel

On Tue, Mar 23, 2021 at 12:04:34AM -0500, Steve French wrote:
> reran with the updated patch 7 and it failed (although I didn't have
> time to dig much into it today) - see
> 
> http://smb3-test-rhel-75.southcentralus.cloudapp.azure.com/#/builders/2/builds/534
> 
> but it seems to run ok without patch 7 (just the first six patches)
> 
> http://smb3-test-rhel-75.southcentralus.cloudapp.azure.com/#/builders/2/builds/535

Hmm...  Another bug, AFAICS, is that for root we end up with "/", not "".
No idea if that's all there is, though ;-/  How does one set the things up
for those tests?  Anyway, incremental would be
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index ed16f75ac0fa..03afad8b24af 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -114,6 +114,8 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
 	s = dentry_path_raw(direntry, page, PAGE_SIZE);
 	if (IS_ERR(s))
 		return s;
+	if (!s[1])	// for root we want "", not "/"
+		s++;
 	if (s < (char *)page + pplen + dfsplen)
 		return ERR_PTR(-ENAMETOOLONG);
 	if (pplen) {

Folded and force-pushed.  Could you throw the updated branch into testing?

^ permalink raw reply related	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2021-03-24 15:29 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-20  4:31 [RFC][PATCHSET] hopefully saner handling of pathnames in cifs Al Viro
2021-03-20  4:32 ` [PATCH 1/7] cifs: don't cargo-cult strndup() Al Viro
2021-03-20  4:32   ` [PATCH 2/7] cifs: constify get_normalized_path() properly Al Viro
2021-03-20  4:33   ` [PATCH 3/7] cifs: constify path argument of ->make_node() Al Viro
2021-03-20  4:33   ` [PATCH 4/7] cifs: constify pathname arguments in a bunch of helpers Al Viro
2021-03-20  4:33   ` [PATCH 5/7] cifs: make build_path_from_dentry() return const char * Al Viro
2021-03-20  4:33   ` [PATCH 6/7] cifs: allocate buffer in the caller of build_path_from_dentry() Al Viro
2021-03-20  4:33   ` [PATCH 7/7] cifs: switch build_path_from_dentry() to using dentry_path_raw() Al Viro
2021-03-21 19:58 ` [RFC][PATCHSET] hopefully saner handling of pathnames in cifs Steve French
2021-03-22  2:19   ` Steve French
2021-03-22  2:38     ` Al Viro
2021-03-22  3:36       ` Steve French
2021-03-22  3:38         ` Steve French
2021-03-22 13:15           ` Aurélien Aptel
2021-03-23  5:04       ` Steve French
2021-03-24 15:28         ` Al Viro
2021-03-22 12:25 ` Jeff Layton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).