From 130d4924fccf9cbf630664322e8e6b2b013adda7 Mon Sep 17 00:00:00 2001 From: waterwin Date: Sat, 22 Jul 2023 14:13:58 +0000 Subject: [PATCH] hmdfs:merge view UAF in dentry Signed-off-by: waterwin --- fs/hmdfs/dentry.c | 6 ++++-- fs/hmdfs/hmdfs_merge_view.h | 5 +++-- fs/hmdfs/hmdfs_trace.h | 34 ++++++++++++++++++++++++++++++++++ fs/hmdfs/inode_merge.c | 14 +++++++++----- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/fs/hmdfs/dentry.c b/fs/hmdfs/dentry.c index 040d698e1785..d89c34045da8 100644 --- a/fs/hmdfs/dentry.c +++ b/fs/hmdfs/dentry.c @@ -310,7 +310,7 @@ static int d_revalidate_merge(struct dentry *direntry, unsigned int flags) return 1; parent_dentry = dget_parent(direntry); - mutex_lock(&dim->comrade_list_lock); + mutex_lock(&dim->comrade_list_lock); list_for_each_entry(comrade, &(dim->comrade_list), list) { lower_cur_parent_dentry = dget_parent(comrade->lo_d); if ((comrade->lo_d->d_flags & DCACHE_OP_REVALIDATE)) { @@ -324,19 +324,21 @@ static int d_revalidate_merge(struct dentry *direntry, unsigned int flags) dput(lower_cur_parent_dentry); } out: - mutex_unlock(&dim->comrade_list_lock); + mutex_unlock(&dim->comrade_list_lock); dput(parent_dentry); return ret; } static void d_release_merge(struct dentry *dentry) { + trace_d_release_merge_enter(dentry); if (!dentry || !dentry->d_fsdata) return; clear_comrades(dentry); kmem_cache_free(hmdfs_dentry_merge_cachep, dentry->d_fsdata); dentry->d_fsdata = NULL; + trace_d_release_merge_exit(dentry); } const struct dentry_operations hmdfs_dops_merge = { diff --git a/fs/hmdfs/hmdfs_merge_view.h b/fs/hmdfs/hmdfs_merge_view.h index bf647780cf9c..ed72cbd01e2a 100644 --- a/fs/hmdfs/hmdfs_merge_view.h +++ b/fs/hmdfs/hmdfs_merge_view.h @@ -28,6 +28,7 @@ struct merge_lookup_work { struct hmdfs_sb_info *sbi; wait_queue_head_t *wait_queue; struct work_struct work; + struct dentry *dentry; }; struct hmdfs_dentry_info_merge { @@ -118,8 +119,8 @@ struct hmdfs_dentry_comrade *lookup_comrade(struct path lower_path, unsigned int flags); bool is_valid_comrade(struct hmdfs_dentry_info_merge *mdi, umode_t mode); int merge_lookup_async(struct hmdfs_dentry_info_merge *mdi, - struct hmdfs_sb_info *sbi, int devid, - const char *name, unsigned int flags); + struct hmdfs_sb_info *sbi, struct dentry *dentry, + int devid, const char *name, unsigned int flags); char *hmdfs_get_real_dname(struct dentry *dentry, int *devid, int *type); void lock_root_inode_shared(struct inode *root, bool *locked, bool *down); void restore_root_inode_sem(struct inode *root, bool locked, bool down); diff --git a/fs/hmdfs/hmdfs_trace.h b/fs/hmdfs/hmdfs_trace.h index df098885e83a..65ca11bcf7e6 100644 --- a/fs/hmdfs/hmdfs_trace.h +++ b/fs/hmdfs/hmdfs_trace.h @@ -883,6 +883,40 @@ TRACE_EVENT(hmdfs_merge_update_dentry_info_exit, __get_str(dst_name)) ); +TRACE_EVENT(d_release_merge_enter, + + TP_PROTO(struct dentry *dentry), + + TP_ARGS(dentry), + + TP_STRUCT__entry( + __string(name, dentry->d_name.name) + ), + + TP_fast_assign( + __assign_str(name, dentry->d_name.name); + ), + + TP_printk("name:%s", __get_str(name)) +); + +TRACE_EVENT(d_release_merge_exit, + + TP_PROTO(struct dentry *dentry), + + TP_ARGS(dentry), + + TP_STRUCT__entry( + __string(name, dentry->d_name.name) + ), + + TP_fast_assign( + __assign_str(name, dentry->d_name.name); + ), + + TP_printk("name:%s", __get_str(name)) +); + #endif #undef TRACE_INCLUDE_PATH diff --git a/fs/hmdfs/inode_merge.c b/fs/hmdfs/inode_merge.c index 636c8bc55c40..015d1532ae30 100644 --- a/fs/hmdfs/inode_merge.c +++ b/fs/hmdfs/inode_merge.c @@ -427,14 +427,16 @@ static void merge_lookup_work_func(struct work_struct *work) wake_up_all(ml_work->wait_queue); mutex_unlock(&mdi->work_lock); + dput(ml_work->dentry); + trace_hmdfs_merge_lookup_work_exit(ml_work, found); kfree(ml_work->name); kfree(ml_work); } int merge_lookup_async(struct hmdfs_dentry_info_merge *mdi, - struct hmdfs_sb_info *sbi, int devid, const char *name, - unsigned int flags) + struct hmdfs_sb_info *sbi, struct dentry *dentry, int devid, + const char *name, unsigned int flags) { int err = -ENOMEM; struct merge_lookup_work *ml_work; @@ -453,6 +455,8 @@ int merge_lookup_async(struct hmdfs_dentry_info_merge *mdi, ml_work->flags = flags; ml_work->sbi = sbi; ml_work->wait_queue = &mdi->wait_queue; + ml_work->dentry = dentry; + dget(dentry); INIT_WORK(&ml_work->work, merge_lookup_work_func); schedule_work(&ml_work->work); @@ -510,7 +514,7 @@ static int lookup_merge_normal(struct dentry *dentry, unsigned int flags) if (mdi->type != DT_REG || devid == 0) { snprintf(cpath, PATH_MAX, "device_view/local%s/%s", ppath, rname); - err = merge_lookup_async(mdi, sbi, 0, cpath, flags); + err = merge_lookup_async(mdi, sbi, dentry, 0, cpath, flags); if (err) hmdfs_err("failed to create local lookup work"); } @@ -520,8 +524,8 @@ static int lookup_merge_normal(struct dentry *dentry, unsigned int flags) continue; snprintf(cpath, PATH_MAX, "device_view/%s%s/%s", peer->cid, ppath, rname); - err = merge_lookup_async(mdi, sbi, peer->device_id, cpath, - flags); + err = merge_lookup_async(mdi, sbi, dentry, peer->device_id, + cpath, flags); if (err) hmdfs_err("failed to create remote lookup work"); } -- Gitee