Skip to content

Commit 43323a5

Browse files
MaxKellermannidryomov
authored andcommitted
ceph: add a bunch of missing ceph_path_info initializers
ceph_mdsc_build_path() must be called with a zero-initialized ceph_path_info parameter, or else the following ceph_mdsc_free_path_info() may crash. Example crash (on Linux 6.18.12): virt_to_cache: Object is not a Slab page! WARNING: CPU: 184 PID: 2871736 at mm/slub.c:6732 kmem_cache_free+0x316/0x400 [...] Call Trace: [...] ceph_open+0x13d/0x3e0 do_dentry_open+0x134/0x480 vfs_open+0x2a/0xe0 path_openat+0x9a3/0x1160 [...] cache_from_obj: Wrong slab cache. names_cache but object is from ceph_inode_info WARNING: CPU: 184 PID: 2871736 at mm/slub.c:6746 kmem_cache_free+0x2dd/0x400 [...] kernel BUG at mm/slub.c:634! Oops: invalid opcode: 0000 [#1] SMP NOPTI RIP: 0010:__slab_free+0x1a4/0x350 Some of the ceph_mdsc_build_path() callers had initializers, but others had not, even though they were all added by commit 15f519e ("ceph: fix race condition validating r_parent before applying state"). The ones without initializer are suspectible to random crashes. (I can imagine it could even be possible to exploit this bug to elevate privileges.) Unfortunately, these Ceph functions are undocumented and its semantics can only be derived from the code. I see that ceph_mdsc_build_path() initializes the structure only on success, but not on error. Calling ceph_mdsc_free_path_info() after a failed ceph_mdsc_build_path() call does not even make sense, but that's what all callers do, and for it to be safe, the structure must be zero-initialized. The least intrusive approach to fix this is therefore to add initializers everywhere. Cc: [email protected] Fixes: 15f519e ("ceph: fix race condition validating r_parent before applying state") Signed-off-by: Max Kellermann <[email protected]> Reviewed-by: Viacheslav Dubeyko <[email protected]> Signed-off-by: Ilya Dryomov <[email protected]>
1 parent ce0123c commit 43323a5

4 files changed

Lines changed: 6 additions & 6 deletions

File tree

fs/ceph/debugfs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ static int mdsc_show(struct seq_file *s, void *p)
7979
if (req->r_inode) {
8080
seq_printf(s, " #%llx", ceph_ino(req->r_inode));
8181
} else if (req->r_dentry) {
82-
struct ceph_path_info path_info;
82+
struct ceph_path_info path_info = {0};
8383
path = ceph_mdsc_build_path(mdsc, req->r_dentry, &path_info, 0);
8484
if (IS_ERR(path))
8585
path = NULL;
@@ -98,7 +98,7 @@ static int mdsc_show(struct seq_file *s, void *p)
9898
}
9999

100100
if (req->r_old_dentry) {
101-
struct ceph_path_info path_info;
101+
struct ceph_path_info path_info = {0};
102102
path = ceph_mdsc_build_path(mdsc, req->r_old_dentry, &path_info, 0);
103103
if (IS_ERR(path))
104104
path = NULL;

fs/ceph/dir.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1364,7 +1364,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
13641364
if (!dn) {
13651365
try_async = false;
13661366
} else {
1367-
struct ceph_path_info path_info;
1367+
struct ceph_path_info path_info = {0};
13681368
path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0);
13691369
if (IS_ERR(path)) {
13701370
try_async = false;

fs/ceph/file.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ int ceph_open(struct inode *inode, struct file *file)
397397
if (!dentry) {
398398
do_sync = true;
399399
} else {
400-
struct ceph_path_info path_info;
400+
struct ceph_path_info path_info = {0};
401401
path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
402402
if (IS_ERR(path)) {
403403
do_sync = true;
@@ -807,7 +807,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
807807
if (!dn) {
808808
try_async = false;
809809
} else {
810-
struct ceph_path_info path_info;
810+
struct ceph_path_info path_info = {0};
811811
path = ceph_mdsc_build_path(mdsc, dn, &path_info, 0);
812812
if (IS_ERR(path)) {
813813
try_async = false;

fs/ceph/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2551,7 +2551,7 @@ int __ceph_setattr(struct mnt_idmap *idmap, struct inode *inode,
25512551
if (!dentry) {
25522552
do_sync = true;
25532553
} else {
2554-
struct ceph_path_info path_info;
2554+
struct ceph_path_info path_info = {0};
25552555
path = ceph_mdsc_build_path(mdsc, dentry, &path_info, 0);
25562556
if (IS_ERR(path)) {
25572557
do_sync = true;

0 commit comments

Comments
 (0)