Skip to content

Commit 15e9e00

Browse files
pcacjrsmfrench
authored andcommitted
vfs: get rid of BUG_ON() in d_mark_tmpfile_name()
Do proper error handling in d_mark_tmpfile_name() by returning errors rather than using BUG_ON()'s. Adjust caller to check for errors from d_mark_tmpfile_name() as well as clean it up for using return value from scnprintf() in QSTR_LEN() to make it more obvious where the tmpfile name's length is coming from. Link: https://lore.kernel.org/r/CAHk-=wgerpUKCDhdzKH0FEdLyfhj3doc9t+kO9Yb6rSsTp7hdQ@mail.gmail.com Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Reviewed-by: David Howells <dhowells@redhat.com> Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.org> Cc: Christian Brauner <brauner@kernel.org> Cc: Jan Kara <jack@suse.cz> CC: linux-fsdevel@vger.kernel.org Cc: linux-cifs@vger.kernel.org Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent 81dc1e4 commit 15e9e00

4 files changed

Lines changed: 31 additions & 27 deletions

File tree

fs/dcache.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3196,22 +3196,26 @@ void d_mark_tmpfile(struct file *file, struct inode *inode)
31963196
}
31973197
EXPORT_SYMBOL(d_mark_tmpfile);
31983198

3199-
void d_mark_tmpfile_name(struct file *file, const struct qstr *name)
3199+
int d_mark_tmpfile_name(struct file *file, const struct qstr *name)
32003200
{
32013201
struct dentry *dentry = file->f_path.dentry;
32023202
char *dname = dentry->d_shortname.string;
32033203

3204-
BUG_ON(dname_external(dentry));
3205-
BUG_ON(d_really_is_positive(dentry));
3206-
BUG_ON(!d_unlinked(dentry));
3207-
BUG_ON(name->len > DNAME_INLINE_LEN - 1);
3204+
if (unlikely(dname_external(dentry) ||
3205+
d_really_is_positive(dentry) ||
3206+
!d_unlinked(dentry)))
3207+
return -EINVAL;
3208+
if (unlikely(name->len > DNAME_INLINE_LEN - 1))
3209+
return -ENAMETOOLONG;
3210+
32083211
spin_lock(&dentry->d_parent->d_lock);
32093212
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
32103213
dentry->__d_name.len = name->len;
32113214
memcpy(dname, name->name, name->len);
32123215
dname[name->len] = '\0';
32133216
spin_unlock(&dentry->d_lock);
32143217
spin_unlock(&dentry->d_parent->d_lock);
3218+
return 0;
32153219
}
32163220
EXPORT_SYMBOL(d_mark_tmpfile_name);
32173221

fs/smb/client/cifsfs.h

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define _CIFSFS_H
1111

1212
#include <linux/hash.h>
13+
#include <linux/dcache.h>
1314

1415
#define ROOT_I 2
1516

@@ -149,17 +150,11 @@ struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type, int flags,
149150

150151
char *cifs_silly_fullpath(struct dentry *dentry);
151152

152-
#define CIFS_TMPNAME_PREFIX ".__smbfile_tmp"
153-
#define CIFS_TMPNAME_PREFIX_LEN ((int)sizeof(CIFS_TMPNAME_PREFIX) - 1)
154-
#define CIFS_TMPNAME_COUNTER_LEN ((int)sizeof(cifs_tmpcounter) * 2)
155-
#define CIFS_TMPNAME_LEN \
156-
(CIFS_TMPNAME_PREFIX_LEN + CIFS_TMPNAME_COUNTER_LEN)
157-
158-
#define CIFS_SILLYNAME_PREFIX ".__smbfile_silly"
159-
#define CIFS_SILLYNAME_PREFIX_LEN ((int)sizeof(CIFS_SILLYNAME_PREFIX) - 1)
160-
#define CIFS_SILLYNAME_COUNTER_LEN ((int)sizeof(cifs_sillycounter) * 2)
161-
#define CIFS_SILLYNAME_LEN \
162-
(CIFS_SILLYNAME_PREFIX_LEN + CIFS_SILLYNAME_COUNTER_LEN)
153+
#define CIFS_TMPNAME_PREFIX ".__smbfile_tmp"
154+
#define CIFS_TMPNAME_LEN (DNAME_INLINE_LEN - 1)
155+
156+
#define CIFS_SILLYNAME_PREFIX ".__smbfile_silly"
157+
#define CIFS_SILLYNAME_LEN (DNAME_INLINE_LEN - 1)
163158

164159
#ifdef CONFIG_CIFS_NFSD_EXPORT
165160
extern const struct export_operations cifs_export_ops;

fs/smb/client/dir.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,9 +1056,9 @@ int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
10561056
{
10571057
struct dentry *dentry = file->f_path.dentry;
10581058
struct cifs_sb_info *cifs_sb = CIFS_SB(dir);
1059+
size_t namesize = CIFS_TMPNAME_LEN + 1;
10591060
char *path __free(kfree) = NULL, *name;
10601061
unsigned int oflags = file->f_flags;
1061-
size_t size = CIFS_TMPNAME_LEN + 1;
10621062
int retries = 0, max_retries = 16;
10631063
struct TCP_Server_Info *server;
10641064
struct cifs_pending_open open;
@@ -1070,6 +1070,7 @@ int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
10701070
struct inode *inode;
10711071
unsigned int xid;
10721072
__u32 oplock;
1073+
int namelen;
10731074
int rc;
10741075

10751076
if (unlikely(cifs_forced_shutdown(cifs_sb)))
@@ -1093,7 +1094,7 @@ int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
10931094
server->ops->new_lease_key(&fid);
10941095
cifs_add_pending_open(&fid, tlink, &open);
10951096

1096-
path = alloc_parent_path(dentry, size - 1);
1097+
path = alloc_parent_path(dentry, namesize - 1);
10971098
if (IS_ERR(path)) {
10981099
cifs_del_pending_open(&open);
10991100
rc = PTR_ERR(path);
@@ -1103,16 +1104,22 @@ int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
11031104

11041105
name = path + strlen(path);
11051106
do {
1106-
scnprintf(name, size,
1107-
CIFS_TMPNAME_PREFIX "%0*x",
1108-
CIFS_TMPNAME_COUNTER_LEN,
1109-
atomic_inc_return(&cifs_tmpcounter));
1107+
/* Append tmpfile name to @path */
1108+
namelen = scnprintf(name, namesize, CIFS_TMPNAME_PREFIX "%x",
1109+
atomic_inc_return(&cifs_tmpcounter));
11101110
rc = __cifs_do_create(dir, dentry, path, xid, tlink, oflags,
11111111
mode, &oplock, &fid, NULL, &inode);
11121112
if (!rc) {
1113+
rc = d_mark_tmpfile_name(file, &QSTR_LEN(name, namelen));
1114+
if (rc) {
1115+
cifs_dbg(VFS | ONCE, "%s: failed to set filename in dentry: %d\n",
1116+
__func__, rc);
1117+
rc = -EISDIR;
1118+
iput(inode);
1119+
goto err_open;
1120+
}
11131121
set_nlink(inode, 0);
11141122
mark_inode_dirty(inode);
1115-
d_mark_tmpfile_name(file, &QSTR_LEN(name, size - 1));
11161123
d_instantiate(dentry, inode);
11171124
break;
11181125
}
@@ -1168,9 +1175,7 @@ char *cifs_silly_fullpath(struct dentry *dentry)
11681175

11691176
do {
11701177
dput(sdentry);
1171-
scnprintf(name, namesize,
1172-
CIFS_SILLYNAME_PREFIX "%0*x",
1173-
CIFS_SILLYNAME_COUNTER_LEN,
1178+
scnprintf(name, namesize, CIFS_SILLYNAME_PREFIX "%x",
11741179
atomic_inc_return(&cifs_sillycounter));
11751180
sdentry = lookup_noperm(&QSTR(name), dentry->d_parent);
11761181
if (IS_ERR(sdentry))

include/linux/dcache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ extern void d_invalidate(struct dentry *);
264264
extern struct dentry * d_make_root(struct inode *);
265265

266266
extern void d_mark_tmpfile(struct file *, struct inode *);
267-
void d_mark_tmpfile_name(struct file *file, const struct qstr *name);
267+
int d_mark_tmpfile_name(struct file *file, const struct qstr *name);
268268
extern void d_tmpfile(struct file *, struct inode *);
269269

270270
extern struct dentry *d_find_alias(struct inode *);

0 commit comments

Comments
 (0)