Skip to content

Commit 542228d

Browse files
ChenXiaoSongSteve French
ChenXiaoSong
authored and
Steve French
committed
cifs: fix use-after-free on the link name
xfstests generic/011 reported use-after-free bug as follows: BUG: KASAN: use-after-free in __d_alloc+0x269/0x859 Read of size 15 at addr ffff8880078933a0 by task dirstress/952 CPU: 1 PID: 952 Comm: dirstress Not tainted 6.1.0-rc3+ #77 Call Trace: __dump_stack+0x23/0x29 dump_stack_lvl+0x51/0x73 print_address_description+0x67/0x27f print_report+0x3e/0x5c kasan_report+0x7b/0xa8 kasan_check_range+0x1b2/0x1c1 memcpy+0x22/0x5d __d_alloc+0x269/0x859 d_alloc+0x45/0x20c d_alloc_parallel+0xb2/0x8b2 lookup_open+0x3b8/0x9f9 open_last_lookups+0x63d/0xc26 path_openat+0x11a/0x261 do_filp_open+0xcc/0x168 do_sys_openat2+0x13b/0x3f7 do_sys_open+0x10f/0x146 __se_sys_creat+0x27/0x2e __x64_sys_creat+0x55/0x6a do_syscall_64+0x40/0x96 entry_SYSCALL_64_after_hwframe+0x63/0xcd Allocated by task 952: kasan_save_stack+0x1f/0x42 kasan_set_track+0x21/0x2a kasan_save_alloc_info+0x17/0x1d __kasan_kmalloc+0x7e/0x87 __kmalloc_node_track_caller+0x59/0x155 kstrndup+0x60/0xe6 parse_mf_symlink+0x215/0x30b check_mf_symlink+0x260/0x36a cifs_get_inode_info+0x14e1/0x1690 cifs_revalidate_dentry_attr+0x70d/0x964 cifs_revalidate_dentry+0x36/0x62 cifs_d_revalidate+0x162/0x446 lookup_open+0x36f/0x9f9 open_last_lookups+0x63d/0xc26 path_openat+0x11a/0x261 do_filp_open+0xcc/0x168 do_sys_openat2+0x13b/0x3f7 do_sys_open+0x10f/0x146 __se_sys_creat+0x27/0x2e __x64_sys_creat+0x55/0x6a do_syscall_64+0x40/0x96 entry_SYSCALL_64_after_hwframe+0x63/0xcd Freed by task 950: kasan_save_stack+0x1f/0x42 kasan_set_track+0x21/0x2a kasan_save_free_info+0x1c/0x34 ____kasan_slab_free+0x1c1/0x1d5 __kasan_slab_free+0xe/0x13 __kmem_cache_free+0x29a/0x387 kfree+0xd3/0x10e cifs_fattr_to_inode+0xb6a/0xc8c cifs_get_inode_info+0x3cb/0x1690 cifs_revalidate_dentry_attr+0x70d/0x964 cifs_revalidate_dentry+0x36/0x62 cifs_d_revalidate+0x162/0x446 lookup_open+0x36f/0x9f9 open_last_lookups+0x63d/0xc26 path_openat+0x11a/0x261 do_filp_open+0xcc/0x168 do_sys_openat2+0x13b/0x3f7 do_sys_open+0x10f/0x146 __se_sys_creat+0x27/0x2e __x64_sys_creat+0x55/0x6a do_syscall_64+0x40/0x96 entry_SYSCALL_64_after_hwframe+0x63/0xcd When opened a symlink, link name is from 'inode->i_link', but it may be reset to a new value when revalidate the dentry. If some processes get the link name on the race scenario, then UAF will happen on link name. Fix this by implementing 'get_link' interface to duplicate the link name. Fixes: 76894f3 ("cifs: improve symlink handling for smb2+") Signed-off-by: ChenXiaoSong <[email protected]> Reviewed-by: Paulo Alcantara (SUSE) <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 23d9b9b commit 542228d

File tree

2 files changed

+25
-6
lines changed

2 files changed

+25
-6
lines changed

fs/cifs/cifsfs.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1143,8 +1143,32 @@ const struct inode_operations cifs_file_inode_ops = {
11431143
.fiemap = cifs_fiemap,
11441144
};
11451145

1146+
const char *cifs_get_link(struct dentry *dentry, struct inode *inode,
1147+
struct delayed_call *done)
1148+
{
1149+
char *target_path;
1150+
1151+
target_path = kmalloc(PATH_MAX, GFP_KERNEL);
1152+
if (!target_path)
1153+
return ERR_PTR(-ENOMEM);
1154+
1155+
spin_lock(&inode->i_lock);
1156+
if (likely(CIFS_I(inode)->symlink_target)) {
1157+
strscpy(target_path, CIFS_I(inode)->symlink_target, PATH_MAX);
1158+
} else {
1159+
kfree(target_path);
1160+
target_path = ERR_PTR(-EOPNOTSUPP);
1161+
}
1162+
spin_unlock(&inode->i_lock);
1163+
1164+
if (!IS_ERR(target_path))
1165+
set_delayed_call(done, kfree_link, target_path);
1166+
1167+
return target_path;
1168+
}
1169+
11461170
const struct inode_operations cifs_symlink_inode_ops = {
1147-
.get_link = simple_get_link,
1171+
.get_link = cifs_get_link,
11481172
.permission = cifs_permission,
11491173
.listxattr = cifs_listxattr,
11501174
};

fs/cifs/inode.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,11 +215,6 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
215215
kfree(cifs_i->symlink_target);
216216
cifs_i->symlink_target = fattr->cf_symlink_target;
217217
fattr->cf_symlink_target = NULL;
218-
219-
if (unlikely(!cifs_i->symlink_target))
220-
inode->i_link = ERR_PTR(-EOPNOTSUPP);
221-
else
222-
inode->i_link = cifs_i->symlink_target;
223218
}
224219
spin_unlock(&inode->i_lock);
225220

0 commit comments

Comments
 (0)