From: Greg Kroah-Hartman Date: Sat, 30 Dec 2023 11:23:50 +0000 (+0000) Subject: 6.1-stable patches X-Git-Tag: v6.1.70~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7139642a2775d2c33d68122623fc7a54fe97556d;p=thirdparty%2Fkernel%2Fstable-queue.git 6.1-stable patches added patches: fuse-share-lookup-state-between-submount-and-its-parent.patch mm-damon-core-make-damon_start-waits-until-kdamond_fn-starts.patch tracing-kprobes-fix-symbol-counting-logic-by-looking-at-modules-as-well.patch --- diff --git a/queue-6.1/fuse-share-lookup-state-between-submount-and-its-parent.patch b/queue-6.1/fuse-share-lookup-state-between-submount-and-its-parent.patch new file mode 100644 index 00000000000..85f908b356a --- /dev/null +++ b/queue-6.1/fuse-share-lookup-state-between-submount-and-its-parent.patch @@ -0,0 +1,222 @@ +From c4d361f66ac91db8fc65061a9671682f61f4ca9d Mon Sep 17 00:00:00 2001 +From: Krister Johansen +Date: Fri, 3 Nov 2023 10:39:47 -0700 +Subject: fuse: share lookup state between submount and its parent + +From: Krister Johansen + +commit c4d361f66ac91db8fc65061a9671682f61f4ca9d upstream. + +Fuse submounts do not perform a lookup for the nodeid that they inherit +from their parent. Instead, the code decrements the nlookup on the +submount's fuse_inode when it is instantiated, and no forget is +performed when a submount root is evicted. + +Trouble arises when the submount's parent is evicted despite the +submount itself being in use. In this author's case, the submount was +in a container and deatched from the initial mount namespace via a +MNT_DEATCH operation. When memory pressure triggered the shrinker, the +inode from the parent was evicted, which triggered enough forgets to +render the submount's nodeid invalid. + +Since submounts should still function, even if their parent goes away, +solve this problem by sharing refcounted state between the parent and +its submount. When all of the references on this shared state reach +zero, it's safe to forget the final lookup of the fuse nodeid. + +Signed-off-by: Krister Johansen +Cc: stable@vger.kernel.org +Fixes: 1866d779d5d2 ("fuse: Allow fuse_fill_super_common() for submounts") +Signed-off-by: Miklos Szeredi +Signed-off-by: Krister Johansen +Signed-off-by: Greg Kroah-Hartman +--- + fs/fuse/fuse_i.h | 15 +++++++++++ + fs/fuse/inode.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 87 insertions(+), 3 deletions(-) + +--- a/fs/fuse/fuse_i.h ++++ b/fs/fuse/fuse_i.h +@@ -63,6 +63,19 @@ struct fuse_forget_link { + struct fuse_forget_link *next; + }; + ++/* Submount lookup tracking */ ++struct fuse_submount_lookup { ++ /** Refcount */ ++ refcount_t count; ++ ++ /** Unique ID, which identifies the inode between userspace ++ * and kernel */ ++ u64 nodeid; ++ ++ /** The request used for sending the FORGET message */ ++ struct fuse_forget_link *forget; ++}; ++ + /** FUSE inode */ + struct fuse_inode { + /** Inode data */ +@@ -155,6 +168,8 @@ struct fuse_inode { + */ + struct fuse_inode_dax *dax; + #endif ++ /** Submount specific lookup tracking */ ++ struct fuse_submount_lookup *submount_lookup; + }; + + /** FUSE inode state bits */ +--- a/fs/fuse/inode.c ++++ b/fs/fuse/inode.c +@@ -68,6 +68,24 @@ struct fuse_forget_link *fuse_alloc_forg + return kzalloc(sizeof(struct fuse_forget_link), GFP_KERNEL_ACCOUNT); + } + ++static struct fuse_submount_lookup *fuse_alloc_submount_lookup(void) ++{ ++ struct fuse_submount_lookup *sl; ++ ++ sl = kzalloc(sizeof(struct fuse_submount_lookup), GFP_KERNEL_ACCOUNT); ++ if (!sl) ++ return NULL; ++ sl->forget = fuse_alloc_forget(); ++ if (!sl->forget) ++ goto out_free; ++ ++ return sl; ++ ++out_free: ++ kfree(sl); ++ return NULL; ++} ++ + static struct inode *fuse_alloc_inode(struct super_block *sb) + { + struct fuse_inode *fi; +@@ -83,6 +101,7 @@ static struct inode *fuse_alloc_inode(st + fi->attr_version = 0; + fi->orig_ino = 0; + fi->state = 0; ++ fi->submount_lookup = NULL; + mutex_init(&fi->mutex); + spin_lock_init(&fi->lock); + fi->forget = fuse_alloc_forget(); +@@ -113,6 +132,17 @@ static void fuse_free_inode(struct inode + kmem_cache_free(fuse_inode_cachep, fi); + } + ++static void fuse_cleanup_submount_lookup(struct fuse_conn *fc, ++ struct fuse_submount_lookup *sl) ++{ ++ if (!refcount_dec_and_test(&sl->count)) ++ return; ++ ++ fuse_queue_forget(fc, sl->forget, sl->nodeid, 1); ++ sl->forget = NULL; ++ kfree(sl); ++} ++ + static void fuse_evict_inode(struct inode *inode) + { + struct fuse_inode *fi = get_fuse_inode(inode); +@@ -132,6 +162,11 @@ static void fuse_evict_inode(struct inod + fi->nlookup); + fi->forget = NULL; + } ++ ++ if (fi->submount_lookup) { ++ fuse_cleanup_submount_lookup(fc, fi->submount_lookup); ++ fi->submount_lookup = NULL; ++ } + } + if (S_ISREG(inode->i_mode) && !fuse_is_bad(inode)) { + WARN_ON(!list_empty(&fi->write_files)); +@@ -311,6 +346,13 @@ void fuse_change_attributes(struct inode + fuse_dax_dontcache(inode, attr->flags); + } + ++static void fuse_init_submount_lookup(struct fuse_submount_lookup *sl, ++ u64 nodeid) ++{ ++ sl->nodeid = nodeid; ++ refcount_set(&sl->count, 1); ++} ++ + static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) + { + inode->i_mode = attr->mode & S_IFMT; +@@ -368,12 +410,22 @@ struct inode *fuse_iget(struct super_blo + */ + if (fc->auto_submounts && (attr->flags & FUSE_ATTR_SUBMOUNT) && + S_ISDIR(attr->mode)) { ++ struct fuse_inode *fi; ++ + inode = new_inode(sb); + if (!inode) + return NULL; + + fuse_init_inode(inode, attr); +- get_fuse_inode(inode)->nodeid = nodeid; ++ fi = get_fuse_inode(inode); ++ fi->nodeid = nodeid; ++ fi->submount_lookup = fuse_alloc_submount_lookup(); ++ if (!fi->submount_lookup) { ++ iput(inode); ++ return NULL; ++ } ++ /* Sets nlookup = 1 on fi->submount_lookup->nlookup */ ++ fuse_init_submount_lookup(fi->submount_lookup, nodeid); + inode->i_flags |= S_AUTOMOUNT; + goto done; + } +@@ -396,11 +448,11 @@ retry: + iput(inode); + goto retry; + } +-done: + fi = get_fuse_inode(inode); + spin_lock(&fi->lock); + fi->nlookup++; + spin_unlock(&fi->lock); ++done: + fuse_change_attributes(inode, attr, attr_valid, attr_version); + + return inode; +@@ -1439,6 +1491,8 @@ static int fuse_fill_super_submount(stru + struct super_block *parent_sb = parent_fi->inode.i_sb; + struct fuse_attr root_attr; + struct inode *root; ++ struct fuse_submount_lookup *sl; ++ struct fuse_inode *fi; + + fuse_sb_defaults(sb); + fm->sb = sb; +@@ -1461,12 +1515,27 @@ static int fuse_fill_super_submount(stru + * its nlookup should not be incremented. fuse_iget() does + * that, though, so undo it here. + */ +- get_fuse_inode(root)->nlookup--; ++ fi = get_fuse_inode(root); ++ fi->nlookup--; ++ + sb->s_d_op = &fuse_dentry_operations; + sb->s_root = d_make_root(root); + if (!sb->s_root) + return -ENOMEM; + ++ /* ++ * Grab the parent's submount_lookup pointer and take a ++ * reference on the shared nlookup from the parent. This is to ++ * prevent the last forget for this nodeid from getting ++ * triggered until all users have finished with it. ++ */ ++ sl = parent_fi->submount_lookup; ++ WARN_ON(!sl); ++ if (sl) { ++ refcount_inc(&sl->count); ++ fi->submount_lookup = sl; ++ } ++ + return 0; + } + diff --git a/queue-6.1/mm-damon-core-make-damon_start-waits-until-kdamond_fn-starts.patch b/queue-6.1/mm-damon-core-make-damon_start-waits-until-kdamond_fn-starts.patch new file mode 100644 index 00000000000..fd49ed53350 --- /dev/null +++ b/queue-6.1/mm-damon-core-make-damon_start-waits-until-kdamond_fn-starts.patch @@ -0,0 +1,92 @@ +From 6376a824595607e99d032a39ba3394988b4fce96 Mon Sep 17 00:00:00 2001 +From: SeongJae Park +Date: Fri, 8 Dec 2023 17:50:18 +0000 +Subject: mm/damon/core: make damon_start() waits until kdamond_fn() starts + +From: SeongJae Park + +commit 6376a824595607e99d032a39ba3394988b4fce96 upstream. + +The cleanup tasks of kdamond threads including reset of corresponding +DAMON context's ->kdamond field and decrease of global nr_running_ctxs +counter is supposed to be executed by kdamond_fn(). However, commit +0f91d13366a4 ("mm/damon: simplify stop mechanism") made neither +damon_start() nor damon_stop() ensure the corresponding kdamond has +started the execution of kdamond_fn(). + +As a result, the cleanup can be skipped if damon_stop() is called fast +enough after the previous damon_start(). Especially the skipped reset +of ->kdamond could cause a use-after-free. + +Fix it by waiting for start of kdamond_fn() execution from +damon_start(). + +Link: https://lkml.kernel.org/r/20231208175018.63880-1-sj@kernel.org +Fixes: 0f91d13366a4 ("mm/damon: simplify stop mechanism") +Signed-off-by: SeongJae Park +Reported-by: Jakub Acs +Cc: Changbin Du +Cc: Jakub Acs +Cc: # 5.15.x +Signed-off-by: Andrew Morton +Signed-off-by: SeongJae Park +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/damon.h | 3 +++ + mm/damon/core.c | 7 +++++++ + 2 files changed, 10 insertions(+) + +--- a/include/linux/damon.h ++++ b/include/linux/damon.h +@@ -8,6 +8,7 @@ + #ifndef _DAMON_H_ + #define _DAMON_H_ + ++#include + #include + #include + #include +@@ -452,6 +453,8 @@ struct damon_ctx { + /* private: internal use only */ + struct timespec64 last_aggregation; + struct timespec64 last_ops_update; ++ /* for waiting until the execution of the kdamond_fn is started */ ++ struct completion kdamond_started; + + /* public: */ + struct task_struct *kdamond; +--- a/mm/damon/core.c ++++ b/mm/damon/core.c +@@ -383,6 +383,8 @@ struct damon_ctx *damon_new_ctx(void) + if (!ctx) + return NULL; + ++ init_completion(&ctx->kdamond_started); ++ + ctx->attrs.sample_interval = 5 * 1000; + ctx->attrs.aggr_interval = 100 * 1000; + ctx->attrs.ops_update_interval = 60 * 1000 * 1000; +@@ -519,11 +521,14 @@ static int __damon_start(struct damon_ct + mutex_lock(&ctx->kdamond_lock); + if (!ctx->kdamond) { + err = 0; ++ reinit_completion(&ctx->kdamond_started); + ctx->kdamond = kthread_run(kdamond_fn, ctx, "kdamond.%d", + nr_running_ctxs); + if (IS_ERR(ctx->kdamond)) { + err = PTR_ERR(ctx->kdamond); + ctx->kdamond = NULL; ++ } else { ++ wait_for_completion(&ctx->kdamond_started); + } + } + mutex_unlock(&ctx->kdamond_lock); +@@ -1147,6 +1152,8 @@ static int kdamond_fn(void *data) + + pr_debug("kdamond (%d) starts\n", current->pid); + ++ complete(&ctx->kdamond_started); ++ + if (ctx->ops.init) + ctx->ops.init(ctx); + if (ctx->callback.before_start && ctx->callback.before_start(ctx)) diff --git a/queue-6.1/series b/queue-6.1/series index bb0fe3fdcd8..9a246a05c3b 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -106,3 +106,6 @@ kvm-arm64-vgic-simplify-kvm_vgic_destroy.patch kvm-arm64-vgic-add-a-non-locking-primitive-for-kvm_vgic_vcpu_destroy.patch kvm-arm64-vgic-force-vcpu-vgic-teardown-on-vcpu-destroy.patch x86-alternatives-sync-core-before-enabling-interrupts.patch +mm-damon-core-make-damon_start-waits-until-kdamond_fn-starts.patch +fuse-share-lookup-state-between-submount-and-its-parent.patch +tracing-kprobes-fix-symbol-counting-logic-by-looking-at-modules-as-well.patch diff --git a/queue-6.1/tracing-kprobes-fix-symbol-counting-logic-by-looking-at-modules-as-well.patch b/queue-6.1/tracing-kprobes-fix-symbol-counting-logic-by-looking-at-modules-as-well.patch new file mode 100644 index 00000000000..f9bf6392831 --- /dev/null +++ b/queue-6.1/tracing-kprobes-fix-symbol-counting-logic-by-looking-at-modules-as-well.patch @@ -0,0 +1,68 @@ +From 926fe783c8a64b33997fec405cf1af3e61aed441 Mon Sep 17 00:00:00 2001 +From: Andrii Nakryiko +Date: Fri, 27 Oct 2023 16:31:26 -0700 +Subject: tracing/kprobes: Fix symbol counting logic by looking at modules as well + +From: Andrii Nakryiko + +commit 926fe783c8a64b33997fec405cf1af3e61aed441 upstream. + +Recent changes to count number of matching symbols when creating +a kprobe event failed to take into account kernel modules. As such, it +breaks kprobes on kernel module symbols, by assuming there is no match. + +Fix this my calling module_kallsyms_on_each_symbol() in addition to +kallsyms_on_each_match_symbol() to perform a proper counting. + +Link: https://lore.kernel.org/all/20231027233126.2073148-1-andrii@kernel.org/ + +Cc: Francis Laniel +Cc: stable@vger.kernel.org +Cc: Masami Hiramatsu +Cc: Steven Rostedt +Fixes: b022f0c7e404 ("tracing/kprobes: Return EADDRNOTAVAIL when func matches several symbols") +Signed-off-by: Andrii Nakryiko +Acked-by: Song Liu +Signed-off-by: Masami Hiramatsu (Google) +Signed-off-by: Greg Kroah-Hartman +--- + kernel/trace/trace_kprobe.c | 24 ++++++++++++++++++++---- + 1 file changed, 20 insertions(+), 4 deletions(-) + +--- a/kernel/trace/trace_kprobe.c ++++ b/kernel/trace/trace_kprobe.c +@@ -714,14 +714,30 @@ static int count_symbols(void *data, uns + return 0; + } + ++struct sym_count_ctx { ++ unsigned int count; ++ const char *name; ++}; ++ ++static int count_mod_symbols(void *data, const char *name, unsigned long unused) ++{ ++ struct sym_count_ctx *ctx = data; ++ ++ if (strcmp(name, ctx->name) == 0) ++ ctx->count++; ++ ++ return 0; ++} ++ + static unsigned int number_of_same_symbols(char *func_name) + { +- unsigned int count; ++ struct sym_count_ctx ctx = { .count = 0, .name = func_name }; ++ ++ kallsyms_on_each_match_symbol(count_symbols, func_name, &ctx.count); + +- count = 0; +- kallsyms_on_each_match_symbol(count_symbols, func_name, &count); ++ module_kallsyms_on_each_symbol(NULL, count_mod_symbols, &ctx); + +- return count; ++ return ctx.count; + } + + static int __trace_kprobe_create(int argc, const char *argv[])