From aaa191abf6e35649e62ff63c51bcf8e92badac54 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Sep 08 2022 15:07:05 +0000 Subject: Merge branch 'SLE12-SP5' (ba832d0f0ce1) into 'SLE12-SP5-RT' - Refreshed -rt patches. patches.rt/tracing-Update-the-tracing-Inter-event-e.g.-latency-support-patch.patch patches.rt/0382-tracing-Add-support-for-dynamic-tracepoints.patch patches.rt/0417-tracing-Update-the-Inter-event-e.g.-latency-support-patch-to-v2.patch --- diff --git a/blacklist.conf b/blacklist.conf index 6732e48..f81633c 100644 --- a/blacklist.conf +++ b/blacklist.conf @@ -2239,3 +2239,6 @@ f53bad0881a35c45d89bd8c552dc0498b96403c5 # relevant only on m68k 089bca2caed0d0dea7da235ce1fe245808f5ec02 # lockdep warning 369f61bee0f584aee09f0736431eb9b330c98571 # lockdep warning b6d49cab44b567b3e0a5544b3d61e516a7355fad # Kconfig from imply to depends +dbac14a5a05ff8e1ce7c0da0e1f520ce39ec62ea # removal of export would break kabi +c5deb27895e017a0267de0a20d140ad5fcc55a54 # no fix needed, as problem is prohibited by other means +2fdbb8dd01556e1501132b5ad3826e8f71e24a8b # risk is too high without a real request diff --git a/patches.kabi/kABI-Fix-kABI-after-mm-rmap-Fix-anon_vma-degree-ambi.patch b/patches.kabi/kABI-Fix-kABI-after-mm-rmap-Fix-anon_vma-degree-ambi.patch new file mode 100644 index 0000000..d5a517e --- /dev/null +++ b/patches.kabi/kABI-Fix-kABI-after-mm-rmap-Fix-anon_vma-degree-ambi.patch @@ -0,0 +1,63 @@ +From aba7bc914ab6839a4368119d640d5f5cd5e54c85 Mon Sep 17 00:00:00 2001 +From: Vlastimil Babka +Date: Fri, 2 Sep 2022 13:18:12 +0200 +Subject: [PATCH] kABI: Fix kABI after "mm/rmap: Fix anon_vma->degree ambiguity + leading to double-reuse" +Patch-mainline; Never, SUSE kABI +References: git-fixes, bsc#1203098 + +The patch changes struct anon_vma which is exposed, although should not be used +by any non-core code. Move the new fields to the end (hidden from KABI checker) +and restore the removed degree field so the layout doesn't change within the old +size. + +Signed-off-by: Vlastimil Babka +--- + include/linux/rmap.h | 29 +++++++++++++++++++---------- + 1 file changed, 19 insertions(+), 10 deletions(-) + +--- a/include/linux/rmap.h ++++ b/include/linux/rmap.h +@@ -37,16 +37,12 @@ struct anon_vma { + */ + atomic_t refcount; + +- /* +- * Count of child anon_vmas. Equals to the count of all anon_vmas that +- * have ->parent pointing to this one, including itself. +- * +- * This counter is used for making decision about reusing anon_vma +- * instead of forking new one. See comments in function anon_vma_clone. +- */ +- unsigned long num_children; +- /* Count of VMAs whose ->anon_vma pointer points to this object. */ +- unsigned long num_active_vmas; ++ /* SUSE KABI compatibility placeholder */ ++#ifndef __GENKSYMS__ ++ unsigned __unused_degree; ++#else ++ unsigned degree; ++#endif + + struct anon_vma *parent; /* Parent of this anon_vma */ + +@@ -59,6 +55,19 @@ struct anon_vma { + * mm_take_all_locks() (mm_all_locks_mutex). + */ + struct rb_root rb_root; /* Interval tree of private "related" vmas */ ++ ++#ifndef __GENKSYMS__ ++ /* ++ * Count of child anon_vmas. Equals to the count of all anon_vmas that ++ * have ->parent pointing to this one, including itself. ++ * ++ * This counter is used for making decision about reusing anon_vma ++ * instead of forking new one. See comments in function anon_vma_clone. ++ */ ++ unsigned long num_children; ++ /* Count of VMAs whose ->anon_vma pointer points to this object. */ ++ unsigned long num_active_vmas; ++#endif + }; + + /* diff --git a/patches.rt/0382-tracing-Add-support-for-dynamic-tracepoints.patch b/patches.rt/0382-tracing-Add-support-for-dynamic-tracepoints.patch index 2dfade7..f4452f2 100644 --- a/patches.rt/0382-tracing-Add-support-for-dynamic-tracepoints.patch +++ b/patches.rt/0382-tracing-Add-support-for-dynamic-tracepoints.patch @@ -24,7 +24,7 @@ Signed-off-by: Mike Galbraith --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h -@@ -37,9 +37,12 @@ extern int +@@ -37,12 +37,15 @@ tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data); extern int tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data, @@ -33,12 +33,15 @@ Signed-off-by: Mike Galbraith +extern int dynamic_tracepoint_probe_register(struct tracepoint *tp, + void *probe, void *data); extern int + tracepoint_probe_register_prio_may_exist(struct tracepoint *tp, void *probe, void *data, + int prio); + extern int -tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data); +tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data, + bool dynamic); - extern void - for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv), - void *priv); + static inline int + tracepoint_probe_register_may_exist(struct tracepoint *tp, void *probe, + void *data) @@ -209,13 +212,13 @@ extern void syscall_unregfunc(void); int prio) \ { \ @@ -77,13 +80,12 @@ Signed-off-by: Mike Galbraith case TRACE_REG_PERF_CLOSE: --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c -@@ -192,12 +192,15 @@ static void *func_remove(struct tracepoi - * Add the probe function to a tracepoint. +@@ -193,12 +193,14 @@ */ static int tracepoint_add_func(struct tracepoint *tp, -- struct tracepoint_func *func, int prio) -+ struct tracepoint_func *func, int prio, -+ bool dynamic) + struct tracepoint_func *func, int prio, +- bool warn) ++ bool warn, bool dynamic) { struct tracepoint_func *old, *tp_funcs; int ret; @@ -133,7 +135,7 @@ Signed-off-by: Mike Galbraith } rcu_assign_pointer(tp->funcs, tp_funcs); @@ -258,7 +267,7 @@ static int tracepoint_remove_func(struct - } + EXPORT_SYMBOL_GPL(tracepoint_probe_register_prio_may_exist); /** - * tracepoint_probe_register - Connect a probe to a tracepoint @@ -154,8 +156,8 @@ Signed-off-by: Mike Galbraith tp_func.func = probe; tp_func.data = data; tp_func.prio = prio; -- ret = tracepoint_add_func(tp, &tp_func, prio); -+ ret = tracepoint_add_func(tp, &tp_func, prio, dynamic); +- ret = tracepoint_add_func(tp, &tp_func, prio, true); ++ ret = tracepoint_add_func(tp, &tp_func, prio, true, dynamic); mutex_unlock(&tracepoints_mutex); return ret; } diff --git a/patches.rt/0417-tracing-Update-the-Inter-event-e.g.-latency-support-patch-to-v2.patch b/patches.rt/0417-tracing-Update-the-Inter-event-e.g.-latency-support-patch-to-v2.patch index 6beceb3..4498b49 100644 --- a/patches.rt/0417-tracing-Update-the-Inter-event-e.g.-latency-support-patch-to-v2.patch +++ b/patches.rt/0417-tracing-Update-the-Inter-event-e.g.-latency-support-patch-to-v2.patch @@ -193,7 +193,7 @@ diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index 06fe0e9ffcb2..5fa1fb37d587 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h -@@ -37,12 +37,9 @@ extern int +@@ -37,15 +37,12 @@ tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data); extern int tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data, @@ -202,12 +202,15 @@ index 06fe0e9ffcb2..5fa1fb37d587 100644 - void *probe, void *data); + int prio); extern int + tracepoint_probe_register_prio_may_exist(struct tracepoint *tp, void *probe, void *data, + int prio); + extern int -tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data, - bool dynamic); +tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data); - extern void - for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv), - void *priv); + static inline int + tracepoint_probe_register_may_exist(struct tracepoint *tp, void *probe, + void *data) @@ -212,13 +209,13 @@ extern void syscall_unregfunc(void); int prio) \ { \ @@ -3134,13 +3137,12 @@ diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 12cbc4a144ad..3ce1bf967e6a 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c -@@ -192,14 +192,13 @@ static void *func_remove(struct tracepoint_func **funcs, - * Add the probe function to a tracepoint. +@@ -193,13 +193,13 @@ */ static int tracepoint_add_func(struct tracepoint *tp, -- struct tracepoint_func *func, int prio, -- bool dynamic) -+ struct tracepoint_func *func, int prio) + struct tracepoint_func *func, int prio, +- bool warn, bool dynamic) ++ bool warn) { struct tracepoint_func *old, *tp_funcs; int ret; @@ -3202,8 +3204,8 @@ index 12cbc4a144ad..3ce1bf967e6a 100644 tp_func.func = probe; tp_func.data = data; tp_func.prio = prio; -- ret = tracepoint_add_func(tp, &tp_func, prio, dynamic); -+ ret = tracepoint_add_func(tp, &tp_func, prio); +- ret = tracepoint_add_func(tp, &tp_func, prio, true, dynamic); ++ ret = tracepoint_add_func(tp, &tp_func, prio, true); mutex_unlock(&tracepoints_mutex); return ret; } diff --git a/patches.rt/tracing-Update-the-tracing-Inter-event-e.g.-latency-support-patch.patch b/patches.rt/tracing-Update-the-tracing-Inter-event-e.g.-latency-support-patch.patch index 780797c..dc5a443 100644 --- a/patches.rt/tracing-Update-the-tracing-Inter-event-e.g.-latency-support-patch.patch +++ b/patches.rt/tracing-Update-the-tracing-Inter-event-e.g.-latency-support-patch.patch @@ -117,7 +117,7 @@ Signed-off-by: Mike Galbraith --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c -@@ -2603,16 +2603,16 @@ rb_wakeups(struct ring_buffer *buffer, s +@@ -2623,16 +2623,16 @@ rb_wakeups(struct ring_buffer *buffer, s * IRQ context * NMI context * @@ -141,7 +141,7 @@ Signed-off-by: Mike Galbraith cpu_buffer->current_context++; --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c -@@ -7599,6 +7599,7 @@ static int instance_mkdir(const char *na +@@ -7591,6 +7591,7 @@ static int instance_mkdir(const char *na struct trace_array *tr; int ret; @@ -149,7 +149,7 @@ Signed-off-by: Mike Galbraith mutex_lock(&trace_types_lock); ret = -EEXIST; -@@ -7655,6 +7656,7 @@ static int instance_mkdir(const char *na +@@ -7647,6 +7648,7 @@ static int instance_mkdir(const char *na list_add(&tr->list, &ftrace_trace_arrays); mutex_unlock(&trace_types_lock); @@ -157,7 +157,7 @@ Signed-off-by: Mike Galbraith return 0; -@@ -7666,6 +7668,7 @@ static int instance_mkdir(const char *na +@@ -7658,6 +7660,7 @@ static int instance_mkdir(const char *na out_unlock: mutex_unlock(&trace_types_lock); @@ -165,7 +165,7 @@ Signed-off-by: Mike Galbraith return ret; -@@ -7678,6 +7681,7 @@ static int instance_rmdir(const char *na +@@ -7670,6 +7673,7 @@ static int instance_rmdir(const char *na int ret; int i; @@ -173,7 +173,7 @@ Signed-off-by: Mike Galbraith mutex_lock(&trace_types_lock); ret = -ENODEV; -@@ -7723,6 +7727,7 @@ static int instance_rmdir(const char *na +@@ -7715,6 +7719,7 @@ static int instance_rmdir(const char *na out_unlock: mutex_unlock(&trace_types_lock); @@ -183,7 +183,7 @@ Signed-off-by: Mike Galbraith } --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c -@@ -2924,24 +2924,24 @@ create_event_toplevel_files(struct dentr +@@ -2932,24 +2932,24 @@ create_event_toplevel_files(struct dentr * creates the event hierachry in the @parent/events directory. * * Returns 0 on success. @@ -213,7 +213,7 @@ Signed-off-by: Mike Galbraith return ret; } -@@ -2970,9 +2970,10 @@ early_event_add_tracer(struct dentry *pa +@@ -2978,9 +2978,10 @@ early_event_add_tracer(struct dentry *pa return ret; } @@ -225,7 +225,7 @@ Signed-off-by: Mike Galbraith /* Disable any event triggers and associated soft-disabled events */ clear_event_triggers(tr); -@@ -2993,8 +2994,6 @@ int event_trace_del_tracer(struct trace_ +@@ -3001,8 +3002,6 @@ int event_trace_del_tracer(struct trace_ tr->event_dir = NULL; @@ -690,7 +690,7 @@ Signed-off-by: Mike Galbraith } static const struct tracing_map_ops hist_trigger_elt_data_ops = { -@@ -2371,7 +2376,15 @@ struct hist_field *parse_atom(struct his +@@ -2372,7 +2377,15 @@ struct hist_field *parse_atom(struct his s = strchr(++s, '.'); if (s) { ref_system = strsep(&str, "."); @@ -706,7 +706,7 @@ Signed-off-by: Mike Galbraith ref_var = str; } } -@@ -2452,8 +2465,10 @@ static struct hist_field *parse_unary(st +@@ -2453,8 +2466,10 @@ static struct hist_field *parse_unary(st } strsep(&str, "("); @@ -718,7 +718,7 @@ Signed-off-by: Mike Galbraith flags |= HIST_FIELD_FL_EXPR; expr = create_hist_field(hist_data, NULL, flags, var_name); -@@ -3111,8 +3126,10 @@ static int onmax_create(struct hist_trig +@@ -3112,8 +3127,10 @@ static int onmax_create(struct hist_trig for (i = 0; i < data->n_params; i++) { param = kstrdup(data->params[i], GFP_KERNEL); @@ -730,7 +730,7 @@ Signed-off-by: Mike Galbraith field_var = create_target_field_var(hist_data, NULL, NULL, param); if (IS_ERR(field_var)) { -@@ -3144,8 +3161,10 @@ static int parse_action_params(char *par +@@ -3145,8 +3162,10 @@ static int parse_action_params(char *par goto out; param = strsep(¶ms, ","); @@ -742,7 +742,7 @@ Signed-off-by: Mike Galbraith param = strstrip(param); if (strlen(param) < 2) { -@@ -3196,8 +3215,10 @@ static struct action_data *onmax_parse(c +@@ -3197,8 +3216,10 @@ static struct action_data *onmax_parse(c if (strncmp(onmax_fn_name, "save", strlen("save")) == 0) { char *params = strsep(&str, ")"); @@ -754,7 +754,7 @@ Signed-off-by: Mike Galbraith ret = parse_action_params(params, data); if (ret) -@@ -3231,11 +3252,11 @@ static void onmatch_destroy(struct actio +@@ -3232,11 +3253,11 @@ static void onmatch_destroy(struct actio for (i = 0; i < data->n_params; i++) kfree(data->params[i]); @@ -768,7 +768,7 @@ Signed-off-by: Mike Galbraith mutex_unlock(&synth_event_mutex); } -@@ -3372,13 +3393,13 @@ static int onmatch_create(struct hist_tr +@@ -3373,13 +3394,13 @@ static int onmatch_create(struct hist_tr int ret = 0; mutex_lock(&synth_event_mutex); @@ -785,7 +785,7 @@ Signed-off-by: Mike Galbraith var_ref_idx = hist_data->n_var_refs; -@@ -3386,8 +3407,10 @@ static int onmatch_create(struct hist_tr +@@ -3387,8 +3408,10 @@ static int onmatch_create(struct hist_tr char *p; p = param = kstrdup(data->params[i], GFP_KERNEL); @@ -797,7 +797,7 @@ Signed-off-by: Mike Galbraith system = strsep(¶m, "."); if (!param) { -@@ -3401,6 +3424,7 @@ static int onmatch_create(struct hist_tr +@@ -3402,6 +3425,7 @@ static int onmatch_create(struct hist_tr goto out; } } @@ -805,7 +805,7 @@ Signed-off-by: Mike Galbraith if (param[0] == '$') hist_field = onmatch_find_var(hist_data, data, system, event_name, param); -@@ -3449,8 +3473,6 @@ static int onmatch_create(struct hist_tr +@@ -3450,8 +3474,6 @@ static int onmatch_create(struct hist_tr hist_data->actions[hist_data->n_actions++] = data; event->ref++; out: @@ -814,7 +814,7 @@ Signed-off-by: Mike Galbraith return ret; } -@@ -4840,11 +4862,10 @@ static bool hist_trigger_match(struct ev +@@ -4836,11 +4858,10 @@ static bool hist_trigger_match(struct ev return false; if (key_field->is_signed != key_field_test->is_signed) return false; @@ -829,7 +829,7 @@ Signed-off-by: Mike Galbraith return false; } -@@ -5027,8 +5048,10 @@ static void hist_unregister_trigger(char +@@ -5023,8 +5044,10 @@ static void hist_unregister_trigger(char if (unregistered && test->ops->free) test->ops->free(test->ops, test); @@ -842,7 +842,7 @@ Signed-off-by: Mike Galbraith } static bool hist_file_check_refs(struct trace_event_file *file) -@@ -5041,7 +5064,6 @@ static bool hist_file_check_refs(struct +@@ -5037,7 +5060,6 @@ static bool hist_file_check_refs(struct hist_data = test->private_data; if (check_var_refs(hist_data)) return true; @@ -850,7 +850,7 @@ Signed-off-by: Mike Galbraith } } -@@ -5093,7 +5115,10 @@ static int event_hist_trigger_func(struc +@@ -5089,7 +5111,10 @@ static int event_hist_trigger_func(struc if (glob[0] == '!') remove = true; @@ -862,7 +862,7 @@ Signed-off-by: Mike Galbraith trigger = param; p = strstr(param, " if"); if (!p) -@@ -5397,8 +5422,6 @@ static __init int trace_events_hist_init +@@ -5393,8 +5418,6 @@ static __init int trace_events_hist_init goto err; } @@ -901,7 +901,7 @@ Signed-off-by: Mike Galbraith * struct) is still NULL. which means some other --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c -@@ -197,9 +197,7 @@ static int tracepoint_add_func(struct tr +@@ -198,9 +198,7 @@ static int tracepoint_add_func(struct tr struct tracepoint_func *old, *tp_funcs; int ret; @@ -912,7 +912,7 @@ Signed-off-by: Mike Galbraith ret = tp->regfunc(); if (ret < 0) return ret; -@@ -221,9 +219,7 @@ static int tracepoint_add_func(struct tr +@@ -222,9 +220,7 @@ static int tracepoint_add_func(struct tr * is used. */ rcu_assign_pointer(tp->funcs, tp_funcs); @@ -923,7 +923,7 @@ Signed-off-by: Mike Galbraith static_key_slow_inc(&tp->key); release_probes(old); return 0; -@@ -250,14 +246,10 @@ static int tracepoint_remove_func(struct +@@ -251,14 +247,10 @@ static int tracepoint_remove_func(struct if (!tp_funcs) { /* Removed last function */ @@ -940,8 +940,8 @@ Signed-off-by: Mike Galbraith static_key_slow_dec(&tp->key); } rcu_assign_pointer(tp->funcs, tp_funcs); -@@ -266,7 +258,7 @@ static int tracepoint_remove_func(struct - } +@@ -293,7 +285,7 @@ int tracepoint_probe_register_prio_may_e + EXPORT_SYMBOL_GPL(tracepoint_probe_register_prio_may_exist); /** - * tracepoint_probe_register_prio - Connect a probe to a tracepoint diff --git a/patches.suse/KVM-x86-Mark-TSS-busy-during-LTR-emulation-_after_-a.patch b/patches.suse/KVM-x86-Mark-TSS-busy-during-LTR-emulation-_after_-a.patch new file mode 100644 index 0000000..1e716f0 --- /dev/null +++ b/patches.suse/KVM-x86-Mark-TSS-busy-during-LTR-emulation-_after_-a.patch @@ -0,0 +1,70 @@ +Patch-mainline: v6.0-rc1 +Git-commit: ec6e4d863258d4bfb36d48d5e3ef68140234d688 +References: git-fixes +From: Sean Christopherson +Date: Mon, 11 Jul 2022 23:27:48 +0000 +Subject: [PATCH] KVM: x86: Mark TSS busy during LTR emulation _after_ all + fault checks + +Wait to mark the TSS as busy during LTR emulation until after all fault +checks for the LTR have passed. Specifically, don't mark the TSS busy if +the new TSS base is non-canonical. + +Opportunistically drop the one-off !seg_desc.PRESENT check for TR as the +only reason for the early check was to avoid marking a !PRESENT TSS as +busy, i.e. the common !PRESENT is now done before setting the busy bit. + +Fixes: e37a75a13cda ("KVM: x86: Emulator ignores LDTR/TR extended base on LLDT/LTR") +Reported-by: syzbot+760a73552f47a8cd0fd9@syzkaller.appspotmail.com +Cc: stable@vger.kernel.org +Cc: Tetsuo Handa +Cc: Hou Wenlong +Signed-off-by: Sean Christopherson +Reviewed-by: Maxim Levitsky +Link: https://lore.kernel.org/r/20220711232750.1092012-2-seanjc@google.com +Signed-off-by: Sean Christopherson +Signed-off-by: Juergen Gross +--- + arch/x86/kvm/emulate.c | 19 +++++++++---------- + 1 file changed, 9 insertions(+), 10 deletions(-) + +diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c +index 39ea9138224c..09e4b67b881f 100644 +--- a/arch/x86/kvm/emulate.c ++++ b/arch/x86/kvm/emulate.c +@@ -1699,16 +1699,6 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, + case VCPU_SREG_TR: + if (seg_desc.s || (seg_desc.type != 1 && seg_desc.type != 9)) + goto exception; +- if (!seg_desc.p) { +- err_vec = NP_VECTOR; +- goto exception; +- } +- old_desc = seg_desc; +- seg_desc.type |= 2; /* busy */ +- ret = ctxt->ops->cmpxchg_emulated(ctxt, desc_addr, &old_desc, &seg_desc, +- sizeof(seg_desc), &ctxt->exception); +- if (ret != X86EMUL_CONTINUE) +- return ret; + break; + case VCPU_SREG_LDTR: + if (seg_desc.s || seg_desc.type != 2) +@@ -1749,6 +1739,15 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, + ((u64)base3 << 32), ctxt)) + return emulate_gp(ctxt, 0); + } ++ ++ if (seg == VCPU_SREG_TR) { ++ old_desc = seg_desc; ++ seg_desc.type |= 2; /* busy */ ++ ret = ctxt->ops->cmpxchg_emulated(ctxt, desc_addr, &old_desc, &seg_desc, ++ sizeof(seg_desc), &ctxt->exception); ++ if (ret != X86EMUL_CONTINUE) ++ return ret; ++ } + load: + ctxt->ops->set_segment(ctxt, selector, &seg_desc, base3, seg); + if (desc) +-- +2.35.3 + diff --git a/patches.suse/KVM-x86-Set-error-code-to-segment-selector-on-LLDT-L.patch b/patches.suse/KVM-x86-Set-error-code-to-segment-selector-on-LLDT-L.patch new file mode 100644 index 0000000..ef736c8 --- /dev/null +++ b/patches.suse/KVM-x86-Set-error-code-to-segment-selector-on-LLDT-L.patch @@ -0,0 +1,45 @@ +Patch-mainline: v6.0-rc1 +Git-commit: 2626206963ace9e8bf92b6eea5ff78dd674c555c +References: git-fixes +From: Sean Christopherson +Date: Mon, 11 Jul 2022 23:27:49 +0000 +Subject: [PATCH] KVM: x86: Set error code to segment selector on LLDT/LTR + non-canonical #GP + +When injecting a #GP on LLDT/LTR due to a non-canonical LDT/TSS base, set +the error code to the selector. Intel SDM's says nothing about the #GP, +but AMD's APM explicitly states that both LLDT and LTR set the error code +to the selector, not zero. + +Note, a non-canonical memory operand on LLDT/LTR does generate a #GP(0), +but the KVM code in question is specific to the base from the descriptor. + +Fixes: e37a75a13cda ("KVM: x86: Emulator ignores LDTR/TR extended base on LLDT/LTR") +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Reviewed-by: Maxim Levitsky +Link: https://lore.kernel.org/r/20220711232750.1092012-3-seanjc@google.com +Signed-off-by: Sean Christopherson +Signed-off-by: Juergen Gross +--- + arch/x86/kvm/emulate.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c +index 09e4b67b881f..bd9e9c5627d0 100644 +--- a/arch/x86/kvm/emulate.c ++++ b/arch/x86/kvm/emulate.c +@@ -1736,8 +1736,8 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, + if (ret != X86EMUL_CONTINUE) + return ret; + if (emul_is_noncanonical_address(get_desc_base(&seg_desc) | +- ((u64)base3 << 32), ctxt)) +- return emulate_gp(ctxt, 0); ++ ((u64)base3 << 32), ctxt)) ++ return emulate_gp(ctxt, err_code); + } + + if (seg == VCPU_SREG_TR) { +-- +2.35.3 + diff --git a/patches.suse/SUNRPC-Fix-the-svc_deferred_event-trace-class.patch b/patches.suse/SUNRPC-Fix-the-svc_deferred_event-trace-class.patch new file mode 100644 index 0000000..e65ab52 --- /dev/null +++ b/patches.suse/SUNRPC-Fix-the-svc_deferred_event-trace-class.patch @@ -0,0 +1,66 @@ +From: Chuck Lever +Date: Wed, 6 Apr 2022 13:51:32 -0400 +Subject: SUNRPC: Fix the svc_deferred_event trace class +Git-commit: 4d5004451ab2218eab94a30e1841462c9316ba19 +Patch-mainline: v5.18-rc3 +References: git-fixes + +Fix a NULL deref crash that occurs when an svc_rqst is deferred +while the sunrpc tracing subsystem is enabled. svc_revisit() sets +dr->xprt to NULL, so it can't be relied upon in the tracepoint to +provide the remote's address. + +Unfortunately we can't revert the "svc_deferred_class" hunk in +commit ece200ddd54b ("sunrpc: Save remote presentation address in +svc_xprt for trace events") because there is now a specific check +of event format specifiers for unsafe dereferences. The warning +that check emits is: + + event svc_defer_recv has unsafe dereference of argument 1 + +A "%pISpc" format specifier with a "struct sockaddr *" is indeed +flagged by this check. + +Instead, take the brute-force approach used by the svcrdma_qp_error +tracepoint. Convert the dr::addr field into a presentation address +in the TP_fast_assign() arm of the trace event, and store that as +a string. This fix can be backported to -stable kernels. + +In the meantime, commit c6ced22997ad ("tracing: Update print fmt +check to handle new __get_sockaddr() macro") is now in v5.18, so +this wonky fix can be replaced with __sockaddr() and friends +properly during the v5.19 merge window. + +Fixes: ece200ddd54b ("sunrpc: Save remote presentation address in svc_xprt for trace events") +Signed-off-by: Chuck Lever +Acked-by: Petr Pavlu +--- + include/trace/events/sunrpc.h | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h +index ab8ae1f6ba84..4eb706fa5825 100644 +--- a/include/trace/events/sunrpc.h ++++ b/include/trace/events/sunrpc.h +@@ -2017,16 +2017,17 @@ DECLARE_EVENT_CLASS(svc_deferred_event, + + TP_STRUCT__entry( + __field(u32, xid) +- __string(addr, dr->xprt->xpt_remotebuf) ++ __array(__u8, addr, INET6_ADDRSTRLEN + 10) + ), + + TP_fast_assign( + __entry->xid = be32_to_cpu(*(__be32 *)(dr->args + + (dr->xprt_hlen>>2))); +- __assign_str(addr, dr->xprt->xpt_remotebuf); ++ snprintf(__entry->addr, sizeof(__entry->addr) - 1, ++ "%pISpc", (struct sockaddr *)&dr->addr); + ), + +- TP_printk("addr=%s xid=0x%08x", __get_str(addr), __entry->xid) ++ TP_printk("addr=%s xid=0x%08x", __entry->addr, __entry->xid) + ); + + DEFINE_EVENT(svc_deferred_event, svc_drop_deferred, + diff --git a/patches.suse/af_key-Do-not-call-xfrm_probe_algs-in-parallel.patch b/patches.suse/af_key-Do-not-call-xfrm_probe_algs-in-parallel.patch new file mode 100644 index 0000000..a7af65e --- /dev/null +++ b/patches.suse/af_key-Do-not-call-xfrm_probe_algs-in-parallel.patch @@ -0,0 +1,41 @@ +From ba953a9d89a00c078b85f4b190bc1dde66fe16b5 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Thu, 4 Aug 2022 18:03:46 +0800 +Subject: [PATCH] af_key: Do not call xfrm_probe_algs in parallel +Git-commit: ba953a9d89a00c078b85f4b190bc1dde66fe16b5 +Patch-mainline: v6.0-rc3 +References: bsc#1202898 CVE-2022-3028 + +When namespace support was added to xfrm/afkey, it caused the +previously single-threaded call to xfrm_probe_algs to become +multi-threaded. This is buggy and needs to be fixed with a mutex. + +Reported-by: Abhishek Shah +Fixes: 283bc9f35bbb ("xfrm: Namespacify xfrm state/policy locks") +Signed-off-by: Herbert Xu +Signed-off-by: Steffen Klassert +Signed-off-by: Denis Kirjanov +--- + net/key/af_key.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/net/key/af_key.c b/net/key/af_key.c +index fb16d7c4e1b8..20e73643b9c8 100644 +--- a/net/key/af_key.c ++++ b/net/key/af_key.c +@@ -1697,9 +1697,12 @@ static int pfkey_register(struct sock *sk, struct sk_buff *skb, const struct sad + pfk->registered |= (1<sadb_msg_satype); + } + ++ mutex_lock(&pfkey_mutex); + xfrm_probe_algs(); + + supp_skb = compose_sadb_supported(hdr, GFP_KERNEL | __GFP_ZERO); ++ mutex_unlock(&pfkey_mutex); ++ + if (!supp_skb) { + if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC) + pfk->registered &= ~(1<sadb_msg_satype); +-- +2.16.4 + diff --git a/patches.suse/ceph-don-t-truncate-file-in-atomic_open.patch b/patches.suse/ceph-don-t-truncate-file-in-atomic_open.patch new file mode 100644 index 0000000..8af47bb --- /dev/null +++ b/patches.suse/ceph-don-t-truncate-file-in-atomic_open.patch @@ -0,0 +1,50 @@ +From: Hu Weiwen +Date: Fri, 1 Jul 2022 10:52:27 +0800 +Subject: ceph: don't truncate file in atomic_open +Git-commit: 7cb9994754f8a36ae9e5ec4597c5c4c2d6c03832 +Patch-mainline: v6.0-rc1 +References: bsc#1202830 + +Clear O_TRUNC from the flags sent in the MDS create request. + +`atomic_open' is called before permission check. We should not do any +modification to the file here. The caller will do the truncation +afterward. + +Fixes: 124e68e74099 ("ceph: file operations") +Signed-off-by: Hu Weiwen +Reviewed-by: Xiubo Li +Signed-off-by: Ilya Dryomov +Acked-by: Luis Henriques + +--- + fs/ceph/file.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/fs/ceph/file.c ++++ b/fs/ceph/file.c +@@ -447,6 +447,12 @@ int ceph_atomic_open(struct inode *dir, + if (dentry->d_name.len > NAME_MAX) + return -ENAMETOOLONG; + ++ /* ++ * Do not truncate the file, since atomic_open is called before the ++ * permission check. The caller will do the truncation afterward. ++ */ ++ flags &= ~O_TRUNC; ++ + if (flags & O_CREAT) { + if (ceph_quota_is_max_files_exceeded(dir)) + return -EDQUOT; +@@ -482,9 +488,7 @@ int ceph_atomic_open(struct inode *dir, + + req->r_parent = dir; + set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags); +- err = ceph_mdsc_do_request(mdsc, +- (flags & (O_CREAT|O_TRUNC)) ? dir : NULL, +- req); ++ err = ceph_mdsc_do_request(mdsc, (flags & O_CREAT) ? dir : NULL, req); + err = ceph_handle_snapdir(req, dentry, err); + if (err) + goto out_req; + diff --git a/patches.suse/ext4-Fix-check-for-block-being-out-of-directory-size.patch b/patches.suse/ext4-Fix-check-for-block-being-out-of-directory-size.patch new file mode 100644 index 0000000..68a1d95 --- /dev/null +++ b/patches.suse/ext4-Fix-check-for-block-being-out-of-directory-size.patch @@ -0,0 +1,35 @@ +From 9fd3f1868e9e3bb249546edba45889c18d40bd6d Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Mon, 22 Aug 2022 13:20:59 +0200 +Subject: [PATCH] ext4: Fix check for block being out of directory size +References: bsc#1198577 CVE-2022-1184 +Patch-mainline: Submitted, Aug 22 2022 + +The check in __ext4_read_dirblock() for block being outside of directory +size was wrong because it compared block number against directory size +in bytes. Fix it. + +Fixes: 65f8ea4cd57d ("ext4: check if directory block is within i_size") +CVE: CVE-2022-1184 +CC: stable@vger.kernel.org +Signed-off-by: Jan Kara +--- + fs/ext4/namei.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c +index 3a31b662f661..bc2e0612ec32 100644 +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -126,7 +126,7 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode, + struct ext4_dir_entry *dirent; + int is_dx_block = 0; + +- if (block >= inode->i_size) { ++ if (block >= inode->i_size >> inode->i_blkbits) { + ext4_error_inode(inode, func, line, block, + "Attempting to read directory block (%u) that is past i_size (%llu)", + block, inode->i_size); +-- +2.35.3 + diff --git a/patches.suse/ext4-check-if-directory-block-is-within-i_size.patch b/patches.suse/ext4-check-if-directory-block-is-within-i_size.patch new file mode 100644 index 0000000..3ef4d9c --- /dev/null +++ b/patches.suse/ext4-check-if-directory-block-is-within-i_size.patch @@ -0,0 +1,52 @@ +From 65f8ea4cd57dbd46ea13b41dc8bac03176b04233 Mon Sep 17 00:00:00 2001 +From: Lukas Czerner +Date: Mon, 4 Jul 2022 16:27:20 +0200 +Subject: [PATCH] ext4: check if directory block is within i_size +Git-commit: 65f8ea4cd57dbd46ea13b41dc8bac03176b04233 +Patch-mainline: v6.0-rc1 +References: bsc#1198577 CVE-2022-1184 + +Currently ext4 directory handling code implicitly assumes that the +directory blocks are always within the i_size. In fact ext4_append() +will attempt to allocate next directory block based solely on i_size and +the i_size is then appropriately increased after a successful +allocation. + +However, for this to work it requires i_size to be correct. If, for any +reason, the directory inode i_size is corrupted in a way that the +directory tree refers to a valid directory block past i_size, we could +end up corrupting parts of the directory tree structure by overwriting +already used directory blocks when modifying the directory. + +Fix it by catching the corruption early in __ext4_read_dirblock(). + +Addresses Red-Hat-Bugzilla: #2070205 + +Cve: CVE-2022-1184 +Signed-off-by: Lukas Czerner +Cc: stable@vger.kernel.org +Reviewed-by: Andreas Dilger +Link: https://lore.kernel.org/r/20220704142721.157985-1-lczerner@redhat.com +Signed-off-by: Theodore Ts'o +Acked-by: Jan Kara + +--- + fs/ext4/namei.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -109,6 +109,13 @@ static struct buffer_head *__ext4_read_d + struct ext4_dir_entry *dirent; + int is_dx_block = 0; + ++ if (block >= inode->i_size) { ++ ext4_error_inode(inode, func, line, block, ++ "Attempting to read directory block (%u) that is past i_size (%llu)", ++ block, inode->i_size); ++ return ERR_PTR(-EFSCORRUPTED); ++ } ++ + bh = ext4_bread(NULL, inode, block, 0); + if (IS_ERR(bh)) { + __ext4_warning(inode->i_sb, func, line, diff --git a/patches.suse/ext4-make-sure-ext4_append-always-allocates-new-bloc.patch b/patches.suse/ext4-make-sure-ext4_append-always-allocates-new-bloc.patch new file mode 100644 index 0000000..ed62987 --- /dev/null +++ b/patches.suse/ext4-make-sure-ext4_append-always-allocates-new-bloc.patch @@ -0,0 +1,63 @@ +From b8a04fe77ef1360fbf73c80fddbdfeaa9407ed1b Mon Sep 17 00:00:00 2001 +From: Lukas Czerner +Date: Mon, 4 Jul 2022 16:27:21 +0200 +Subject: [PATCH] ext4: make sure ext4_append() always allocates new block +Git-commit: b8a04fe77ef1360fbf73c80fddbdfeaa9407ed1b +Patch-mainline: v6.0-rc1 +References: bsc#1198577 CVE-2022-1184 + +ext4_append() must always allocate a new block, otherwise we run the +risk of overwriting existing directory block corrupting the directory +tree in the process resulting in all manner of problems later on. + +Add a sanity check to see if the logical block is already allocated and +error out if it is. + +Cc: stable@kernel.org +Signed-off-by: Lukas Czerner +Reviewed-by: Andreas Dilger +Link: https://lore.kernel.org/r/20220704142721.157985-2-lczerner@redhat.com +Signed-off-by: Theodore Ts'o +Acked-by: Jan Kara + +--- + fs/ext4/namei.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c +index 7fced54e2891..3a31b662f661 100644 +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -54,6 +54,7 @@ static struct buffer_head *ext4_append(handle_t *handle, + struct inode *inode, + ext4_lblk_t *block) + { ++ struct ext4_map_blocks map; + struct buffer_head *bh; + int err; + +@@ -63,6 +64,21 @@ static struct buffer_head *ext4_append(handle_t *handle, + return ERR_PTR(-ENOSPC); + + *block = inode->i_size >> inode->i_sb->s_blocksize_bits; ++ map.m_lblk = *block; ++ map.m_len = 1; ++ ++ /* ++ * We're appending new directory block. Make sure the block is not ++ * allocated yet, otherwise we will end up corrupting the ++ * directory. ++ */ ++ err = ext4_map_blocks(NULL, inode, &map, 0); ++ if (err < 0) ++ return ERR_PTR(err); ++ if (err) { ++ EXT4_ERROR_INODE(inode, "Logical block already allocated"); ++ return ERR_PTR(-EFSCORRUPTED); ++ } + + bh = ext4_bread(handle, inode, *block, EXT4_GET_BLOCKS_CREATE); + if (IS_ERR(bh)) +-- +2.35.3 + diff --git a/patches.suse/fuse-limit-nsec.patch b/patches.suse/fuse-limit-nsec.patch new file mode 100644 index 0000000..d39da45 --- /dev/null +++ b/patches.suse/fuse-limit-nsec.patch @@ -0,0 +1,34 @@ +From: Miklos Szeredi +Date: Thu, 21 Jul 2022 16:06:18 +0200 +Subject: fuse: limit nsec +Git-commit: 47912eaa061a6a81e4aa790591a1874c650733c0 +Patch-mainline: v6.0-rc1 +References: bsc#1203126 + +Limit nanoseconds to 0..999999999. + +Fixes: d8a5ba45457e ("[PATCH] FUSE - core") +Cc: +Signed-off-by: Miklos Szeredi +Acked-by: Luis Henriques + +--- + fs/fuse/inode.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/fs/fuse/inode.c ++++ b/fs/fuse/inode.c +@@ -174,6 +174,12 @@ void fuse_change_attributes_common(struc + inode->i_uid = make_kuid(&init_user_ns, attr->uid); + inode->i_gid = make_kgid(&init_user_ns, attr->gid); + inode->i_blocks = attr->blocks; ++ ++ /* Sanitize nsecs */ ++ attr->atimensec = min_t(u32, attr->atimensec, NSEC_PER_SEC - 1); ++ attr->mtimensec = min_t(u32, attr->mtimensec, NSEC_PER_SEC - 1); ++ attr->ctimensec = min_t(u32, attr->ctimensec, NSEC_PER_SEC - 1); ++ + inode->i_atime.tv_sec = attr->atime; + inode->i_atime.tv_nsec = attr->atimensec; + /* mtime from server may be stale due to local buffered write */ + diff --git a/patches.suse/lightnvm-remove-lightnvm-implemenation.patch b/patches.suse/lightnvm-remove-lightnvm-implemenation.patch new file mode 100644 index 0000000..d822994 --- /dev/null +++ b/patches.suse/lightnvm-remove-lightnvm-implemenation.patch @@ -0,0 +1,1306 @@ +From: Daniel Wagner +Date: Wed, 26 Jan 2022 17:46:45 +0100 +Subject: lightnvm: Remove lightnvm implemenation +Patch-mainline: Never, remove unsupported features due to bit rotting +References: bsc#1191881 bsc#1201420 ZDI-CAN-17325 + +lightnvm never really got traction and there were no hardware devices +to buy. Eventually, it was replaced by the ZNS protocol and devices. + +Commit 9ea9b9c48387 ("remove the lightnvm subsystem") removes the code +and all definitions concerning lightnvm. Unfortunatly, we can't do +this without breaking kABI. + +The code base has started to bit rot and we start getting bug reports +in the lightnvm code base (e.g. accessing sysfs triggers a crash). +Hence the best option forward is just to remove the code and let +all data structs definition in. + +Signed-off-by: Daniel Wagner +--- + drivers/nvme/host/lightnvm.c | 911 ------------------------------------------- + drivers/nvme/host/pci.c | 2 + 2 files changed, 3 insertions(+), 910 deletions(-) + +--- a/drivers/nvme/host/lightnvm.c ++++ b/drivers/nvme/host/lightnvm.c +@@ -23,1266 +23,34 @@ + #include "nvme.h" + + #include +-#include + #include +-#include +-#include + #include + +-enum nvme_nvm_admin_opcode { +- nvme_nvm_admin_identity = 0xe2, +- nvme_nvm_admin_get_bb_tbl = 0xf2, +- nvme_nvm_admin_set_bb_tbl = 0xf1, +-}; +- +-enum nvme_nvm_log_page { +- NVME_NVM_LOG_REPORT_CHUNK = 0xca, +-}; +- +-struct nvme_nvm_ph_rw { +- __u8 opcode; +- __u8 flags; +- __u16 command_id; +- __le32 nsid; +- __u64 rsvd2; +- __le64 metadata; +- __le64 prp1; +- __le64 prp2; +- __le64 spba; +- __le16 length; +- __le16 control; +- __le32 dsmgmt; +- __le64 resv; +-}; +- +-struct nvme_nvm_erase_blk { +- __u8 opcode; +- __u8 flags; +- __u16 command_id; +- __le32 nsid; +- __u64 rsvd[2]; +- __le64 prp1; +- __le64 prp2; +- __le64 spba; +- __le16 length; +- __le16 control; +- __le32 dsmgmt; +- __le64 resv; +-}; +- +-struct nvme_nvm_identity { +- __u8 opcode; +- __u8 flags; +- __u16 command_id; +- __le32 nsid; +- __u64 rsvd[2]; +- __le64 prp1; +- __le64 prp2; +- __u32 rsvd11[6]; +-}; +- +-struct nvme_nvm_getbbtbl { +- __u8 opcode; +- __u8 flags; +- __u16 command_id; +- __le32 nsid; +- __u64 rsvd[2]; +- __le64 prp1; +- __le64 prp2; +- __le64 spba; +- __u32 rsvd4[4]; +-}; +- +-struct nvme_nvm_setbbtbl { +- __u8 opcode; +- __u8 flags; +- __u16 command_id; +- __le32 nsid; +- __le64 rsvd[2]; +- __le64 prp1; +- __le64 prp2; +- __le64 spba; +- __le16 nlb; +- __u8 value; +- __u8 rsvd3; +- __u32 rsvd4[3]; +-}; +- +-struct nvme_nvm_command { +- union { +- struct nvme_common_command common; +- struct nvme_nvm_ph_rw ph_rw; +- struct nvme_nvm_erase_blk erase; +- struct nvme_nvm_identity identity; +- struct nvme_nvm_getbbtbl get_bb; +- struct nvme_nvm_setbbtbl set_bb; +- }; +-}; +- +-struct nvme_nvm_id12_grp { +- __u8 mtype; +- __u8 fmtype; +- __le16 res16; +- __u8 num_ch; +- __u8 num_lun; +- __u8 num_pln; +- __u8 rsvd1; +- __le16 num_chk; +- __le16 num_pg; +- __le16 fpg_sz; +- __le16 csecs; +- __le16 sos; +- __le16 rsvd2; +- __le32 trdt; +- __le32 trdm; +- __le32 tprt; +- __le32 tprm; +- __le32 tbet; +- __le32 tbem; +- __le32 mpos; +- __le32 mccap; +- __le16 cpar; +- __u8 reserved[906]; +-} __packed; +- +-struct nvme_nvm_id12_addrf { +- __u8 ch_offset; +- __u8 ch_len; +- __u8 lun_offset; +- __u8 lun_len; +- __u8 pln_offset; +- __u8 pln_len; +- __u8 blk_offset; +- __u8 blk_len; +- __u8 pg_offset; +- __u8 pg_len; +- __u8 sec_offset; +- __u8 sec_len; +- __u8 res[4]; +-} __packed; +- +-struct nvme_nvm_id12 { +- __u8 ver_id; +- __u8 vmnt; +- __u8 cgrps; +- __u8 res; +- __le32 cap; +- __le32 dom; +- struct nvme_nvm_id12_addrf ppaf; +- __u8 resv[228]; +- struct nvme_nvm_id12_grp grp; +- __u8 resv2[2880]; +-} __packed; +- +-struct nvme_nvm_bb_tbl { +- __u8 tblid[4]; +- __le16 verid; +- __le16 revid; +- __le32 rvsd1; +- __le32 tblks; +- __le32 tfact; +- __le32 tgrown; +- __le32 tdresv; +- __le32 thresv; +- __le32 rsvd2[8]; +- __u8 blk[0]; +-}; +- +-struct nvme_nvm_id20_addrf { +- __u8 grp_len; +- __u8 pu_len; +- __u8 chk_len; +- __u8 lba_len; +- __u8 resv[4]; +-}; +- +-struct nvme_nvm_id20 { +- __u8 mjr; +- __u8 mnr; +- __u8 resv[6]; +- +- struct nvme_nvm_id20_addrf lbaf; +- +- __le32 mccap; +- __u8 resv2[12]; +- +- __u8 wit; +- __u8 resv3[31]; +- +- /* Geometry */ +- __le16 num_grp; +- __le16 num_pu; +- __le32 num_chk; +- __le32 clba; +- __u8 resv4[52]; +- +- /* Write data requirements */ +- __le32 ws_min; +- __le32 ws_opt; +- __le32 mw_cunits; +- __le32 maxoc; +- __le32 maxocpu; +- __u8 resv5[44]; +- +- /* Performance related metrics */ +- __le32 trdt; +- __le32 trdm; +- __le32 twrt; +- __le32 twrm; +- __le32 tcrst; +- __le32 tcrsm; +- __u8 resv6[40]; +- +- /* Reserved area */ +- __u8 resv7[2816]; +- +- /* Vendor specific */ +- __u8 vs[1024]; +-}; +- +-struct nvme_nvm_chk_meta { +- __u8 state; +- __u8 type; +- __u8 wi; +- __u8 rsvd[5]; +- __le64 slba; +- __le64 cnlb; +- __le64 wp; +-}; +- +-/* +- * Check we didn't inadvertently grow the command struct +- */ +-static inline void _nvme_nvm_check_size(void) +-{ +- BUILD_BUG_ON(sizeof(struct nvme_nvm_identity) != 64); +- BUILD_BUG_ON(sizeof(struct nvme_nvm_ph_rw) != 64); +- BUILD_BUG_ON(sizeof(struct nvme_nvm_erase_blk) != 64); +- BUILD_BUG_ON(sizeof(struct nvme_nvm_getbbtbl) != 64); +- BUILD_BUG_ON(sizeof(struct nvme_nvm_setbbtbl) != 64); +- BUILD_BUG_ON(sizeof(struct nvme_nvm_id12_grp) != 960); +- BUILD_BUG_ON(sizeof(struct nvme_nvm_id12_addrf) != 16); +- BUILD_BUG_ON(sizeof(struct nvme_nvm_id12) != NVME_IDENTIFY_DATA_SIZE); +- BUILD_BUG_ON(sizeof(struct nvme_nvm_bb_tbl) != 64); +- BUILD_BUG_ON(sizeof(struct nvme_nvm_id20_addrf) != 8); +- BUILD_BUG_ON(sizeof(struct nvme_nvm_id20) != NVME_IDENTIFY_DATA_SIZE); +- BUILD_BUG_ON(sizeof(struct nvme_nvm_chk_meta) != 32); +- BUILD_BUG_ON(sizeof(struct nvme_nvm_chk_meta) != +- sizeof(struct nvm_chk_meta)); +-} +- +-static void nvme_nvm_set_addr_12(struct nvm_addrf_12 *dst, +- struct nvme_nvm_id12_addrf *src) +-{ +- dst->ch_len = src->ch_len; +- dst->lun_len = src->lun_len; +- dst->blk_len = src->blk_len; +- dst->pg_len = src->pg_len; +- dst->pln_len = src->pln_len; +- dst->sec_len = src->sec_len; +- +- dst->ch_offset = src->ch_offset; +- dst->lun_offset = src->lun_offset; +- dst->blk_offset = src->blk_offset; +- dst->pg_offset = src->pg_offset; +- dst->pln_offset = src->pln_offset; +- dst->sec_offset = src->sec_offset; +- +- dst->ch_mask = ((1ULL << dst->ch_len) - 1) << dst->ch_offset; +- dst->lun_mask = ((1ULL << dst->lun_len) - 1) << dst->lun_offset; +- dst->blk_mask = ((1ULL << dst->blk_len) - 1) << dst->blk_offset; +- dst->pg_mask = ((1ULL << dst->pg_len) - 1) << dst->pg_offset; +- dst->pln_mask = ((1ULL << dst->pln_len) - 1) << dst->pln_offset; +- dst->sec_mask = ((1ULL << dst->sec_len) - 1) << dst->sec_offset; +-} +- +-static int nvme_nvm_setup_12(struct nvme_nvm_id12 *id, +- struct nvm_geo *geo) +-{ +- struct nvme_nvm_id12_grp *src; +- int sec_per_pg, sec_per_pl, pg_per_blk; +- +- if (id->cgrps != 1) +- return -EINVAL; +- +- src = &id->grp; +- +- if (src->mtype != 0) { +- pr_err("nvm: memory type not supported\n"); +- return -EINVAL; +- } +- +- /* 1.2 spec. only reports a single version id - unfold */ +- geo->major_ver_id = id->ver_id; +- geo->minor_ver_id = 2; +- +- /* Set compacted version for upper layers */ +- geo->version = NVM_OCSSD_SPEC_12; +- +- geo->num_ch = src->num_ch; +- geo->num_lun = src->num_lun; +- geo->all_luns = geo->num_ch * geo->num_lun; +- +- geo->num_chk = le16_to_cpu(src->num_chk); +- +- geo->csecs = le16_to_cpu(src->csecs); +- geo->sos = le16_to_cpu(src->sos); +- +- pg_per_blk = le16_to_cpu(src->num_pg); +- sec_per_pg = le16_to_cpu(src->fpg_sz) / geo->csecs; +- sec_per_pl = sec_per_pg * src->num_pln; +- geo->clba = sec_per_pl * pg_per_blk; +- +- geo->all_chunks = geo->all_luns * geo->num_chk; +- geo->total_secs = geo->clba * geo->all_chunks; +- +- geo->ws_min = sec_per_pg; +- geo->ws_opt = sec_per_pg; +- geo->mw_cunits = geo->ws_opt << 3; /* default to MLC safe values */ +- +- /* Do not impose values for maximum number of open blocks as it is +- * unspecified in 1.2. Users of 1.2 must be aware of this and eventually +- * specify these values through a quirk if restrictions apply. +- */ +- geo->maxoc = geo->all_luns * geo->num_chk; +- geo->maxocpu = geo->num_chk; +- +- geo->mccap = le32_to_cpu(src->mccap); +- +- geo->trdt = le32_to_cpu(src->trdt); +- geo->trdm = le32_to_cpu(src->trdm); +- geo->tprt = le32_to_cpu(src->tprt); +- geo->tprm = le32_to_cpu(src->tprm); +- geo->tbet = le32_to_cpu(src->tbet); +- geo->tbem = le32_to_cpu(src->tbem); +- +- /* 1.2 compatibility */ +- geo->vmnt = id->vmnt; +- geo->cap = le32_to_cpu(id->cap); +- geo->dom = le32_to_cpu(id->dom); +- +- geo->mtype = src->mtype; +- geo->fmtype = src->fmtype; +- +- geo->cpar = le16_to_cpu(src->cpar); +- geo->mpos = le32_to_cpu(src->mpos); +- +- geo->pln_mode = NVM_PLANE_SINGLE; +- +- if (geo->mpos & 0x020202) { +- geo->pln_mode = NVM_PLANE_DOUBLE; +- geo->ws_opt <<= 1; +- } else if (geo->mpos & 0x040404) { +- geo->pln_mode = NVM_PLANE_QUAD; +- geo->ws_opt <<= 2; +- } +- +- geo->num_pln = src->num_pln; +- geo->num_pg = le16_to_cpu(src->num_pg); +- geo->fpg_sz = le16_to_cpu(src->fpg_sz); +- +- nvme_nvm_set_addr_12((struct nvm_addrf_12 *)&geo->addrf, &id->ppaf); +- +- return 0; +-} +- +-static void nvme_nvm_set_addr_20(struct nvm_addrf *dst, +- struct nvme_nvm_id20_addrf *src) +-{ +- dst->ch_len = src->grp_len; +- dst->lun_len = src->pu_len; +- dst->chk_len = src->chk_len; +- dst->sec_len = src->lba_len; +- +- dst->sec_offset = 0; +- dst->chk_offset = dst->sec_len; +- dst->lun_offset = dst->chk_offset + dst->chk_len; +- dst->ch_offset = dst->lun_offset + dst->lun_len; +- +- dst->ch_mask = ((1ULL << dst->ch_len) - 1) << dst->ch_offset; +- dst->lun_mask = ((1ULL << dst->lun_len) - 1) << dst->lun_offset; +- dst->chk_mask = ((1ULL << dst->chk_len) - 1) << dst->chk_offset; +- dst->sec_mask = ((1ULL << dst->sec_len) - 1) << dst->sec_offset; +-} +- +-static int nvme_nvm_setup_20(struct nvme_nvm_id20 *id, +- struct nvm_geo *geo) +-{ +- geo->major_ver_id = id->mjr; +- geo->minor_ver_id = id->mnr; +- +- /* Set compacted version for upper layers */ +- geo->version = NVM_OCSSD_SPEC_20; +- +- geo->num_ch = le16_to_cpu(id->num_grp); +- geo->num_lun = le16_to_cpu(id->num_pu); +- geo->all_luns = geo->num_ch * geo->num_lun; +- +- geo->num_chk = le32_to_cpu(id->num_chk); +- geo->clba = le32_to_cpu(id->clba); +- +- geo->all_chunks = geo->all_luns * geo->num_chk; +- geo->total_secs = geo->clba * geo->all_chunks; +- +- geo->ws_min = le32_to_cpu(id->ws_min); +- geo->ws_opt = le32_to_cpu(id->ws_opt); +- geo->mw_cunits = le32_to_cpu(id->mw_cunits); +- geo->maxoc = le32_to_cpu(id->maxoc); +- geo->maxocpu = le32_to_cpu(id->maxocpu); +- +- geo->trdt = le32_to_cpu(id->trdt); +- geo->trdm = le32_to_cpu(id->trdm); +- geo->tprt = le32_to_cpu(id->twrt); +- geo->tprm = le32_to_cpu(id->twrm); +- geo->tbet = le32_to_cpu(id->tcrst); +- geo->tbem = le32_to_cpu(id->tcrsm); +- +- nvme_nvm_set_addr_20(&geo->addrf, &id->lbaf); +- +- return 0; +-} +- +-static int nvme_nvm_identity(struct nvm_dev *nvmdev) +-{ +- struct nvme_ns *ns = nvmdev->q->queuedata; +- struct nvme_nvm_id12 *id; +- struct nvme_nvm_command c = {}; +- int ret; +- +- c.identity.opcode = nvme_nvm_admin_identity; +- c.identity.nsid = cpu_to_le32(ns->head->ns_id); +- +- id = kmalloc(sizeof(struct nvme_nvm_id12), GFP_KERNEL); +- if (!id) +- return -ENOMEM; +- +- ret = nvme_submit_sync_cmd(ns->ctrl->admin_q, (struct nvme_command *)&c, +- id, sizeof(struct nvme_nvm_id12)); +- if (ret) { +- ret = -EIO; +- goto out; +- } +- +- /* +- * The 1.2 and 2.0 specifications share the first byte in their geometry +- * command to make it possible to know what version a device implements. +- */ +- switch (id->ver_id) { +- case 1: +- ret = nvme_nvm_setup_12(id, &nvmdev->geo); +- break; +- case 2: +- ret = nvme_nvm_setup_20((struct nvme_nvm_id20 *)id, +- &nvmdev->geo); +- break; +- default: +- dev_err(ns->ctrl->device, "OCSSD revision not supported (%d)\n", +- id->ver_id); +- ret = -EINVAL; +- } +- +-out: +- kfree(id); +- return ret; +-} +- +-static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa, +- u8 *blks) +-{ +- struct request_queue *q = nvmdev->q; +- struct nvm_geo *geo = &nvmdev->geo; +- struct nvme_ns *ns = q->queuedata; +- struct nvme_ctrl *ctrl = ns->ctrl; +- struct nvme_nvm_command c = {}; +- struct nvme_nvm_bb_tbl *bb_tbl; +- int nr_blks = geo->num_chk * geo->num_pln; +- int tblsz = sizeof(struct nvme_nvm_bb_tbl) + nr_blks; +- int ret = 0; +- +- c.get_bb.opcode = nvme_nvm_admin_get_bb_tbl; +- c.get_bb.nsid = cpu_to_le32(ns->head->ns_id); +- c.get_bb.spba = cpu_to_le64(ppa.ppa); +- +- bb_tbl = kzalloc(tblsz, GFP_KERNEL); +- if (!bb_tbl) +- return -ENOMEM; +- +- ret = nvme_submit_sync_cmd(ctrl->admin_q, (struct nvme_command *)&c, +- bb_tbl, tblsz); +- if (ret) { +- dev_err(ctrl->device, "get bad block table failed (%d)\n", ret); +- ret = -EIO; +- goto out; +- } +- +- if (bb_tbl->tblid[0] != 'B' || bb_tbl->tblid[1] != 'B' || +- bb_tbl->tblid[2] != 'L' || bb_tbl->tblid[3] != 'T') { +- dev_err(ctrl->device, "bbt format mismatch\n"); +- ret = -EINVAL; +- goto out; +- } +- +- if (le16_to_cpu(bb_tbl->verid) != 1) { +- ret = -EINVAL; +- dev_err(ctrl->device, "bbt version not supported\n"); +- goto out; +- } +- +- if (le32_to_cpu(bb_tbl->tblks) != nr_blks) { +- ret = -EINVAL; +- dev_err(ctrl->device, +- "bbt unsuspected blocks returned (%u!=%u)", +- le32_to_cpu(bb_tbl->tblks), nr_blks); +- goto out; +- } +- +- memcpy(blks, bb_tbl->blk, geo->num_chk * geo->num_pln); +-out: +- kfree(bb_tbl); +- return ret; +-} +- +-static int nvme_nvm_set_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr *ppas, +- int nr_ppas, int type) +-{ +- struct nvme_ns *ns = nvmdev->q->queuedata; +- struct nvme_nvm_command c = {}; +- int ret = 0; +- +- c.set_bb.opcode = nvme_nvm_admin_set_bb_tbl; +- c.set_bb.nsid = cpu_to_le32(ns->head->ns_id); +- c.set_bb.spba = cpu_to_le64(ppas->ppa); +- c.set_bb.nlb = cpu_to_le16(nr_ppas - 1); +- c.set_bb.value = type; +- +- ret = nvme_submit_sync_cmd(ns->ctrl->admin_q, (struct nvme_command *)&c, +- NULL, 0); +- if (ret) +- dev_err(ns->ctrl->device, "set bad block table failed (%d)\n", +- ret); +- return ret; +-} +- +-/* +- * Expect the lba in device format +- */ +-static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev, +- struct nvm_chk_meta *meta, +- sector_t slba, int nchks) +-{ +- struct nvm_geo *geo = &ndev->geo; +- struct nvme_ns *ns = ndev->q->queuedata; +- struct nvme_ctrl *ctrl = ns->ctrl; +- struct nvme_nvm_chk_meta *dev_meta = (struct nvme_nvm_chk_meta *)meta; +- struct ppa_addr ppa; +- size_t left = nchks * sizeof(struct nvme_nvm_chk_meta); +- size_t log_pos, offset, len; +- int ret, i, max_len; +- +- /* +- * limit requests to maximum 256K to avoid issuing arbitrary large +- * requests when the device does not specific a maximum transfer size. +- */ +- max_len = min_t(unsigned int, ctrl->max_hw_sectors << 9, 256 * 1024); +- +- /* Normalize lba address space to obtain log offset */ +- ppa.ppa = slba; +- ppa = dev_to_generic_addr(ndev, ppa); +- +- log_pos = ppa.m.chk; +- log_pos += ppa.m.pu * geo->num_chk; +- log_pos += ppa.m.grp * geo->num_lun * geo->num_chk; +- +- offset = log_pos * sizeof(struct nvme_nvm_chk_meta); +- +- while (left) { +- len = min_t(unsigned int, left, max_len); +- +- ret = nvme_get_log(ctrl, ns->head->ns_id, +- NVME_NVM_LOG_REPORT_CHUNK, 0, dev_meta, len, +- offset); +- if (ret) { +- dev_err(ctrl->device, "Get REPORT CHUNK log error\n"); +- break; +- } +- +- for (i = 0; i < len; i += sizeof(struct nvme_nvm_chk_meta)) { +- meta->state = dev_meta->state; +- meta->type = dev_meta->type; +- meta->wi = dev_meta->wi; +- meta->slba = le64_to_cpu(dev_meta->slba); +- meta->cnlb = le64_to_cpu(dev_meta->cnlb); +- meta->wp = le64_to_cpu(dev_meta->wp); +- +- meta++; +- dev_meta++; +- } +- +- offset += len; +- left -= len; +- } +- +- return ret; +-} +- +-static inline void nvme_nvm_rqtocmd(struct nvm_rq *rqd, struct nvme_ns *ns, +- struct nvme_nvm_command *c) +-{ +- c->ph_rw.opcode = rqd->opcode; +- c->ph_rw.nsid = cpu_to_le32(ns->head->ns_id); +- c->ph_rw.spba = cpu_to_le64(rqd->ppa_addr.ppa); +- c->ph_rw.metadata = cpu_to_le64(rqd->dma_meta_list); +- c->ph_rw.control = cpu_to_le16(rqd->flags); +- c->ph_rw.length = cpu_to_le16(rqd->nr_ppas - 1); +-} +- +-static void nvme_nvm_end_io(struct request *rq, blk_status_t status) +-{ +- struct nvm_rq *rqd = rq->end_io_data; +- +- rqd->ppa_status = le64_to_cpu(nvme_req(rq)->result.u64); +- rqd->error = nvme_req(rq)->status; +- nvm_end_io(rqd); +- +- kfree(nvme_req(rq)->cmd); +- blk_mq_free_request(rq); +-} +- +-static struct request *nvme_nvm_alloc_request(struct request_queue *q, +- struct nvm_rq *rqd, +- struct nvme_nvm_command *cmd) +-{ +- struct nvme_ns *ns = q->queuedata; +- struct request *rq; +- +- nvme_nvm_rqtocmd(rqd, ns, cmd); +- +- rq = nvme_alloc_request(q, (struct nvme_command *)cmd, 0, NVME_QID_ANY); +- if (IS_ERR(rq)) +- return rq; +- +- rq->cmd_flags &= ~REQ_FAILFAST_DRIVER; +- +- if (rqd->bio) { +- blk_init_request_from_bio(rq, rqd->bio); +- } else { +- rq->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, IOPRIO_NORM); +- rq->__data_len = 0; +- } +- +- return rq; +-} +- +-static int nvme_nvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd) +-{ +- struct request_queue *q = dev->q; +- struct nvme_nvm_command *cmd; +- struct request *rq; +- +- cmd = kzalloc(sizeof(struct nvme_nvm_command), GFP_KERNEL); +- if (!cmd) +- return -ENOMEM; +- +- rq = nvme_nvm_alloc_request(q, rqd, cmd); +- if (IS_ERR(rq)) { +- kfree(cmd); +- return PTR_ERR(rq); +- } +- +- rq->end_io_data = rqd; +- +- blk_execute_rq_nowait(q, NULL, rq, 0, nvme_nvm_end_io); +- +- return 0; +-} +- +-static int nvme_nvm_submit_io_sync(struct nvm_dev *dev, struct nvm_rq *rqd) +-{ +- struct request_queue *q = dev->q; +- struct request *rq; +- struct nvme_nvm_command cmd; +- int ret = 0; +- +- memset(&cmd, 0, sizeof(struct nvme_nvm_command)); +- +- rq = nvme_nvm_alloc_request(q, rqd, &cmd); +- if (IS_ERR(rq)) +- return PTR_ERR(rq); +- +- /* I/Os can fail and the error is signaled through rqd. Callers must +- * handle the error accordingly. +- */ +- blk_execute_rq(q, NULL, rq, 0); +- if (nvme_req(rq)->flags & NVME_REQ_CANCELLED) +- ret = -EINTR; +- +- rqd->ppa_status = le64_to_cpu(nvme_req(rq)->result.u64); +- rqd->error = nvme_req(rq)->status; +- +- blk_mq_free_request(rq); +- +- return ret; +-} +- +-static void *nvme_nvm_create_dma_pool(struct nvm_dev *nvmdev, char *name) +-{ +- struct nvme_ns *ns = nvmdev->q->queuedata; +- +- return dma_pool_create(name, ns->ctrl->dev, PAGE_SIZE, PAGE_SIZE, 0); +-} +- +-static void nvme_nvm_destroy_dma_pool(void *pool) +-{ +- struct dma_pool *dma_pool = pool; +- +- dma_pool_destroy(dma_pool); +-} +- +-static void *nvme_nvm_dev_dma_alloc(struct nvm_dev *dev, void *pool, +- gfp_t mem_flags, dma_addr_t *dma_handler) +-{ +- return dma_pool_alloc(pool, mem_flags, dma_handler); +-} +- +-static void nvme_nvm_dev_dma_free(void *pool, void *addr, +- dma_addr_t dma_handler) +-{ +- dma_pool_free(pool, addr, dma_handler); +-} +- +-static struct nvm_dev_ops nvme_nvm_dev_ops = { +- .identity = nvme_nvm_identity, +- +- .get_bb_tbl = nvme_nvm_get_bb_tbl, +- .set_bb_tbl = nvme_nvm_set_bb_tbl, +- +- .get_chk_meta = nvme_nvm_get_chk_meta, +- +- .submit_io = nvme_nvm_submit_io, +- .submit_io_sync = nvme_nvm_submit_io_sync, +- +- .create_dma_pool = nvme_nvm_create_dma_pool, +- .destroy_dma_pool = nvme_nvm_destroy_dma_pool, +- .dev_dma_alloc = nvme_nvm_dev_dma_alloc, +- .dev_dma_free = nvme_nvm_dev_dma_free, +-}; +- +-static int nvme_nvm_submit_user_cmd(struct request_queue *q, +- struct nvme_ns *ns, +- struct nvme_nvm_command *vcmd, +- void __user *ubuf, unsigned int bufflen, +- void __user *meta_buf, unsigned int meta_len, +- void __user *ppa_buf, unsigned int ppa_len, +- u32 *result, u64 *status, unsigned int timeout) +-{ +- bool write = nvme_is_write((struct nvme_command *)vcmd); +- struct nvm_dev *dev = ns->ndev; +- struct gendisk *disk = ns->disk; +- struct request *rq; +- struct bio *bio = NULL; +- __le64 *ppa_list = NULL; +- dma_addr_t ppa_dma; +- __le64 *metadata = NULL; +- dma_addr_t metadata_dma; +- DECLARE_COMPLETION_ONSTACK(wait); +- int ret = 0; +- +- rq = nvme_alloc_request(q, (struct nvme_command *)vcmd, 0, +- NVME_QID_ANY); +- if (IS_ERR(rq)) { +- ret = -ENOMEM; +- goto err_cmd; +- } +- +- rq->timeout = timeout ? timeout : ADMIN_TIMEOUT; +- +- if (ppa_buf && ppa_len) { +- ppa_list = dma_pool_alloc(dev->dma_pool, GFP_KERNEL, &ppa_dma); +- if (!ppa_list) { +- ret = -ENOMEM; +- goto err_rq; +- } +- if (copy_from_user(ppa_list, (void __user *)ppa_buf, +- sizeof(u64) * (ppa_len + 1))) { +- ret = -EFAULT; +- goto err_ppa; +- } +- vcmd->ph_rw.spba = cpu_to_le64(ppa_dma); +- } else { +- vcmd->ph_rw.spba = cpu_to_le64((uintptr_t)ppa_buf); +- } +- +- if (ubuf && bufflen) { +- ret = blk_rq_map_user(q, rq, NULL, ubuf, bufflen, GFP_KERNEL); +- if (ret) +- goto err_ppa; +- bio = rq->bio; +- +- if (meta_buf && meta_len) { +- metadata = dma_pool_alloc(dev->dma_pool, GFP_KERNEL, +- &metadata_dma); +- if (!metadata) { +- ret = -ENOMEM; +- goto err_map; +- } +- +- if (write) { +- if (copy_from_user(metadata, +- (void __user *)meta_buf, +- meta_len)) { +- ret = -EFAULT; +- goto err_meta; +- } +- } +- vcmd->ph_rw.metadata = cpu_to_le64(metadata_dma); +- } +- +- bio->bi_disk = disk; +- } +- +- blk_execute_rq(q, NULL, rq, 0); +- +- if (nvme_req(rq)->flags & NVME_REQ_CANCELLED) +- ret = -EINTR; +- else if (nvme_req(rq)->status & 0x7ff) +- ret = -EIO; +- if (result) +- *result = nvme_req(rq)->status & 0x7ff; +- if (status) +- *status = le64_to_cpu(nvme_req(rq)->result.u64); +- +- if (metadata && !ret && !write) { +- if (copy_to_user(meta_buf, (void *)metadata, meta_len)) +- ret = -EFAULT; +- } +-err_meta: +- if (meta_buf && meta_len) +- dma_pool_free(dev->dma_pool, metadata, metadata_dma); +-err_map: +- if (bio) +- blk_rq_unmap_user(bio); +-err_ppa: +- if (ppa_buf && ppa_len) +- dma_pool_free(dev->dma_pool, ppa_list, ppa_dma); +-err_rq: +- blk_mq_free_request(rq); +-err_cmd: +- return ret; +-} +- +-static int nvme_nvm_submit_vio(struct nvme_ns *ns, +- struct nvm_user_vio __user *uvio) +-{ +- struct nvm_user_vio vio; +- struct nvme_nvm_command c; +- unsigned int length; +- int ret; +- +- if (copy_from_user(&vio, uvio, sizeof(vio))) +- return -EFAULT; +- if (vio.flags) +- return -EINVAL; +- +- memset(&c, 0, sizeof(c)); +- c.ph_rw.opcode = vio.opcode; +- c.ph_rw.nsid = cpu_to_le32(ns->head->ns_id); +- c.ph_rw.control = cpu_to_le16(vio.control); +- c.ph_rw.length = cpu_to_le16(vio.nppas); +- +- length = (vio.nppas + 1) << ns->lba_shift; +- +- ret = nvme_nvm_submit_user_cmd(ns->queue, ns, &c, +- (void __user *)(uintptr_t)vio.addr, length, +- (void __user *)(uintptr_t)vio.metadata, +- vio.metadata_len, +- (void __user *)(uintptr_t)vio.ppa_list, vio.nppas, +- &vio.result, &vio.status, 0); +- +- if (ret && copy_to_user(uvio, &vio, sizeof(vio))) +- return -EFAULT; +- +- return ret; +-} +- +-static int nvme_nvm_user_vcmd(struct nvme_ns *ns, int admin, +- struct nvm_passthru_vio __user *uvcmd) +-{ +- struct nvm_passthru_vio vcmd; +- struct nvme_nvm_command c; +- struct request_queue *q; +- unsigned int timeout = 0; +- int ret; +- +- if (copy_from_user(&vcmd, uvcmd, sizeof(vcmd))) +- return -EFAULT; +- if ((vcmd.opcode != 0xF2) && (!capable(CAP_SYS_ADMIN))) +- return -EACCES; +- if (vcmd.flags) +- return -EINVAL; +- +- memset(&c, 0, sizeof(c)); +- c.common.opcode = vcmd.opcode; +- c.common.nsid = cpu_to_le32(ns->head->ns_id); +- c.common.cdw2[0] = cpu_to_le32(vcmd.cdw2); +- c.common.cdw2[1] = cpu_to_le32(vcmd.cdw3); +- /* cdw11-12 */ +- c.ph_rw.length = cpu_to_le16(vcmd.nppas); +- c.ph_rw.control = cpu_to_le16(vcmd.control); +- c.common.cdw10[3] = cpu_to_le32(vcmd.cdw13); +- c.common.cdw10[4] = cpu_to_le32(vcmd.cdw14); +- c.common.cdw10[5] = cpu_to_le32(vcmd.cdw15); +- +- if (vcmd.timeout_ms) +- timeout = msecs_to_jiffies(vcmd.timeout_ms); +- +- q = admin ? ns->ctrl->admin_q : ns->queue; +- +- ret = nvme_nvm_submit_user_cmd(q, ns, +- (struct nvme_nvm_command *)&c, +- (void __user *)(uintptr_t)vcmd.addr, vcmd.data_len, +- (void __user *)(uintptr_t)vcmd.metadata, +- vcmd.metadata_len, +- (void __user *)(uintptr_t)vcmd.ppa_list, vcmd.nppas, +- &vcmd.result, &vcmd.status, timeout); +- +- if (ret && copy_to_user(uvcmd, &vcmd, sizeof(vcmd))) +- return -EFAULT; +- +- return ret; +-} +- + int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, unsigned long arg) + { +- switch (cmd) { +- case NVME_NVM_IOCTL_ADMIN_VIO: +- return nvme_nvm_user_vcmd(ns, 1, (void __user *)arg); +- case NVME_NVM_IOCTL_IO_VIO: +- return nvme_nvm_user_vcmd(ns, 0, (void __user *)arg); +- case NVME_NVM_IOCTL_SUBMIT_VIO: +- return nvme_nvm_submit_vio(ns, (void __user *)arg); +- default: +- return -ENOTTY; +- } ++ return -ENOTTY; + } + + void nvme_nvm_update_nvm_info(struct nvme_ns *ns) + { +- struct nvm_dev *ndev = ns->ndev; +- struct nvm_geo *geo = &ndev->geo; +- +- geo->csecs = 1 << ns->lba_shift; +- geo->sos = ns->ms; + } + + int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node) + { +- struct request_queue *q = ns->queue; +- struct nvm_dev *dev; +- +- _nvme_nvm_check_size(); +- +- dev = nvm_alloc_dev(node); +- if (!dev) +- return -ENOMEM; +- +- dev->q = q; +- memcpy(dev->name, disk_name, DISK_NAME_LEN); +- dev->ops = &nvme_nvm_dev_ops; +- dev->private_data = ns; +- ns->ndev = dev; +- +- return nvm_register(dev); ++ return 0; + } + + void nvme_nvm_unregister(struct nvme_ns *ns) + { +- nvm_unregister(ns->ndev); +-} +- +-static ssize_t nvm_dev_attr_show(struct device *dev, +- struct device_attribute *dattr, char *page) +-{ +- struct nvme_ns *ns = nvme_get_ns_from_dev(dev); +- struct nvm_dev *ndev = ns->ndev; +- struct nvm_geo *geo = &ndev->geo; +- struct attribute *attr; +- +- if (!ndev) +- return 0; +- +- attr = &dattr->attr; +- +- if (strcmp(attr->name, "version") == 0) { +- if (geo->major_ver_id == 1) +- return scnprintf(page, PAGE_SIZE, "%u\n", +- geo->major_ver_id); +- else +- return scnprintf(page, PAGE_SIZE, "%u.%u\n", +- geo->major_ver_id, +- geo->minor_ver_id); +- } else if (strcmp(attr->name, "capabilities") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->cap); +- } else if (strcmp(attr->name, "read_typ") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->trdt); +- } else if (strcmp(attr->name, "read_max") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->trdm); +- } else { +- return scnprintf(page, +- PAGE_SIZE, +- "Unhandled attr(%s) in `%s`\n", +- attr->name, __func__); +- } +-} +- +-static ssize_t nvm_dev_attr_show_ppaf(struct nvm_addrf_12 *ppaf, char *page) +-{ +- return scnprintf(page, PAGE_SIZE, +- "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", +- ppaf->ch_offset, ppaf->ch_len, +- ppaf->lun_offset, ppaf->lun_len, +- ppaf->pln_offset, ppaf->pln_len, +- ppaf->blk_offset, ppaf->blk_len, +- ppaf->pg_offset, ppaf->pg_len, +- ppaf->sec_offset, ppaf->sec_len); +-} +- +-static ssize_t nvm_dev_attr_show_12(struct device *dev, +- struct device_attribute *dattr, char *page) +-{ +- struct nvme_ns *ns = nvme_get_ns_from_dev(dev); +- struct nvm_dev *ndev = ns->ndev; +- struct nvm_geo *geo = &ndev->geo; +- struct attribute *attr; +- +- if (!ndev) +- return 0; +- +- attr = &dattr->attr; +- +- if (strcmp(attr->name, "vendor_opcode") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->vmnt); +- } else if (strcmp(attr->name, "device_mode") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->dom); +- /* kept for compatibility */ +- } else if (strcmp(attr->name, "media_manager") == 0) { +- return scnprintf(page, PAGE_SIZE, "%s\n", "gennvm"); +- } else if (strcmp(attr->name, "ppa_format") == 0) { +- return nvm_dev_attr_show_ppaf((void *)&geo->addrf, page); +- } else if (strcmp(attr->name, "media_type") == 0) { /* u8 */ +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->mtype); +- } else if (strcmp(attr->name, "flash_media_type") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->fmtype); +- } else if (strcmp(attr->name, "num_channels") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_ch); +- } else if (strcmp(attr->name, "num_luns") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_lun); +- } else if (strcmp(attr->name, "num_planes") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_pln); +- } else if (strcmp(attr->name, "num_blocks") == 0) { /* u16 */ +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_chk); +- } else if (strcmp(attr->name, "num_pages") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_pg); +- } else if (strcmp(attr->name, "page_size") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->fpg_sz); +- } else if (strcmp(attr->name, "hw_sector_size") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->csecs); +- } else if (strcmp(attr->name, "oob_sector_size") == 0) {/* u32 */ +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->sos); +- } else if (strcmp(attr->name, "prog_typ") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprt); +- } else if (strcmp(attr->name, "prog_max") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprm); +- } else if (strcmp(attr->name, "erase_typ") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbet); +- } else if (strcmp(attr->name, "erase_max") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbem); +- } else if (strcmp(attr->name, "multiplane_modes") == 0) { +- return scnprintf(page, PAGE_SIZE, "0x%08x\n", geo->mpos); +- } else if (strcmp(attr->name, "media_capabilities") == 0) { +- return scnprintf(page, PAGE_SIZE, "0x%08x\n", geo->mccap); +- } else if (strcmp(attr->name, "max_phys_secs") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", NVM_MAX_VLBA); +- } else { +- return scnprintf(page, PAGE_SIZE, +- "Unhandled attr(%s) in `%s`\n", +- attr->name, __func__); +- } + } + +-static ssize_t nvm_dev_attr_show_20(struct device *dev, +- struct device_attribute *dattr, char *page) +-{ +- struct nvme_ns *ns = nvme_get_ns_from_dev(dev); +- struct nvm_dev *ndev = ns->ndev; +- struct nvm_geo *geo = &ndev->geo; +- struct attribute *attr; +- +- if (!ndev) +- return 0; +- +- attr = &dattr->attr; +- +- if (strcmp(attr->name, "groups") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_ch); +- } else if (strcmp(attr->name, "punits") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_lun); +- } else if (strcmp(attr->name, "chunks") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->num_chk); +- } else if (strcmp(attr->name, "clba") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->clba); +- } else if (strcmp(attr->name, "ws_min") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->ws_min); +- } else if (strcmp(attr->name, "ws_opt") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->ws_opt); +- } else if (strcmp(attr->name, "maxoc") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->maxoc); +- } else if (strcmp(attr->name, "maxocpu") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->maxocpu); +- } else if (strcmp(attr->name, "mw_cunits") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->mw_cunits); +- } else if (strcmp(attr->name, "write_typ") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprt); +- } else if (strcmp(attr->name, "write_max") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->tprm); +- } else if (strcmp(attr->name, "reset_typ") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbet); +- } else if (strcmp(attr->name, "reset_max") == 0) { +- return scnprintf(page, PAGE_SIZE, "%u\n", geo->tbem); +- } else { +- return scnprintf(page, PAGE_SIZE, +- "Unhandled attr(%s) in `%s`\n", +- attr->name, __func__); +- } +-} +- +-#define NVM_DEV_ATTR_RO(_name) \ +- DEVICE_ATTR(_name, S_IRUGO, nvm_dev_attr_show, NULL) +-#define NVM_DEV_ATTR_12_RO(_name) \ +- DEVICE_ATTR(_name, S_IRUGO, nvm_dev_attr_show_12, NULL) +-#define NVM_DEV_ATTR_20_RO(_name) \ +- DEVICE_ATTR(_name, S_IRUGO, nvm_dev_attr_show_20, NULL) +- +-/* general attributes */ +-static NVM_DEV_ATTR_RO(version); +-static NVM_DEV_ATTR_RO(capabilities); +- +-static NVM_DEV_ATTR_RO(read_typ); +-static NVM_DEV_ATTR_RO(read_max); +- +-/* 1.2 values */ +-static NVM_DEV_ATTR_12_RO(vendor_opcode); +-static NVM_DEV_ATTR_12_RO(device_mode); +-static NVM_DEV_ATTR_12_RO(ppa_format); +-static NVM_DEV_ATTR_12_RO(media_manager); +-static NVM_DEV_ATTR_12_RO(media_type); +-static NVM_DEV_ATTR_12_RO(flash_media_type); +-static NVM_DEV_ATTR_12_RO(num_channels); +-static NVM_DEV_ATTR_12_RO(num_luns); +-static NVM_DEV_ATTR_12_RO(num_planes); +-static NVM_DEV_ATTR_12_RO(num_blocks); +-static NVM_DEV_ATTR_12_RO(num_pages); +-static NVM_DEV_ATTR_12_RO(page_size); +-static NVM_DEV_ATTR_12_RO(hw_sector_size); +-static NVM_DEV_ATTR_12_RO(oob_sector_size); +-static NVM_DEV_ATTR_12_RO(prog_typ); +-static NVM_DEV_ATTR_12_RO(prog_max); +-static NVM_DEV_ATTR_12_RO(erase_typ); +-static NVM_DEV_ATTR_12_RO(erase_max); +-static NVM_DEV_ATTR_12_RO(multiplane_modes); +-static NVM_DEV_ATTR_12_RO(media_capabilities); +-static NVM_DEV_ATTR_12_RO(max_phys_secs); +- +-/* 2.0 values */ +-static NVM_DEV_ATTR_20_RO(groups); +-static NVM_DEV_ATTR_20_RO(punits); +-static NVM_DEV_ATTR_20_RO(chunks); +-static NVM_DEV_ATTR_20_RO(clba); +-static NVM_DEV_ATTR_20_RO(ws_min); +-static NVM_DEV_ATTR_20_RO(ws_opt); +-static NVM_DEV_ATTR_20_RO(maxoc); +-static NVM_DEV_ATTR_20_RO(maxocpu); +-static NVM_DEV_ATTR_20_RO(mw_cunits); +-static NVM_DEV_ATTR_20_RO(write_typ); +-static NVM_DEV_ATTR_20_RO(write_max); +-static NVM_DEV_ATTR_20_RO(reset_typ); +-static NVM_DEV_ATTR_20_RO(reset_max); +- + static struct attribute *nvm_dev_attrs[] = { +- /* version agnostic attrs */ +- &dev_attr_version.attr, +- &dev_attr_capabilities.attr, +- &dev_attr_read_typ.attr, +- &dev_attr_read_max.attr, +- +- /* 1.2 attrs */ +- &dev_attr_vendor_opcode.attr, +- &dev_attr_device_mode.attr, +- &dev_attr_media_manager.attr, +- &dev_attr_ppa_format.attr, +- &dev_attr_media_type.attr, +- &dev_attr_flash_media_type.attr, +- &dev_attr_num_channels.attr, +- &dev_attr_num_luns.attr, +- &dev_attr_num_planes.attr, +- &dev_attr_num_blocks.attr, +- &dev_attr_num_pages.attr, +- &dev_attr_page_size.attr, +- &dev_attr_hw_sector_size.attr, +- &dev_attr_oob_sector_size.attr, +- &dev_attr_prog_typ.attr, +- &dev_attr_prog_max.attr, +- &dev_attr_erase_typ.attr, +- &dev_attr_erase_max.attr, +- &dev_attr_multiplane_modes.attr, +- &dev_attr_media_capabilities.attr, +- &dev_attr_max_phys_secs.attr, +- +- /* 2.0 attrs */ +- &dev_attr_groups.attr, +- &dev_attr_punits.attr, +- &dev_attr_chunks.attr, +- &dev_attr_clba.attr, +- &dev_attr_ws_min.attr, +- &dev_attr_ws_opt.attr, +- &dev_attr_maxoc.attr, +- &dev_attr_maxocpu.attr, +- &dev_attr_mw_cunits.attr, +- +- &dev_attr_write_typ.attr, +- &dev_attr_write_max.attr, +- &dev_attr_reset_typ.attr, +- &dev_attr_reset_max.attr, +- + NULL, + }; + + static umode_t nvm_dev_attrs_visible(struct kobject *kobj, + struct attribute *attr, int index) + { +- struct device *dev = container_of(kobj, struct device, kobj); +- struct gendisk *disk = dev_to_disk(dev); +- struct nvme_ns *ns = disk->private_data; +- struct nvm_dev *ndev = ns->ndev; +- struct device_attribute *dev_attr = +- container_of(attr, typeof(*dev_attr), attr); +- +- if (!ndev) +- return 0; +- +- if (dev_attr->show == nvm_dev_attr_show) +- return attr->mode; +- +- switch (ndev->geo.major_ver_id) { +- case 1: +- if (dev_attr->show == nvm_dev_attr_show_12) +- return attr->mode; +- break; +- case 2: +- if (dev_attr->show == nvm_dev_attr_show_20) +- return attr->mode; +- break; +- } +- + return 0; + } + +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -2703,8 +2703,6 @@ static const struct pci_device_id nvme_i + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE(0x144d, 0xa822), /* Samsung PM1725a */ + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, +- { PCI_DEVICE(0x1d1d, 0x1f1f), /* LighNVM qemu device */ +- .driver_data = NVME_QUIRK_LIGHTNVM, }, + { PCI_DEVICE(0x1d1d, 0x2807), /* CNEX WL */ + .driver_data = NVME_QUIRK_LIGHTNVM, }, + { PCI_DEVICE(0x1d1d, 0x2601), /* CNEX Granby */ diff --git a/patches.suse/mm-Force-TLB-flush-for-PFNMAP-mappings-before-unlink_file_vma.patch b/patches.suse/mm-Force-TLB-flush-for-PFNMAP-mappings-before-unlink_file_vma.patch new file mode 100644 index 0000000..b292a7c --- /dev/null +++ b/patches.suse/mm-Force-TLB-flush-for-PFNMAP-mappings-before-unlink_file_vma.patch @@ -0,0 +1,54 @@ +From: Jann Horn +Date: Wed, 31 Aug 2022 21:13:48 +0200 +Subject: mm: Force TLB flush for PFNMAP mappings before unlink_file_vma() +Git-commit: b67fbebd4cf980aecbcc750e1462128bffe8ae15 +Patch-mainline: v5.19-rc8 +References: CVE-2022-39188, bsc#1203107 + +commit b67fbebd4cf980aecbcc750e1462128bffe8ae15 upstream. + +Some drivers rely on having all VMAs through which a PFN might be +accessible listed in the rmap for correctness. +However, on X86, it was possible for a VMA with stale TLB entries +to not be listed in the rmap. + +This was fixed in mainline with +commit b67fbebd4cf9 ("mmu_gather: Force tlb-flush VM_PFNMAP vmas"), +but that commit relies on preceding refactoring in +commit 18ba064e42df3 ("mmu_gather: Let there be one tlb_{start,end}_vma() +implementation") and commit 1e9fdf21a4339 ("mmu_gather: Remove per arch +tlb_{start,end}_vma()"). + +This patch provides equivalent protection without needing that +refactoring, by forcing a TLB flush between removing PTEs in +unmap_vmas() and the call to unlink_file_vma() in free_pgtables(). + +[This is a stable-specific rewrite of the upstream commit!] +Signed-off-by: Jann Horn +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Vlastimil Babka +--- + mm/mmap.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -2545,6 +2545,18 @@ static void unmap_region(struct mm_struc + tlb_gather_mmu(&tlb, mm, start, end); + update_hiwater_rss(mm); + unmap_vmas(&tlb, vma, start, end); ++ ++ /* ++ * Ensure we have no stale TLB entries by the time this mapping is ++ * removed from the rmap. ++ * Note that we don't have to worry about nested flushes here because ++ * we're holding the mm semaphore for removing the mapping - so any ++ * concurrent flush in this region has to be coming through the rmap, ++ * and we synchronize against that using the rmap lock. ++ */ ++ if ((vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP)) != 0) ++ tlb_flush_mmu(&tlb); ++ + free_pgtables(&tlb, vma, prev ? prev->vm_end : FIRST_USER_ADDRESS, + next ? next->vm_start : USER_PGTABLES_CEILING); + tlb_finish_mmu(&tlb, start, end); diff --git a/patches.suse/mm-rmap-Fix-anon_vma-degree-ambiguity-leading-to-double-reuse.patch b/patches.suse/mm-rmap-Fix-anon_vma-degree-ambiguity-leading-to-double-reuse.patch new file mode 100644 index 0000000..18e1180 --- /dev/null +++ b/patches.suse/mm-rmap-Fix-anon_vma-degree-ambiguity-leading-to-double-reuse.patch @@ -0,0 +1,164 @@ +From: Jann Horn +Date: Wed, 31 Aug 2022 19:06:00 +0200 +Subject: mm/rmap: Fix anon_vma->degree ambiguity leading to double-reuse +Git-commit: 2555283eb40df89945557273121e9393ef9b542b +Patch-mainline: v6.0-rc4 +References: git-fixes, bsc#1203098 + +anon_vma->degree tracks the combined number of child anon_vmas and VMAs +that use the anon_vma as their ->anon_vma. + +anon_vma_clone() then assumes that for any anon_vma attached to +src->anon_vma_chain other than src->anon_vma, it is impossible for it to +be a leaf node of the VMA tree, meaning that for such VMAs ->degree is +elevated by 1 because of a child anon_vma, meaning that if ->degree +equals 1 there are no VMAs that use the anon_vma as their ->anon_vma. + +This assumption is wrong because the ->degree optimization leads to leaf +nodes being abandoned on anon_vma_clone() - an existing anon_vma is +reused and no new parent-child relationship is created. So it is +possible to reuse an anon_vma for one VMA while it is still tied to +another VMA. + +This is an issue because is_mergeable_anon_vma() and its callers assume +that if two VMAs have the same ->anon_vma, the list of anon_vmas +attached to the VMAs is guaranteed to be the same. When this assumption +is violated, vma_merge() can merge pages into a VMA that is not attached +to the corresponding anon_vma, leading to dangling page->mapping +pointers that will be dereferenced during rmap walks. + +Fix it by separately tracking the number of child anon_vmas and the +number of VMAs using the anon_vma as their ->anon_vma. + +Fixes: 7a3ef208e662 ("mm: prevent endless growth of anon_vma hierarchy") +Cc: stable@kernel.org +Acked-by: Michal Hocko +Acked-by: Vlastimil Babka +Signed-off-by: Jann Horn +Signed-off-by: Linus Torvalds +--- + include/linux/rmap.h | 7 +++++-- + mm/rmap.c | 29 ++++++++++++++++------------- + 2 files changed, 21 insertions(+), 15 deletions(-) + +--- a/include/linux/rmap.h ++++ b/include/linux/rmap.h +@@ -38,12 +38,15 @@ struct anon_vma { + atomic_t refcount; + + /* +- * Count of child anon_vmas and VMAs which points to this anon_vma. ++ * Count of child anon_vmas. Equals to the count of all anon_vmas that ++ * have ->parent pointing to this one, including itself. + * + * This counter is used for making decision about reusing anon_vma + * instead of forking new one. See comments in function anon_vma_clone. + */ +- unsigned degree; ++ unsigned long num_children; ++ /* Count of VMAs whose ->anon_vma pointer points to this object. */ ++ unsigned long num_active_vmas; + + struct anon_vma *parent; /* Parent of this anon_vma */ + +--- a/mm/rmap.c ++++ b/mm/rmap.c +@@ -82,7 +82,8 @@ static inline struct anon_vma *anon_vma_ + anon_vma = kmem_cache_alloc(anon_vma_cachep, GFP_KERNEL); + if (anon_vma) { + atomic_set(&anon_vma->refcount, 1); +- anon_vma->degree = 1; /* Reference for first vma */ ++ anon_vma->num_children = 0; ++ anon_vma->num_active_vmas = 0; + anon_vma->parent = anon_vma; + /* + * Initialise the anon_vma root to point to itself. If called +@@ -190,6 +191,7 @@ int __anon_vma_prepare(struct vm_area_st + anon_vma = anon_vma_alloc(); + if (unlikely(!anon_vma)) + goto out_enomem_free_avc; ++ anon_vma->num_children++; /* self-parent link for new root */ + allocated = anon_vma; + } + +@@ -199,8 +201,7 @@ int __anon_vma_prepare(struct vm_area_st + if (likely(!vma->anon_vma)) { + vma->anon_vma = anon_vma; + anon_vma_chain_link(vma, avc, anon_vma); +- /* vma reference or self-parent link for new root */ +- anon_vma->degree++; ++ anon_vma->num_active_vmas++; + allocated = NULL; + avc = NULL; + } +@@ -285,19 +286,19 @@ int anon_vma_clone(struct vm_area_struct + anon_vma_chain_link(dst, avc, anon_vma); + + /* +- * Reuse existing anon_vma if its degree lower than two, +- * that means it has no vma and only one anon_vma child. ++ * Reuse existing anon_vma if it has no vma and only one ++ * anon_vma child. + * +- * Do not chose parent anon_vma, otherwise first child +- * will always reuse it. Root anon_vma is never reused: ++ * Root anon_vma is never reused: + * it has self-parent reference and at least one child. + */ + if (!dst->anon_vma && src->anon_vma && +- anon_vma != src->anon_vma && anon_vma->degree < 2) ++ anon_vma->num_children < 2 && ++ anon_vma->num_active_vmas == 0) + dst->anon_vma = anon_vma; + } + if (dst->anon_vma) +- dst->anon_vma->degree++; ++ dst->anon_vma->num_active_vmas++; + unlock_anon_vma_root(root); + return 0; + +@@ -347,6 +348,7 @@ int anon_vma_fork(struct vm_area_struct + anon_vma = anon_vma_alloc(); + if (!anon_vma) + goto out_error; ++ anon_vma->num_active_vmas++; + avc = anon_vma_chain_alloc(GFP_KERNEL); + if (!avc) + goto out_error_free_anon_vma; +@@ -367,7 +369,7 @@ int anon_vma_fork(struct vm_area_struct + vma->anon_vma = anon_vma; + anon_vma_lock_write(anon_vma); + anon_vma_chain_link(vma, avc, anon_vma); +- anon_vma->parent->degree++; ++ anon_vma->parent->num_children++; + anon_vma_unlock_write(anon_vma); + + return 0; +@@ -399,7 +401,7 @@ void unlink_anon_vmas(struct vm_area_str + * to free them outside the lock. + */ + if (RB_EMPTY_ROOT(&anon_vma->rb_root)) { +- anon_vma->parent->degree--; ++ anon_vma->parent->num_children--; + continue; + } + +@@ -407,7 +409,7 @@ void unlink_anon_vmas(struct vm_area_str + anon_vma_chain_free(avc); + } + if (vma->anon_vma) +- vma->anon_vma->degree--; ++ vma->anon_vma->num_active_vmas--; + unlock_anon_vma_root(root); + + /* +@@ -418,7 +420,8 @@ void unlink_anon_vmas(struct vm_area_str + list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) { + struct anon_vma *anon_vma = avc->anon_vma; + +- VM_WARN_ON(anon_vma->degree); ++ VM_WARN_ON(anon_vma->num_children); ++ VM_WARN_ON(anon_vma->num_active_vmas); + put_anon_vma(anon_vma); + + list_del(&avc->same_vma); diff --git a/patches.suse/mm-rmap.c-don-t-reuse-anon_vma-if-we-just-want-a-copy.patch b/patches.suse/mm-rmap.c-don-t-reuse-anon_vma-if-we-just-want-a-copy.patch index d5d17e8..39315bd 100644 --- a/patches.suse/mm-rmap.c-don-t-reuse-anon_vma-if-we-just-want-a-copy.patch +++ b/patches.suse/mm-rmap.c-don-t-reuse-anon_vma-if-we-just-want-a-copy.patch @@ -6,7 +6,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -References: git fixes (mm/rmap) +References: git-fixes, bsc#1203098 Patch-mainline: v5.5 Git-commit: 47b390d23bf81894395c8773acf6f73c66465dc4 diff --git a/patches.suse/net-rds-fix-warn-in-rds_message_alloc_sgs.patch b/patches.suse/net-rds-fix-warn-in-rds_message_alloc_sgs.patch index c271ee9..1d320b7 100644 --- a/patches.suse/net-rds-fix-warn-in-rds_message_alloc_sgs.patch +++ b/patches.suse/net-rds-fix-warn-in-rds_message_alloc_sgs.patch @@ -4,7 +4,7 @@ Date: Sun, 16 Dec 2018 09:01:08 +0200 Subject: [PATCH] net/rds: fix warn in rds_message_alloc_sgs Git-commit: ea010070d0a7497253d5a6f919f6dd107450b31a Patch-mainline: v4.20 -References: bsc#1154848 +References: CVE-2022-21385 bsc#1202897 bsc#1154848 [ Needed to modify a few code to adapt the changes without backport of zerocopy support; especially rds_rm_size() is extended with keeping diff --git a/patches.suse/net-rds-remove-user-triggered-WARN_ON-in-rds_sendmsg.patch b/patches.suse/net-rds-remove-user-triggered-WARN_ON-in-rds_sendmsg.patch index 1f0171c..2412496 100644 --- a/patches.suse/net-rds-remove-user-triggered-WARN_ON-in-rds_sendmsg.patch +++ b/patches.suse/net-rds-remove-user-triggered-WARN_ON-in-rds_sendmsg.patch @@ -4,7 +4,7 @@ Date: Sun, 16 Dec 2018 09:01:09 +0200 Subject: [PATCH] net/rds: remove user triggered WARN_ON in rds_sendmsg Git-commit: c75ab8a55ac1083c232e4407f52b0cadae6c1e0e Patch-mainline: v4.20 -References: bsc#1154848 +References: CVE-2022-21385 bsc#1202897 bsc#1154848 [ Slightly modified for adaping the downstream changes -- tiwai ] diff --git a/patches.suse/net_sched-cls_route-disallow-handle-of-0.patch b/patches.suse/net_sched-cls_route-disallow-handle-of-0.patch new file mode 100644 index 0000000..730c4ec --- /dev/null +++ b/patches.suse/net_sched-cls_route-disallow-handle-of-0.patch @@ -0,0 +1,85 @@ +From: Jamal Hadi Salim +Date: Sun, 14 Aug 2022 11:27:58 +0000 +Subject: net_sched: cls_route: disallow handle of 0 +Patch-mainline: v6.0-rc2 +Git-commit: 02799571714dc5dd6948824b9d080b44a295f695 +References: bsc#1202393 + +Follows up on: +https://lore.kernel.org/all/20220809170518.164662-1-cascardo@canonical.com/ + +handle of 0 implies from/to of universe realm which is not very +sensible. + +Lets see what this patch will do: +$sudo tc qdisc add dev $DEV root handle 1:0 prio + +//lets manufacture a way to insert handle of 0 +$sudo tc filter add dev $DEV parent 1:0 protocol ip prio 100 \ +route to 0 from 0 classid 1:10 action ok + +//gets rejected... +Error: handle of 0 is not valid. +We have an error talking to the kernel, -1 + +//lets create a legit entry.. +sudo tc filter add dev $DEV parent 1:0 protocol ip prio 100 route from 10 \ +classid 1:10 action ok + +//what did the kernel insert? +$sudo tc filter ls dev $DEV parent 1:0 +filter protocol ip pref 100 route chain 0 +filter protocol ip pref 100 route chain 0 fh 0x000a8000 flowid 1:10 from 10 + action order 1: gact action pass + random type none pass val 0 + index 1 ref 1 bind 1 + +//Lets try to replace that legit entry with a handle of 0 +$ sudo tc filter replace dev $DEV parent 1:0 protocol ip prio 100 \ +handle 0x000a8000 route to 0 from 0 classid 1:10 action drop + +Error: Replacing with handle of 0 is invalid. +We have an error talking to the kernel, -1 + +And last, lets run Cascardo's POC: +$ ./poc +0 +0 +-22 +-22 +-22 + +Signed-off-by: Jamal Hadi Salim +Acked-by: Stephen Hemminger +Signed-off-by: David S. Miller +Acked-by: Michal Kubecek + +SLE15-LTSS / SLE12-SP4-LTSS: as extack is not passed to route4_set_parms() +and route4_change(), omit setting the error message and just bail out. + +--- + net/sched/cls_route.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/net/sched/cls_route.c ++++ b/net/sched/cls_route.c +@@ -427,6 +427,9 @@ static int route4_set_parms(struct net * + return -EINVAL; + } + ++ if (!nhandle) ++ return -EINVAL; ++ + h1 = to_hash(nhandle); + b = rtnl_dereference(head->table[h1]); + if (!b) { +@@ -472,6 +475,9 @@ static int route4_change(struct net *net, struct sk_buff *in_skb, + int err; + bool new = true; + ++ if (!handle) ++ return -EINVAL; ++ + if (opt == NULL) + return handle ? -EINVAL : 0; + diff --git a/patches.suse/net_sched-cls_route-remove-from-list-when-handle-is-.patch b/patches.suse/net_sched-cls_route-remove-from-list-when-handle-is-.patch new file mode 100644 index 0000000..34a5e7d --- /dev/null +++ b/patches.suse/net_sched-cls_route-remove-from-list-when-handle-is-.patch @@ -0,0 +1,44 @@ +From: Thadeu Lima de Souza Cascardo +Date: Tue, 9 Aug 2022 14:05:18 -0300 +Subject: net_sched: cls_route: remove from list when handle is 0 +Patch-mainline: v6.0-rc1 +Git-commit: 9ad36309e2719a884f946678e0296be10f0bb4c1 +References: CVE-2022-2588 bsc#1202096 + +When a route filter is replaced and the old filter has a 0 handle, the old +one won't be removed from the hashtable, while it will still be freed. + +The test was there since before commit 1109c00547fc ("net: sched: RCU +cls_route"), when a new filter was not allocated when there was an old one. +The old filter was reused and the reinserting would only be necessary if an +old filter was replaced. That was still wrong for the same case where the +old handle was 0. + +Remove the old filter from the list independently from its handle value. + +This fixes CVE-2022-2588, also reported as ZDI-CAN-17440. + +Reported-by: Zhenpeng Lin +Signed-off-by: Thadeu Lima de Souza Cascardo +Reviewed-by: Kamal Mostafa +Cc: +Acked-by: Jamal Hadi Salim +Link: https://lore.kernel.org/r/20220809170518.164662-1-cascardo@canonical.com +Signed-off-by: Jakub Kicinski +Acked-by: Michal Kubecek + +--- + net/sched/cls_route.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/sched/cls_route.c ++++ b/net/sched/cls_route.c +@@ -528,7 +528,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb, + rcu_assign_pointer(f->next, f1); + rcu_assign_pointer(*fp, f); + +- if (fold && fold->handle && f->handle != fold->handle) { ++ if (fold) { + th = to_hash(fold->handle); + h = from_hash(fold->handle >> 16); + b = rtnl_dereference(head->table[th]); diff --git a/patches.suse/netfilter-nf_conntrack_irc-Fix-forged-IP-logic.patch b/patches.suse/netfilter-nf_conntrack_irc-Fix-forged-IP-logic.patch new file mode 100644 index 0000000..5337253 --- /dev/null +++ b/patches.suse/netfilter-nf_conntrack_irc-Fix-forged-IP-logic.patch @@ -0,0 +1,38 @@ +From: David Leadbeater +Date: Fri, 26 Aug 2022 14:56:58 +1000 +Subject: netfilter: nf_conntrack_irc: Fix forged IP logic +Patch-mainline: Queued in subsystem maintainer repository +Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git +Git-commit: 0efe125cfb99e6773a7434f3463f7c2fa28f3a43 +References: CVE-2022-2663 bsc#1202097 + +Ensure the match happens in the right direction, previously the +destination used was the server, not the NAT host, as the comment +shows the code intended. + +Additionally nf_nat_irc uses port 0 as a signal and there's no valid way +it can appear in a DCC message, so consider port 0 also forged. + +Fixes: 869f37d8e48f ("[NETFILTER]: nf_conntrack/nf_nat: add IRC helper port") +Signed-off-by: David Leadbeater +Signed-off-by: Pablo Neira Ayuso +Acked-by: Michal Kubecek + +--- + net/netfilter/nf_conntrack_irc.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/net/netfilter/nf_conntrack_irc.c ++++ b/net/netfilter/nf_conntrack_irc.c +@@ -187,8 +187,9 @@ static int help(struct sk_buff *skb, unsigned int protoff, + + /* dcc_ip can be the internal OR external (NAT'ed) IP */ + tuple = &ct->tuplehash[dir].tuple; +- if (tuple->src.u3.ip != dcc_ip && +- tuple->dst.u3.ip != dcc_ip) { ++ if ((tuple->src.u3.ip != dcc_ip && ++ ct->tuplehash[!dir].tuple.dst.u3.ip != dcc_ip) || ++ dcc_port == 0) { + net_warn_ratelimited("Forged DCC command from %pI4: %pI4:%u\n", + &tuple->src.u3.ip, + &dcc_ip, dcc_port); diff --git a/patches.suse/netfilter-nf_conntrack_irc-Tighten-matching-on-DCC-m.patch b/patches.suse/netfilter-nf_conntrack_irc-Tighten-matching-on-DCC-m.patch new file mode 100644 index 0000000..664ca35 --- /dev/null +++ b/patches.suse/netfilter-nf_conntrack_irc-Tighten-matching-on-DCC-m.patch @@ -0,0 +1,70 @@ +From: David Leadbeater +Date: Fri, 26 Aug 2022 14:56:57 +1000 +Subject: netfilter: nf_conntrack_irc: Tighten matching on DCC message +Patch-mainline: Submitted - 2022-08-26 - 20220826045658.100360-1-dgl@dgl.cx +References: CVE-2022-2663 bsc#1202097 + +CTCP messages should only be at the start of an IRC message, not +anywhere within it. + +Fixes: 869f37d8e48f ("[NETFILTER]: nf_conntrack/nf_nat: add IRC helper port") +Signed-off-by: David Leadbeater +Acked-by: Michal Kubecek +--- + net/netfilter/nf_conntrack_irc.c | 34 ++++++++++++++++++++++++++------ + 1 file changed, 28 insertions(+), 6 deletions(-) + +--- a/net/netfilter/nf_conntrack_irc.c ++++ b/net/netfilter/nf_conntrack_irc.c +@@ -150,15 +150,37 @@ static int help(struct sk_buff *skb, unsigned int protoff, + data = ib_ptr; + data_limit = ib_ptr + skb->len - dataoff; + +- /* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24 +- * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */ +- while (data < data_limit - (19 + MINMATCHLEN)) { +- if (memcmp(data, "\1DCC ", 5)) { ++ /* Skip any whitespace */ ++ while (data < data_limit - 10) { ++ if (*data == ' ' || *data == '\r' || *data == '\n') ++ data++; ++ else ++ break; ++ } ++ ++ /* strlen("PRIVMSG x ")=10 */ ++ if (data < data_limit - 10) { ++ if (strncasecmp("PRIVMSG ", data, 8)) ++ goto out; ++ data += 8; ++ } ++ ++ /* strlen(" :\1DCC SENT t AAAAAAAA P\1\n")=26 ++ * 7+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=26 ++ */ ++ while (data < data_limit - (21 + MINMATCHLEN)) { ++ /* Find first " :", the start of message */ ++ if (memcmp(data, " :", 2)) { + data++; + continue; + } ++ data += 2; ++ ++ /* then check that place only for the DCC command */ ++ if (memcmp(data, "\1DCC ", 5)) ++ goto out; + data += 5; +- /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ ++ /* we have at least (21+MINMATCHLEN)-(2+5) bytes valid data left */ + + iph = ip_hdr(skb); + pr_debug("DCC found in master %pI4:%u %pI4:%u\n", +@@ -174,7 +196,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, + pr_debug("DCC %s detected\n", dccprotos[i]); + + /* we have at least +- * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid ++ * (21+MINMATCHLEN)-7-dccprotos[i].matchlen bytes valid + * data left (== 14/13 bytes) */ + if (parse_dcc(data, data_limit, &dcc_ip, + &dcc_port, &addr_beg_p, &addr_end_p)) { diff --git a/patches.suse/objtool-Add-backtrace-support.patch b/patches.suse/objtool-Add-backtrace-support.patch new file mode 100644 index 0000000..7b0c9f4 --- /dev/null +++ b/patches.suse/objtool-Add-backtrace-support.patch @@ -0,0 +1,166 @@ +From: Peter Zijlstra +Date: Fri, 1 Mar 2019 11:15:49 +0100 +Subject: objtool: Add --backtrace support +Git-commit: 7697eee3ddd768a1fd78c1e687afaa6c5aa5072d +Patch-mainline: v5.2-rc1 +References: bsc#1202396 + +For when you want to know the path that reached your fail state: + + $ ./objtool check --no-fp --backtrace arch/x86/lib/usercopy_64.o + arch/x86/lib/usercopy_64.o: warning: objtool: .altinstr_replacement+0x3: UACCESS disable without MEMOPs: __clear_user() + arch/x86/lib/usercopy_64.o: warning: objtool: __clear_user()+0x3a: (alt) + arch/x86/lib/usercopy_64.o: warning: objtool: __clear_user()+0x2e: (branch) + arch/x86/lib/usercopy_64.o: warning: objtool: __clear_user()+0x18: (branch) + arch/x86/lib/usercopy_64.o: warning: objtool: .altinstr_replacement+0xffffffffffffffff: (branch) + arch/x86/lib/usercopy_64.o: warning: objtool: __clear_user()+0x5: (alt) + arch/x86/lib/usercopy_64.o: warning: objtool: __clear_user()+0x0: <=== (func) + + 0000000000000000 <__clear_user>: + 0: e8 00 00 00 00 callq 5 <__clear_user+0x5> + 1: R_X86_64_PLT32 __fentry__-0x4 + 5: 90 nop + 6: 90 nop + 7: 90 nop + 8: 48 89 f0 mov %rsi,%rax + b: 48 c1 ee 03 shr $0x3,%rsi + f: 83 e0 07 and $0x7,%eax + 12: 48 89 f1 mov %rsi,%rcx + 15: 48 85 c9 test %rcx,%rcx + 18: 74 0f je 29 <__clear_user+0x29> + 1a: 48 c7 07 00 00 00 00 movq $0x0,(%rdi) + 21: 48 83 c7 08 add $0x8,%rdi + 25: ff c9 dec %ecx + 27: 75 f1 jne 1a <__clear_user+0x1a> + 29: 48 89 c1 mov %rax,%rcx + 2c: 85 c9 test %ecx,%ecx + 2e: 74 0a je 3a <__clear_user+0x3a> + 30: c6 07 00 movb $0x0,(%rdi) + 33: 48 ff c7 inc %rdi + 36: ff c9 dec %ecx + 38: 75 f6 jne 30 <__clear_user+0x30> + 3a: 90 nop + 3b: 90 nop + 3c: 90 nop + 3d: 48 89 c8 mov %rcx,%rax + 40: c3 retq + +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Josh Poimboeuf +Cc: Borislav Petkov +Cc: Linus Torvalds +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Signed-off-by: Ingo Molnar +Acked-by: Miroslav Benes +--- + tools/objtool/builtin-check.c | 3 ++- + tools/objtool/builtin.h | 2 +- + tools/objtool/check.c | 18 ++++++++++++++---- + tools/objtool/warn.h | 8 ++++++++ + 4 files changed, 25 insertions(+), 6 deletions(-) + +diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c +index 694abc628e9b..99f10c585cbe 100644 +--- a/tools/objtool/builtin-check.c ++++ b/tools/objtool/builtin-check.c +@@ -29,7 +29,7 @@ + #include "builtin.h" + #include "check.h" + +-bool no_fp, no_unreachable, retpoline, module; ++bool no_fp, no_unreachable, retpoline, module, backtrace; + + static const char * const check_usage[] = { + "objtool check [] file.o", +@@ -41,6 +41,7 @@ const struct option check_options[] = { + OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"), + OPT_BOOLEAN('r', "retpoline", &retpoline, "Validate retpoline assumptions"), + OPT_BOOLEAN('m', "module", &module, "Indicates the object will be part of a kernel module"), ++ OPT_BOOLEAN('b', "backtrace", &backtrace, "unwind on error"), + OPT_END(), + }; + +diff --git a/tools/objtool/builtin.h b/tools/objtool/builtin.h +index 28ff40e19a14..65fd3cc3c98b 100644 +--- a/tools/objtool/builtin.h ++++ b/tools/objtool/builtin.h +@@ -20,7 +20,7 @@ + #include + + extern const struct option check_options[]; +-extern bool no_fp, no_unreachable, retpoline, module; ++extern bool no_fp, no_unreachable, retpoline, module, backtrace; + + extern int cmd_check(int argc, const char **argv); + extern int cmd_orc(int argc, const char **argv); +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index 8d8191f25381..ccc66af5907f 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -1885,8 +1885,11 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, + if (!insn->ignore_alts) { + list_for_each_entry(alt, &insn->alts, list) { + ret = validate_branch(file, alt->insn, state); +- if (ret) +- return 1; ++ if (ret) { ++ if (backtrace) ++ BT_FUNC("(alt)", insn); ++ return ret; ++ } + } + } + +@@ -1933,8 +1936,11 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, + insn->jump_dest->func->pfunc == func)) { + ret = validate_branch(file, insn->jump_dest, + state); +- if (ret) +- return 1; ++ if (ret) { ++ if (backtrace) ++ BT_FUNC("(branch)", insn); ++ return ret; ++ } + + } else if (func && has_modified_stack_frame(&state)) { + WARN_FUNC("sibling call from callable instruction with modified stack frame", +@@ -2005,6 +2011,8 @@ static int validate_unwind_hints(struct objtool_file *file) + for_each_insn(file, insn) { + if (insn->hint && !insn->visited) { + ret = validate_branch(file, insn, state); ++ if (ret && backtrace) ++ BT_FUNC("<=== (hint)", insn); + warnings += ret; + } + } +@@ -2133,6 +2141,8 @@ static int validate_functions(struct objtool_file *file) + continue; + + ret = validate_branch(file, insn, state); ++ if (ret && backtrace) ++ BT_FUNC("<=== (func)", insn); + warnings += ret; + } + } +diff --git a/tools/objtool/warn.h b/tools/objtool/warn.h +index afd9f7a05f6d..f4fbb972b611 100644 +--- a/tools/objtool/warn.h ++++ b/tools/objtool/warn.h +@@ -64,6 +64,14 @@ static inline char *offstr(struct section *sec, unsigned long offset) + free(_str); \ + }) + ++#define BT_FUNC(format, insn, ...) \ ++({ \ ++ struct instruction *_insn = (insn); \ ++ char *_str = offstr(_insn->sec, _insn->offset); \ ++ WARN(" %s: " format, _str, ##__VA_ARGS__); \ ++ free(_str); \ ++}) ++ + #define WARN_ELF(format, ...) \ + WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) + + diff --git a/patches.suse/objtool-Add-support-for-intra-function-calls.patch b/patches.suse/objtool-Add-support-for-intra-function-calls.patch new file mode 100644 index 0000000..73db894 --- /dev/null +++ b/patches.suse/objtool-Add-support-for-intra-function-calls.patch @@ -0,0 +1,199 @@ +From: Alexandre Chartre +Date: Tue, 14 Apr 2020 12:36:12 +0200 +Subject: objtool: Add support for intra-function calls +Git-commit: 8aa8eb2a8f5b3305a95f39957dd2b715fa668e21 +Patch-mainline: v5.8-rc1 +References: bsc#1202396 + +Change objtool to support intra-function calls. On x86, an intra-function +call is represented in objtool as a push onto the stack (of the return +address), and a jump to the destination address. That way the stack +information is correctly updated and the call flow is still accurate. + +Signed-off-by: Alexandre Chartre +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Miroslav Benes +Acked-by: Josh Poimboeuf +Link: https://lkml.kernel.org/r/20200414103618.12657-4-alexandre.chartre@oracle.com + +Acked-by: Miroslav Benes +--- + include/linux/frame.h | 11 +++ + tools/objtool/Documentation/stack-validation.txt | 8 ++ + tools/objtool/arch/x86/decode.c | 8 ++ + tools/objtool/check.c | 79 +++++++++++++++++++++-- + 4 files changed, 102 insertions(+), 4 deletions(-) + +--- a/include/linux/frame.h ++++ b/include/linux/frame.h +@@ -14,9 +14,20 @@ + static void __used __section(.discard.func_stack_frame_non_standard) \ + *__func_stack_frame_non_standard_##func = func + ++/* ++ * This macro indicates that the following intra-function call is valid. ++ * Any non-annotated intra-function call will cause objtool to issue a warning. ++ */ ++#define ANNOTATE_INTRA_FUNCTION_CALL \ ++ 999: \ ++ .pushsection .discard.intra_function_calls; \ ++ .long 999b; \ ++ .popsection; ++ + #else /* !CONFIG_STACK_VALIDATION */ + + #define STACK_FRAME_NON_STANDARD(func) ++#define ANNOTATE_INTRA_FUNCTION_CALL + + #endif /* CONFIG_STACK_VALIDATION */ + +--- a/tools/objtool/Documentation/stack-validation.txt ++++ b/tools/objtool/Documentation/stack-validation.txt +@@ -290,6 +290,14 @@ they mean, and suggestions for how to fi + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70646 + + ++11. file.o: warning: unannotated intra-function call ++ ++ This warning means that a direct call is done to a destination which ++ is not at the beginning of a function. If this is a legit call, you ++ can remove this warning by putting the ANNOTATE_INTRA_FUNCTION_CALL ++ directive right before the call. ++ ++ + If the error doesn't seem to make sense, it could be a bug in objtool. + Feel free to ask the objtool maintainer for help. + +--- a/tools/objtool/arch/x86/decode.c ++++ b/tools/objtool/arch/x86/decode.c +@@ -470,6 +470,14 @@ int arch_decode_instruction(struct elf * + + case 0xe8: + *type = INSN_CALL; ++ /* ++ * For the impact on the stack, a CALL behaves like ++ * a PUSH of an immediate value (the return address). ++ */ ++ ADD_OP(op) { ++ op->src.type = OP_SRC_CONST; ++ op->dest.type = OP_DEST_PUSH; ++ } + break; + + case 0xff: +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -590,6 +590,16 @@ static int add_jump_destinations(struct + return 0; + } + ++static void remove_insn_ops(struct instruction *insn) ++{ ++ struct stack_op *op, *tmp; ++ ++ list_for_each_entry_safe(op, tmp, &insn->stack_ops, list) { ++ list_del(&op->list); ++ free(op); ++ } ++} ++ + /* + * Find the destination instructions for all calls. + */ +@@ -611,10 +621,7 @@ static int add_call_destinations(struct + dest_off); + + if (!insn->call_dest && !insn->ignore) { +- WARN_FUNC("unsupported intra-function call", +- insn->sec, insn->offset); +- if (retpoline) +- WARN("If this is a retpoline, please patch it in with alternatives and annotate it with ANNOTATE_NOSPEC_ALTERNATIVE."); ++ WARN_FUNC("unannotated intra-function call", insn->sec, insn->offset); + return -1; + } + +@@ -631,6 +638,15 @@ static int add_call_destinations(struct + } + } else + insn->call_dest = rela->sym; ++ ++ /* ++ * Whatever stack impact regular CALLs have, should be undone ++ * by the RETURN of the called function. ++ * ++ * Annotated intra-function calls retain the stack_ops but ++ * are converted to JUMP, see read_intra_function_calls(). ++ */ ++ remove_insn_ops(insn); + } + + return 0; +@@ -1243,6 +1259,57 @@ static int read_retpoline_hints(struct o + return 0; + } + ++static int read_intra_function_calls(struct objtool_file *file) ++{ ++ struct instruction *insn; ++ struct section *sec; ++ struct rela *rela; ++ ++ sec = find_section_by_name(file->elf, ".rela.discard.intra_function_calls"); ++ if (!sec) ++ return 0; ++ ++ list_for_each_entry(rela, &sec->rela_list, list) { ++ unsigned long dest_off; ++ ++ if (rela->sym->type != STT_SECTION) { ++ WARN("unexpected relocation symbol type in %s", ++ sec->name); ++ return -1; ++ } ++ ++ insn = find_insn(file, rela->sym->sec, rela->addend); ++ if (!insn) { ++ WARN("bad .discard.intra_function_call entry"); ++ return -1; ++ } ++ ++ if (insn->type != INSN_CALL) { ++ WARN_FUNC("intra_function_call not a direct call", ++ insn->sec, insn->offset); ++ return -1; ++ } ++ ++ /* ++ * Treat intra-function CALLs as JMPs, but with a stack_op. ++ * See add_call_destinations(), which strips stack_ops from ++ * normal CALLs. ++ */ ++ insn->type = INSN_JUMP_UNCONDITIONAL; ++ ++ dest_off = insn->offset + insn->len + insn->immediate; ++ insn->jump_dest = find_insn(file, insn->sec, dest_off); ++ if (!insn->jump_dest) { ++ WARN_FUNC("can't find call dest at %s+0x%lx", ++ insn->sec, insn->offset, ++ insn->sec->name, dest_off); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ + static int decode_sections(struct objtool_file *file) + { + int ret; +@@ -1269,6 +1336,10 @@ static int decode_sections(struct objtoo + if (ret) + return ret; + ++ ret = read_intra_function_calls(file); ++ if (ret) ++ return ret; ++ + ret = add_call_destinations(file); + if (ret) + return ret; diff --git a/patches.suse/objtool-Allow-no-op-CFI-ops-in-alternatives.patch b/patches.suse/objtool-Allow-no-op-CFI-ops-in-alternatives.patch new file mode 100644 index 0000000..860e263 --- /dev/null +++ b/patches.suse/objtool-Allow-no-op-CFI-ops-in-alternatives.patch @@ -0,0 +1,59 @@ +From: Peter Zijlstra +Date: Fri, 8 May 2020 12:34:33 +0200 +Subject: objtool: Allow no-op CFI ops in alternatives +Git-commit: ab3852ab5cb8fd2e2c5bfa176e5f953353836907 +Patch-mainline: v5.8-rc1 +References: bsc#1202396 + +Randy reported a false-positive: + + arch/x86/hyperv/hv_apic.o: warning: objtool: hv_apic_write()+0x25: alternative modifies stack + +What happens is that: + + alternative_io("movl %0, %P1", "xchgl %0, %P1", X86_BUG_11AP, + 13d: 89 9d 00 d0 7f ff mov %ebx,-0x803000(%rbp) + +decodes to an instruction with CFI-ops because it modifies RBP. +However, due to this being a !frame-pointer build, that should not in +fact change the CFI state. + +So instead of dis-allowing any CFI-op, verify the op would've actually +changed the CFI state. + +Fixes: 7117f16bf460 ("objtool: Fix ORC vs alternatives") +Reported-by: Randy Dunlap +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Josh Poimboeuf +Acked-by: Randy Dunlap +Tested-by: Randy Dunlap +Acked-by: Miroslav Benes +--- + tools/objtool/check.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -1842,16 +1842,17 @@ static int handle_insn_ops(struct instru + struct stack_op *op; + + list_for_each_entry(op, &insn->stack_ops, list) { ++ struct cfi_state old_cfi = state->cfi; + int res; + +- if (insn->alt_group) { +- WARN_FUNC("alternative modifies stack", insn->sec, insn->offset); +- return -1; +- } +- + res = update_cfi_state(insn, &state->cfi, op); + if (res) + return res; ++ ++ if (insn->alt_group && memcmp(&state->cfi, &old_cfi, sizeof(struct cfi_state))) { ++ WARN_FUNC("alternative modifies stack", insn->sec, insn->offset); ++ return -1; ++ } + } + + return 0; diff --git a/patches.suse/objtool-Convert-insn-type-to-enum.patch b/patches.suse/objtool-Convert-insn-type-to-enum.patch new file mode 100644 index 0000000..0a31ef1 --- /dev/null +++ b/patches.suse/objtool-Convert-insn-type-to-enum.patch @@ -0,0 +1,105 @@ +From: Josh Poimboeuf +Date: Wed, 17 Jul 2019 20:36:56 -0500 +Subject: objtool: Convert insn type to enum +Git-commit: 9fe7b7642fe2c5158904d06fe31b740ca0695a01 +Patch-mainline: v5.3-rc1 +References: bsc#1202396 + +This makes it easier to add new instruction types. Also it's hopefully +more robust since the compiler should warn about out-of-range enums. + +Signed-off-by: Josh Poimboeuf +Signed-off-by: Thomas Gleixner +Tested-by: Nick Desaulniers +Acked-by: Peter Zijlstra (Intel) +Link: https://lkml.kernel.org/r/0740e96af0d40e54cfd6a07bf09db0fbd10793cd.1563413318.git.jpoimboe@redhat.com + +Acked-by: Miroslav Benes +--- + tools/objtool/arch.h | 27 ++++++++++++++------------- + tools/objtool/arch/x86/decode.c | 2 +- + tools/objtool/check.c | 7 ------- + tools/objtool/check.h | 2 +- + 4 files changed, 16 insertions(+), 22 deletions(-) + +--- a/tools/objtool/arch.h ++++ b/tools/objtool/arch.h +@@ -23,18 +23,19 @@ + #include "elf.h" + #include "cfi.h" + +-#define INSN_JUMP_CONDITIONAL 1 +-#define INSN_JUMP_UNCONDITIONAL 2 +-#define INSN_JUMP_DYNAMIC 3 +-#define INSN_CALL 4 +-#define INSN_CALL_DYNAMIC 5 +-#define INSN_RETURN 6 +-#define INSN_CONTEXT_SWITCH 7 +-#define INSN_STACK 8 +-#define INSN_BUG 9 +-#define INSN_NOP 10 +-#define INSN_OTHER 11 +-#define INSN_LAST INSN_OTHER ++enum insn_type { ++ INSN_JUMP_CONDITIONAL, ++ INSN_JUMP_UNCONDITIONAL, ++ INSN_JUMP_DYNAMIC, ++ INSN_CALL, ++ INSN_CALL_DYNAMIC, ++ INSN_RETURN, ++ INSN_CONTEXT_SWITCH, ++ INSN_STACK, ++ INSN_BUG, ++ INSN_NOP, ++ INSN_OTHER, ++}; + + enum op_dest_type { + OP_DEST_REG, +@@ -74,7 +75,7 @@ void arch_initial_func_cfi_state(struct + + int arch_decode_instruction(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int maxlen, +- unsigned int *len, unsigned char *type, ++ unsigned int *len, enum insn_type *type, + unsigned long *immediate, struct stack_op *op); + + bool arch_callee_saved_reg(unsigned char reg); +--- a/tools/objtool/arch/x86/decode.c ++++ b/tools/objtool/arch/x86/decode.c +@@ -80,7 +80,7 @@ bool arch_callee_saved_reg(unsigned char + + int arch_decode_instruction(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int maxlen, +- unsigned int *len, unsigned char *type, ++ unsigned int *len, enum insn_type *type, + unsigned long *immediate, struct stack_op *op) + { + struct insn insn; +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -295,13 +295,6 @@ static int decode_instructions(struct ob + if (ret) + goto err; + +- if (!insn->type || insn->type > INSN_LAST) { +- WARN_FUNC("invalid instruction type %d", +- insn->sec, insn->offset, insn->type); +- ret = -1; +- goto err; +- } +- + hash_add(file->insn_hash, &insn->hash, insn->offset); + list_add_tail(&insn->list, &file->insn_list); + } +--- a/tools/objtool/check.h ++++ b/tools/objtool/check.h +@@ -42,7 +42,7 @@ struct instruction { + struct section *sec; + unsigned long offset; + unsigned int len; +- unsigned char type; ++ enum insn_type type; + unsigned long immediate; + bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; + bool retpoline_safe; diff --git a/patches.suse/objtool-Don-t-use-ignore-flag-for-fake-jumps.patch b/patches.suse/objtool-Don-t-use-ignore-flag-for-fake-jumps.patch new file mode 100644 index 0000000..3647904 --- /dev/null +++ b/patches.suse/objtool-Don-t-use-ignore-flag-for-fake-jumps.patch @@ -0,0 +1,68 @@ +From: Josh Poimboeuf +Date: Mon, 13 May 2019 12:01:31 -0500 +Subject: objtool: Don't use ignore flag for fake jumps +Git-commit: e6da9567959e164f82bc81967e0d5b10dee870b4 +Patch-mainline: v5.2-rc1 +References: bsc#1202396 + +The ignore flag is set on fake jumps in order to keep +add_jump_destinations() from setting their jump_dest, since it already +got set when the fake jump was created. + +But using the ignore flag is a bit of a hack. It's normally used to +skip validation of an instruction, which doesn't really make sense for +fake jumps. + +Also, after the next patch, using the ignore flag for fake jumps can +trigger a false "why am I validating an ignored function?" warning. + +Instead just add an explicit check in add_jump_destinations() to skip +fake jumps. + +Signed-off-by: Josh Poimboeuf +Cc: Linus Torvalds +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Link: http://lkml.kernel.org/r/71abc072ff48b2feccc197723a9c52859476c068.1557766718.git.jpoimboe@redhat.com +Signed-off-by: Ingo Molnar +Acked-by: Miroslav Benes +--- + tools/objtool/check.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index ac743a1d53ab..90226791df6b 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -28,6 +28,8 @@ + #include + #include + ++#define FAKE_JUMP_OFFSET -1 ++ + struct alternative { + struct list_head list; + struct instruction *insn; +@@ -568,7 +570,7 @@ static int add_jump_destinations(struct objtool_file *file) + insn->type != INSN_JUMP_UNCONDITIONAL) + continue; + +- if (insn->ignore) ++ if (insn->ignore || insn->offset == FAKE_JUMP_OFFSET) + continue; + + rela = find_rela_by_dest_range(insn->sec, insn->offset, +@@ -745,10 +747,10 @@ static int handle_group_alt(struct objtool_file *file, + clear_insn_state(&fake_jump->state); + + fake_jump->sec = special_alt->new_sec; +- fake_jump->offset = -1; ++ fake_jump->offset = FAKE_JUMP_OFFSET; + fake_jump->type = INSN_JUMP_UNCONDITIONAL; + fake_jump->jump_dest = list_next_entry(last_orig_insn, list); +- fake_jump->ignore = true; ++ fake_jump->func = orig_insn->func; + } + + if (!special_alt->new_len) { + diff --git a/patches.suse/objtool-Fix-CFI-insn_state-propagation.patch b/patches.suse/objtool-Fix-CFI-insn_state-propagation.patch new file mode 100644 index 0000000..e73694a --- /dev/null +++ b/patches.suse/objtool-Fix-CFI-insn_state-propagation.patch @@ -0,0 +1,738 @@ +From: Peter Zijlstra +Date: Wed, 25 Mar 2020 14:04:45 +0100 +Subject: objtool: Fix !CFI insn_state propagation +Git-commit: e7c0219b328c96746767f21b9532eed6a48f61c5 +Patch-mainline: v5.8-rc1 +References: bsc#1202396 + +Objtool keeps per instruction CFI state in struct insn_state and will +save/restore this where required. However, insn_state has grown some +!CFI state, and this must not be saved/restored (that would +loose/destroy state). + +Fix this by moving the CFI specific parts of insn_state into struct +cfi_state. + +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Miroslav Benes +Reviewed-by: Alexandre Chartre +Acked-by: Josh Poimboeuf +Link: https://lkml.kernel.org/r/20200416115119.045821071@infradead.org +Signed-off-by: Ingo Molnar +Acked-by: Miroslav Benes +--- + tools/objtool/cfi.h | 12 ++ + tools/objtool/check.c | 264 ++++++++++++++++++++++++------------------------ + tools/objtool/check.h | 11 -- + tools/objtool/orc_gen.c | 6 - + 4 files changed, 154 insertions(+), 139 deletions(-) + +--- a/tools/objtool/cfi.h ++++ b/tools/objtool/cfi.h +@@ -48,8 +48,20 @@ struct cfi_reg { + }; + + struct cfi_init_state { ++ struct cfi_reg regs[CFI_NUM_REGS]; + struct cfi_reg cfa; ++}; ++ ++struct cfi_state { + struct cfi_reg regs[CFI_NUM_REGS]; ++ struct cfi_reg vals[CFI_NUM_REGS]; ++ struct cfi_reg cfa; ++ int stack_size; ++ int drap_reg, drap_offset; ++ unsigned char type; ++ bool bp_scratch; ++ bool drap; ++ bool end; + }; + + #endif /* _OBJTOOL_CFI_H */ +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -238,18 +238,23 @@ static int dead_end_function(struct objt + return __dead_end_function(file, func, 0); + } + +-static void clear_insn_state(struct insn_state *state) ++static void init_cfi_state(struct cfi_state *cfi) + { + int i; + +- memset(state, 0, sizeof(*state)); +- state->cfa.base = CFI_UNDEFINED; + for (i = 0; i < CFI_NUM_REGS; i++) { +- state->regs[i].base = CFI_UNDEFINED; +- state->vals[i].base = CFI_UNDEFINED; ++ cfi->regs[i].base = CFI_UNDEFINED; ++ cfi->vals[i].base = CFI_UNDEFINED; + } +- state->drap_reg = CFI_UNDEFINED; +- state->drap_offset = -1; ++ cfi->cfa.base = CFI_UNDEFINED; ++ cfi->drap_reg = CFI_UNDEFINED; ++ cfi->drap_offset = -1; ++} ++ ++static void clear_insn_state(struct insn_state *state) ++{ ++ memset(state, 0, sizeof(*state)); ++ init_cfi_state(&state->cfi); + } + + /* +@@ -283,7 +288,7 @@ static int decode_instructions(struct ob + memset(insn, 0, sizeof(*insn)); + INIT_LIST_HEAD(&insn->alts); + INIT_LIST_HEAD(&insn->stack_ops); +- clear_insn_state(&insn->state); ++ init_cfi_state(&insn->cfi); + + insn->sec = sec; + insn->offset = offset; +@@ -675,7 +680,7 @@ static int handle_group_alt(struct objto + memset(fake_jump, 0, sizeof(*fake_jump)); + INIT_LIST_HEAD(&fake_jump->alts); + INIT_LIST_HEAD(&fake_jump->stack_ops); +- clear_insn_state(&fake_jump->state); ++ init_cfi_state(&fake_jump->cfi); + + fake_jump->sec = special_alt->new_sec; + fake_jump->offset = FAKE_JUMP_OFFSET; +@@ -1147,7 +1152,7 @@ static int read_unwind_hints(struct objt + return -1; + } + +- cfa = &insn->state.cfa; ++ cfa = &insn->cfi.cfa; + + if (hint->type == UNWIND_HINT_TYPE_SAVE) { + insn->save = true; +@@ -1193,7 +1198,7 @@ static int read_unwind_hints(struct objt + } + + cfa->offset = hint->sp_offset; +- insn->state.type = hint->type; ++ insn->cfi.type = hint->type; + } + + return 0; +@@ -1291,17 +1296,18 @@ static bool is_fentry_call(struct instru + + static bool has_modified_stack_frame(struct insn_state *state) + { ++ struct cfi_state *cfi = &state->cfi; + int i; + +- if (state->cfa.base != initial_func_cfi.cfa.base || +- state->cfa.offset != initial_func_cfi.cfa.offset || +- state->stack_size != initial_func_cfi.cfa.offset || +- state->drap) ++ if (cfi->cfa.base != initial_func_cfi.cfa.base || ++ cfi->cfa.offset != initial_func_cfi.cfa.offset || ++ cfi->stack_size != initial_func_cfi.cfa.offset || ++ cfi->drap) + return true; + + for (i = 0; i < CFI_NUM_REGS; i++) +- if (state->regs[i].base != initial_func_cfi.regs[i].base || +- state->regs[i].offset != initial_func_cfi.regs[i].offset) ++ if (cfi->regs[i].base != initial_func_cfi.regs[i].base || ++ cfi->regs[i].offset != initial_func_cfi.regs[i].offset) + return true; + + return false; +@@ -1309,21 +1315,23 @@ static bool has_modified_stack_frame(str + + static bool has_valid_stack_frame(struct insn_state *state) + { +- if (state->cfa.base == CFI_BP && state->regs[CFI_BP].base == CFI_CFA && +- state->regs[CFI_BP].offset == -16) ++ struct cfi_state *cfi = &state->cfi; ++ ++ if (cfi->cfa.base == CFI_BP && cfi->regs[CFI_BP].base == CFI_CFA && ++ cfi->regs[CFI_BP].offset == -16) + return true; + +- if (state->drap && state->regs[CFI_BP].base == CFI_BP) ++ if (cfi->drap && cfi->regs[CFI_BP].base == CFI_BP) + return true; + + return false; + } + +-static int update_insn_state_regs(struct instruction *insn, +- struct insn_state *state, ++static int update_cfi_state_regs(struct instruction *insn, ++ struct cfi_state *cfi, + struct stack_op *op) + { +- struct cfi_reg *cfa = &state->cfa; ++ struct cfi_reg *cfa = &cfi->cfa; + + if (cfa->base != CFI_SP && cfa->base != CFI_SP_INDIRECT) + return 0; +@@ -1344,20 +1352,19 @@ static int update_insn_state_regs(struct + return 0; + } + +-static void save_reg(struct insn_state *state, unsigned char reg, int base, +- int offset) ++static void save_reg(struct cfi_state *cfi, unsigned char reg, int base, int offset) + { + if (arch_callee_saved_reg(reg) && +- state->regs[reg].base == CFI_UNDEFINED) { +- state->regs[reg].base = base; +- state->regs[reg].offset = offset; ++ cfi->regs[reg].base == CFI_UNDEFINED) { ++ cfi->regs[reg].base = base; ++ cfi->regs[reg].offset = offset; + } + } + +-static void restore_reg(struct insn_state *state, unsigned char reg) ++static void restore_reg(struct cfi_state *cfi, unsigned char reg) + { +- state->regs[reg].base = CFI_UNDEFINED; +- state->regs[reg].offset = 0; ++ cfi->regs[reg].base = CFI_UNDEFINED; ++ cfi->regs[reg].offset = 0; + } + + /* +@@ -1413,11 +1420,11 @@ static void restore_reg(struct insn_stat + * 41 5d pop %r13 + * c3 retq + */ +-static int update_insn_state(struct instruction *insn, struct insn_state *state, ++static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi, + struct stack_op *op) + { +- struct cfi_reg *cfa = &state->cfa; +- struct cfi_reg *regs = state->regs; ++ struct cfi_reg *cfa = &cfi->cfa; ++ struct cfi_reg *regs = cfi->regs; + + /* stack operations don't make sense with an undefined CFA */ + if (cfa->base == CFI_UNDEFINED) { +@@ -1428,8 +1435,8 @@ static int update_insn_state(struct inst + return 0; + } + +- if (state->type == ORC_TYPE_REGS || state->type == ORC_TYPE_REGS_IRET) +- return update_insn_state_regs(insn, state, op); ++ if (cfi->type == ORC_TYPE_REGS || cfi->type == ORC_TYPE_REGS_IRET) ++ return update_cfi_state_regs(insn, cfi, op); + + switch (op->dest.type) { + +@@ -1444,16 +1451,16 @@ static int update_insn_state(struct inst + + /* mov %rsp, %rbp */ + cfa->base = op->dest.reg; +- state->bp_scratch = false; ++ cfi->bp_scratch = false; + } + + else if (op->src.reg == CFI_SP && +- op->dest.reg == CFI_BP && state->drap) { ++ op->dest.reg == CFI_BP && cfi->drap) { + + /* drap: mov %rsp, %rbp */ + regs[CFI_BP].base = CFI_BP; +- regs[CFI_BP].offset = -state->stack_size; +- state->bp_scratch = false; ++ regs[CFI_BP].offset = -cfi->stack_size; ++ cfi->bp_scratch = false; + } + + else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { +@@ -1468,15 +1475,15 @@ static int update_insn_state(struct inst + * ... + * mov %rax, %rsp + */ +- state->vals[op->dest.reg].base = CFI_CFA; +- state->vals[op->dest.reg].offset = -state->stack_size; ++ cfi->vals[op->dest.reg].base = CFI_CFA; ++ cfi->vals[op->dest.reg].offset = -cfi->stack_size; + } + + else if (op->dest.reg == cfa->base) { + + /* mov %reg, %rsp */ + if (cfa->base == CFI_SP && +- state->vals[op->src.reg].base == CFI_CFA) { ++ cfi->vals[op->src.reg].base == CFI_CFA) { + + /* + * This is needed for the rare case +@@ -1486,8 +1493,8 @@ static int update_insn_state(struct inst + * ... + * mov %rcx, %rsp + */ +- cfa->offset = -state->vals[op->src.reg].offset; +- state->stack_size = cfa->offset; ++ cfa->offset = -cfi->vals[op->src.reg].offset; ++ cfi->stack_size = cfa->offset; + + } else { + cfa->base = CFI_UNDEFINED; +@@ -1501,7 +1508,7 @@ static int update_insn_state(struct inst + if (op->dest.reg == CFI_SP && op->src.reg == CFI_SP) { + + /* add imm, %rsp */ +- state->stack_size -= op->src.offset; ++ cfi->stack_size -= op->src.offset; + if (cfa->base == CFI_SP) + cfa->offset -= op->src.offset; + break; +@@ -1510,14 +1517,14 @@ static int update_insn_state(struct inst + if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) { + + /* lea disp(%rbp), %rsp */ +- state->stack_size = -(op->src.offset + regs[CFI_BP].offset); ++ cfi->stack_size = -(op->src.offset + regs[CFI_BP].offset); + break; + } + + if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { + + /* drap: lea disp(%rsp), %drap */ +- state->drap_reg = op->dest.reg; ++ cfi->drap_reg = op->dest.reg; + + /* + * lea disp(%rsp), %reg +@@ -1529,25 +1536,25 @@ static int update_insn_state(struct inst + * ... + * mov %rcx, %rsp + */ +- state->vals[op->dest.reg].base = CFI_CFA; +- state->vals[op->dest.reg].offset = \ +- -state->stack_size + op->src.offset; ++ cfi->vals[op->dest.reg].base = CFI_CFA; ++ cfi->vals[op->dest.reg].offset = \ ++ -cfi->stack_size + op->src.offset; + + break; + } + +- if (state->drap && op->dest.reg == CFI_SP && +- op->src.reg == state->drap_reg) { ++ if (cfi->drap && op->dest.reg == CFI_SP && ++ op->src.reg == cfi->drap_reg) { + + /* drap: lea disp(%drap), %rsp */ + cfa->base = CFI_SP; +- cfa->offset = state->stack_size = -op->src.offset; +- state->drap_reg = CFI_UNDEFINED; +- state->drap = false; ++ cfa->offset = cfi->stack_size = -op->src.offset; ++ cfi->drap_reg = CFI_UNDEFINED; ++ cfi->drap = false; + break; + } + +- if (op->dest.reg == state->cfa.base) { ++ if (op->dest.reg == cfi->cfa.base) { + WARN_FUNC("unsupported stack register modification", + insn->sec, insn->offset); + return -1; +@@ -1557,18 +1564,18 @@ static int update_insn_state(struct inst + + case OP_SRC_AND: + if (op->dest.reg != CFI_SP || +- (state->drap_reg != CFI_UNDEFINED && cfa->base != CFI_SP) || +- (state->drap_reg == CFI_UNDEFINED && cfa->base != CFI_BP)) { ++ (cfi->drap_reg != CFI_UNDEFINED && cfa->base != CFI_SP) || ++ (cfi->drap_reg == CFI_UNDEFINED && cfa->base != CFI_BP)) { + WARN_FUNC("unsupported stack pointer realignment", + insn->sec, insn->offset); + return -1; + } + +- if (state->drap_reg != CFI_UNDEFINED) { ++ if (cfi->drap_reg != CFI_UNDEFINED) { + /* drap: and imm, %rsp */ +- cfa->base = state->drap_reg; +- cfa->offset = state->stack_size = 0; +- state->drap = true; ++ cfa->base = cfi->drap_reg; ++ cfa->offset = cfi->stack_size = 0; ++ cfi->drap = true; + } + + /* +@@ -1579,57 +1586,57 @@ static int update_insn_state(struct inst + break; + + case OP_SRC_POP: +- if (!state->drap && op->dest.type == OP_DEST_REG && ++ if (!cfi->drap && op->dest.type == OP_DEST_REG && + op->dest.reg == cfa->base) { + + /* pop %rbp */ + cfa->base = CFI_SP; + } + +- if (state->drap && cfa->base == CFI_BP_INDIRECT && ++ if (cfi->drap && cfa->base == CFI_BP_INDIRECT && + op->dest.type == OP_DEST_REG && +- op->dest.reg == state->drap_reg && +- state->drap_offset == -state->stack_size) { ++ op->dest.reg == cfi->drap_reg && ++ cfi->drap_offset == -cfi->stack_size) { + + /* drap: pop %drap */ +- cfa->base = state->drap_reg; ++ cfa->base = cfi->drap_reg; + cfa->offset = 0; +- state->drap_offset = -1; ++ cfi->drap_offset = -1; + +- } else if (regs[op->dest.reg].offset == -state->stack_size) { ++ } else if (regs[op->dest.reg].offset == -cfi->stack_size) { + + /* pop %reg */ +- restore_reg(state, op->dest.reg); ++ restore_reg(cfi, op->dest.reg); + } + +- state->stack_size -= 8; ++ cfi->stack_size -= 8; + if (cfa->base == CFI_SP) + cfa->offset -= 8; + + break; + + case OP_SRC_REG_INDIRECT: +- if (state->drap && op->src.reg == CFI_BP && +- op->src.offset == state->drap_offset) { ++ if (cfi->drap && op->src.reg == CFI_BP && ++ op->src.offset == cfi->drap_offset) { + + /* drap: mov disp(%rbp), %drap */ +- cfa->base = state->drap_reg; ++ cfa->base = cfi->drap_reg; + cfa->offset = 0; +- state->drap_offset = -1; ++ cfi->drap_offset = -1; + } + +- if (state->drap && op->src.reg == CFI_BP && ++ if (cfi->drap && op->src.reg == CFI_BP && + op->src.offset == regs[op->dest.reg].offset) { + + /* drap: mov disp(%rbp), %reg */ +- restore_reg(state, op->dest.reg); ++ restore_reg(cfi, op->dest.reg); + + } else if (op->src.reg == cfa->base && + op->src.offset == regs[op->dest.reg].offset + cfa->offset) { + + /* mov disp(%rbp), %reg */ + /* mov disp(%rsp), %reg */ +- restore_reg(state, op->dest.reg); ++ restore_reg(cfi, op->dest.reg); + } + + break; +@@ -1643,78 +1650,78 @@ static int update_insn_state(struct inst + break; + + case OP_DEST_PUSH: +- state->stack_size += 8; ++ cfi->stack_size += 8; + if (cfa->base == CFI_SP) + cfa->offset += 8; + + if (op->src.type != OP_SRC_REG) + break; + +- if (state->drap) { +- if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) { ++ if (cfi->drap) { ++ if (op->src.reg == cfa->base && op->src.reg == cfi->drap_reg) { + + /* drap: push %drap */ + cfa->base = CFI_BP_INDIRECT; +- cfa->offset = -state->stack_size; ++ cfa->offset = -cfi->stack_size; + + /* save drap so we know when to restore it */ +- state->drap_offset = -state->stack_size; ++ cfi->drap_offset = -cfi->stack_size; + +- } else if (op->src.reg == CFI_BP && cfa->base == state->drap_reg) { ++ } else if (op->src.reg == CFI_BP && cfa->base == cfi->drap_reg) { + + /* drap: push %rbp */ +- state->stack_size = 0; ++ cfi->stack_size = 0; + + } else if (regs[op->src.reg].base == CFI_UNDEFINED) { + + /* drap: push %reg */ +- save_reg(state, op->src.reg, CFI_BP, -state->stack_size); ++ save_reg(cfi, op->src.reg, CFI_BP, -cfi->stack_size); + } + + } else { + + /* push %reg */ +- save_reg(state, op->src.reg, CFI_CFA, -state->stack_size); ++ save_reg(cfi, op->src.reg, CFI_CFA, -cfi->stack_size); + } + + /* detect when asm code uses rbp as a scratch register */ + if (!no_fp && insn->func && op->src.reg == CFI_BP && + cfa->base != CFI_BP) +- state->bp_scratch = true; ++ cfi->bp_scratch = true; + break; + + case OP_DEST_REG_INDIRECT: + +- if (state->drap) { +- if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) { ++ if (cfi->drap) { ++ if (op->src.reg == cfa->base && op->src.reg == cfi->drap_reg) { + + /* drap: mov %drap, disp(%rbp) */ + cfa->base = CFI_BP_INDIRECT; + cfa->offset = op->dest.offset; + + /* save drap offset so we know when to restore it */ +- state->drap_offset = op->dest.offset; ++ cfi->drap_offset = op->dest.offset; + } + + else if (regs[op->src.reg].base == CFI_UNDEFINED) { + + /* drap: mov reg, disp(%rbp) */ +- save_reg(state, op->src.reg, CFI_BP, op->dest.offset); ++ save_reg(cfi, op->src.reg, CFI_BP, op->dest.offset); + } + + } else if (op->dest.reg == cfa->base) { + + /* mov reg, disp(%rbp) */ + /* mov reg, disp(%rsp) */ +- save_reg(state, op->src.reg, CFI_CFA, +- op->dest.offset - state->cfa.offset); ++ save_reg(cfi, op->src.reg, CFI_CFA, ++ op->dest.offset - cfi->cfa.offset); + } + + break; + + case OP_DEST_LEAVE: +- if ((!state->drap && cfa->base != CFI_BP) || +- (state->drap && cfa->base != state->drap_reg)) { ++ if ((!cfi->drap && cfa->base != CFI_BP) || ++ (cfi->drap && cfa->base != cfi->drap_reg)) { + WARN_FUNC("leave instruction with modified stack frame", + insn->sec, insn->offset); + return -1; +@@ -1722,10 +1729,10 @@ static int update_insn_state(struct inst + + /* leave (mov %rbp, %rsp; pop %rbp) */ + +- state->stack_size = -state->regs[CFI_BP].offset - 8; +- restore_reg(state, CFI_BP); ++ cfi->stack_size = -cfi->regs[CFI_BP].offset - 8; ++ restore_reg(cfi, CFI_BP); + +- if (!state->drap) { ++ if (!cfi->drap) { + cfa->base = CFI_SP; + cfa->offset -= 8; + } +@@ -1740,7 +1747,7 @@ static int update_insn_state(struct inst + } + + /* pop mem */ +- state->stack_size -= 8; ++ cfi->stack_size -= 8; + if (cfa->base == CFI_SP) + cfa->offset -= 8; + +@@ -1762,7 +1769,7 @@ static int handle_insn_ops(struct instru + list_for_each_entry(op, &insn->stack_ops, list) { + int res; + +- res = update_insn_state(insn, state, op); ++ res = update_cfi_state(insn, &state->cfi, op); + if (res) + return res; + } +@@ -1770,41 +1777,44 @@ static int handle_insn_ops(struct instru + return 0; + } + +-static bool insn_state_match(struct instruction *insn, struct insn_state *state) ++static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2) + { +- struct insn_state *state1 = &insn->state, *state2 = state; ++ struct cfi_state *cfi1 = &insn->cfi; + int i; + +- if (memcmp(&state1->cfa, &state2->cfa, sizeof(state1->cfa))) { ++ if (memcmp(&cfi1->cfa, &cfi2->cfa, sizeof(cfi1->cfa))) { ++ + WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d", + insn->sec, insn->offset, +- state1->cfa.base, state1->cfa.offset, +- state2->cfa.base, state2->cfa.offset); ++ cfi1->cfa.base, cfi1->cfa.offset, ++ cfi2->cfa.base, cfi2->cfa.offset); + +- } else if (memcmp(&state1->regs, &state2->regs, sizeof(state1->regs))) { ++ } else if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) { + for (i = 0; i < CFI_NUM_REGS; i++) { +- if (!memcmp(&state1->regs[i], &state2->regs[i], ++ if (!memcmp(&cfi1->regs[i], &cfi2->regs[i], + sizeof(struct cfi_reg))) + continue; + + WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d", + insn->sec, insn->offset, +- i, state1->regs[i].base, state1->regs[i].offset, +- i, state2->regs[i].base, state2->regs[i].offset); ++ i, cfi1->regs[i].base, cfi1->regs[i].offset, ++ i, cfi2->regs[i].base, cfi2->regs[i].offset); + break; + } + +- } else if (state1->type != state2->type) { ++ } else if (cfi1->type != cfi2->type) { ++ + WARN_FUNC("stack state mismatch: type1=%d type2=%d", +- insn->sec, insn->offset, state1->type, state2->type); ++ insn->sec, insn->offset, cfi1->type, cfi2->type); ++ ++ } else if (cfi1->drap != cfi2->drap || ++ (cfi1->drap && cfi1->drap_reg != cfi2->drap_reg) || ++ (cfi1->drap && cfi1->drap_offset != cfi2->drap_offset)) { + +- } else if (state1->drap != state2->drap || +- (state1->drap && state1->drap_reg != state2->drap_reg) || +- (state1->drap && state1->drap_offset != state2->drap_offset)) { + WARN_FUNC("stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)", + insn->sec, insn->offset, +- state1->drap, state1->drap_reg, state1->drap_offset, +- state2->drap, state2->drap_reg, state2->drap_offset); ++ cfi1->drap, cfi1->drap_reg, cfi1->drap_offset, ++ cfi2->drap, cfi2->drap_reg, cfi2->drap_offset); + + } else + return true; +@@ -1862,7 +1872,7 @@ static int validate_branch(struct objtoo + } + + if (insn->visited) { +- if (!insn->hint && !insn_state_match(insn, &state)) ++ if (!insn->hint && !insn_cfi_match(insn, &state.cfi)) + return 1; + + return 0; +@@ -1903,13 +1913,13 @@ static int validate_branch(struct objtoo + return 1; + } + +- insn->state = save_insn->state; ++ insn->cfi = save_insn->cfi; + } + +- state = insn->state; ++ state.cfi = insn->cfi; + + } else +- insn->state = state; ++ insn->cfi = state.cfi; + + insn->visited = true; + +@@ -1941,7 +1951,7 @@ static int validate_branch(struct objtoo + return 1; + } + +- if (state.bp_scratch) { ++ if (state.cfi.bp_scratch) { + WARN_FUNC("BP used as a scratch register", + sec, insn->offset); + return 1; +@@ -2027,7 +2037,7 @@ static int validate_branch(struct objtoo + return 0; + + if (!next_insn) { +- if (state.cfa.base == CFI_UNDEFINED) ++ if (state.cfi.cfa.base == CFI_UNDEFINED) + return 0; + WARN("%s: unexpected end of section", sec->name); + return 1; +@@ -2176,10 +2186,10 @@ static int validate_functions(struct obj + continue; + + clear_insn_state(&state); +- state.cfa = initial_func_cfi.cfa; +- memcpy(&state.regs, &initial_func_cfi.regs, ++ state.cfi.cfa = initial_func_cfi.cfa; ++ memcpy(&state.cfi.regs, &initial_func_cfi.regs, + CFI_NUM_REGS * sizeof(struct cfi_reg)); +- state.stack_size = initial_func_cfi.cfa.offset; ++ state.cfi.stack_size = initial_func_cfi.cfa.offset; + + ret = validate_branch(file, func, insn, state); + if (ret && backtrace) +--- a/tools/objtool/check.h ++++ b/tools/objtool/check.h +@@ -26,14 +26,7 @@ + #include + + struct insn_state { +- struct cfi_reg cfa; +- struct cfi_reg regs[CFI_NUM_REGS]; +- int stack_size; +- unsigned char type; +- bool bp_scratch; +- bool drap; +- int drap_reg, drap_offset; +- struct cfi_reg vals[CFI_NUM_REGS]; ++ struct cfi_state cfi; + }; + + struct instruction { +@@ -52,7 +45,7 @@ struct instruction { + struct list_head alts; + struct symbol *func; + struct list_head stack_ops; +- struct insn_state state; ++ struct cfi_state cfi; + struct orc_entry orc; + }; + +--- a/tools/objtool/orc_gen.c ++++ b/tools/objtool/orc_gen.c +@@ -28,8 +28,8 @@ int create_orc(struct objtool_file *file + + for_each_insn(file, insn) { + struct orc_entry *orc = &insn->orc; +- struct cfi_reg *cfa = &insn->state.cfa; +- struct cfi_reg *bp = &insn->state.regs[CFI_BP]; ++ struct cfi_reg *cfa = &insn->cfi.cfa; ++ struct cfi_reg *bp = &insn->cfi.regs[CFI_BP]; + + if (cfa->base == CFI_UNDEFINED) { + orc->sp_reg = ORC_REG_UNDEFINED; +@@ -85,7 +85,7 @@ int create_orc(struct objtool_file *file + + orc->sp_offset = cfa->offset; + orc->bp_offset = bp->offset; +- orc->type = insn->state.type; ++ orc->type = insn->cfi.type; + } + + return 0; diff --git a/patches.suse/objtool-Fix-ORC-vs-alternatives.patch b/patches.suse/objtool-Fix-ORC-vs-alternatives.patch new file mode 100644 index 0000000..39dbe6e --- /dev/null +++ b/patches.suse/objtool-Fix-ORC-vs-alternatives.patch @@ -0,0 +1,141 @@ +From: Peter Zijlstra +Date: Tue, 28 Apr 2020 19:37:01 +0200 +Subject: objtool: Fix ORC vs alternatives +Git-commit: 7117f16bf460ef8cd132e6e80c989677397b4868 +Patch-mainline: v5.8-rc1 +References: bsc#1202396 + +Jann reported that (for instance) entry_64.o:general_protection has +very odd ORC data: + + 0000000000000f40 : + #######sp:sp+8 bp:(und) type:iret end:0 + f40: 90 nop + #######sp:(und) bp:(und) type:call end:0 + f41: 90 nop + f42: 90 nop + #######sp:sp+8 bp:(und) type:iret end:0 + f43: e8 a8 01 00 00 callq 10f0 + #######sp:sp+0 bp:(und) type:regs end:0 + f48: f6 84 24 88 00 00 00 testb $0x3,0x88(%rsp) + f4f: 03 + f50: 74 00 je f52 + f52: 48 89 e7 mov %rsp,%rdi + f55: 48 8b 74 24 78 mov 0x78(%rsp),%rsi + f5a: 48 c7 44 24 78 ff ff movq $0xffffffffffffffff,0x78(%rsp) + f61: ff ff + f63: e8 00 00 00 00 callq f68 + f68: e9 73 02 00 00 jmpq 11e0 + #######sp:(und) bp:(und) type:call end:0 + f6d: 0f 1f 00 nopl (%rax) + +Note the entry at 0xf41. Josh found this was the result of commit: + + 764eef4b109a ("objtool: Rewrite alt->skip_orig") + +Due to the early return in validate_branch() we no longer set +insn->cfi of the original instruction stream (the NOPs at 0xf41 and +0xf42) and we'll end up with the above weirdness. + +In other discussions we realized alternatives should be ORC invariant; +that is, due to there being only a single ORC table, it must be valid +for all alternatives. The easiest way to ensure this is to not allow +any stack modifications in alternatives. + +When we enforce this latter observation, we get the property that the +whole alternative must have the same CFI, which we can employ to fix +the former report. + +Fixes: 764eef4b109a ("objtool: Rewrite alt->skip_orig") +Reported-by: Jann Horn +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Miroslav Benes +Acked-by: Josh Poimboeuf +Link: https://lkml.kernel.org/r/20200428191659.499074346@infradead.org + +Acked-by: Miroslav Benes +--- + tools/objtool/Documentation/stack-validation.txt | 7 ++++ + tools/objtool/check.c | 34 ++++++++++++++++++++++- + 2 files changed, 40 insertions(+), 1 deletion(-) + +--- a/tools/objtool/Documentation/stack-validation.txt ++++ b/tools/objtool/Documentation/stack-validation.txt +@@ -293,6 +293,13 @@ they mean, and suggestions for how to fi + If the error doesn't seem to make sense, it could be a bug in objtool. + Feel free to ask the objtool maintainer for help. + ++10. file.o: warning: func()+0x5c: alternative modifies stack ++ ++ This means that an alternative includes instructions that modify the ++ stack. The problem is that there is only one ORC unwind table, this means ++ that the ORC unwind entries must be valid for each of the alternatives. ++ The easiest way to enforce this is to ensure alternatives do not contain ++ any ORC entries, which in turn implies the above constraint. + + Adding exceptions + ----------------- +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -1773,6 +1773,11 @@ static int handle_insn_ops(struct instru + list_for_each_entry(op, &insn->stack_ops, list) { + int res; + ++ if (insn->alt_group) { ++ WARN_FUNC("alternative modifies stack", insn->sec, insn->offset); ++ return -1; ++ } ++ + res = update_cfi_state(insn, &state->cfi, op); + if (res) + return res; +@@ -1838,6 +1843,30 @@ static int validate_sibling_call(struct + } + + /* ++ * Alternatives should not contain any ORC entries, this in turn means they ++ * should not contain any CFI ops, which implies all instructions should have ++ * the same same CFI state. ++ * ++ * It is possible to constuct alternatives that have unreachable holes that go ++ * unreported (because they're NOPs), such holes would result in CFI_UNDEFINED ++ * states which then results in ORC entries, which we just said we didn't want. ++ * ++ * Avoid them by copying the CFI entry of the first instruction into the whole ++ * alternative. ++ */ ++static void fill_alternative_cfi(struct objtool_file *file, struct instruction *insn) ++{ ++ struct instruction *first_insn = insn; ++ int alt_group = insn->alt_group; ++ ++ sec_for_each_insn_continue(file, insn) { ++ if (insn->alt_group != alt_group) ++ break; ++ insn->cfi = first_insn->cfi; ++ } ++} ++ ++/* + * Follow the branch starting at the given instruction, and recursively follow + * any other branches (jumps). Meanwhile, track the frame pointer state at + * each instruction and validate all the rules described in +@@ -1921,7 +1950,7 @@ static int validate_branch(struct objtoo + + insn->visited = true; + +- if (!insn->ignore_alts) { ++ if (!insn->ignore_alts && !list_empty(&insn->alts)) { + bool skip_orig = false; + + list_for_each_entry(alt, &insn->alts, list) { +@@ -1936,6 +1965,9 @@ static int validate_branch(struct objtoo + } + } + ++ if (insn->alt_group) ++ fill_alternative_cfi(file, insn); ++ + if (skip_orig) + return 0; + } diff --git a/patches.suse/objtool-Fix-sibling-call-detection.patch b/patches.suse/objtool-Fix-sibling-call-detection.patch new file mode 100644 index 0000000..cdce79a --- /dev/null +++ b/patches.suse/objtool-Fix-sibling-call-detection.patch @@ -0,0 +1,180 @@ +From: Peter Zijlstra +Date: Wed, 6 Mar 2019 12:58:15 +0100 +Subject: objtool: Fix sibling call detection +Git-commit: 54262aa2830151f89699fa8a6c5aa05f0992e672 +Patch-mainline: v5.2-rc1 +References: bsc#1202396 + +It turned out that we failed to detect some sibling calls; +specifically those without relocation records; like: + + $ ./objdump-func.sh defconfig-build/mm/kasan/generic.o __asan_loadN + 0000 0000000000000840 <__asan_loadN>: + 0000 840: 48 8b 0c 24 mov (%rsp),%rcx + 0004 844: 31 d2 xor %edx,%edx + 0006 846: e9 45 fe ff ff jmpq 690 + +So extend the cross-function jump to also consider those that are not +between known (or newly detected) parent/child functions, as +sibling-cals when they jump to the start of the function. + +The second part of that condition is to deal with random jumps to the +middle of other function, as can be found in +arch/x86/lib/copy_user_64.S for example. + +This then (with later patches applied) makes the above recognise the +sibling call: + + mm/kasan/generic.o: warning: objtool: __asan_loadN()+0x6: call to check_memory_region() with UACCESS enabled + +Also make sure to set insn->call_dest for sibling calls so we can know +who we're calling. This is useful information when printing validation +warnings later. + +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Josh Poimboeuf +Cc: Borislav Petkov +Cc: Linus Torvalds +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Signed-off-by: Ingo Molnar +Acked-by: Miroslav Benes +--- + tools/objtool/check.c | 86 ++++++++++++++++++++++++++++++++------------------- + 1 file changed, 55 insertions(+), 31 deletions(-) + +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index 5264a305d658..8118361295dd 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -515,7 +515,8 @@ static int add_jump_destinations(struct objtool_file *file) + continue; + } else { + /* sibling call */ +- insn->jump_dest = 0; ++ insn->call_dest = rela->sym; ++ insn->jump_dest = NULL; + continue; + } + +@@ -537,25 +538,38 @@ static int add_jump_destinations(struct objtool_file *file) + } + + /* +- * For GCC 8+, create parent/child links for any cold +- * subfunctions. This is _mostly_ redundant with a similar +- * initialization in read_symbols(). +- * +- * If a function has aliases, we want the *first* such function +- * in the symbol table to be the subfunction's parent. In that +- * case we overwrite the initialization done in read_symbols(). +- * +- * However this code can't completely replace the +- * read_symbols() code because this doesn't detect the case +- * where the parent function's only reference to a subfunction +- * is through a switch table. ++ * Cross-function jump. + */ + if (insn->func && insn->jump_dest->func && +- insn->func != insn->jump_dest->func && +- !strstr(insn->func->name, ".cold.") && +- strstr(insn->jump_dest->func->name, ".cold.")) { +- insn->func->cfunc = insn->jump_dest->func; +- insn->jump_dest->func->pfunc = insn->func; ++ insn->func != insn->jump_dest->func) { ++ ++ /* ++ * For GCC 8+, create parent/child links for any cold ++ * subfunctions. This is _mostly_ redundant with a ++ * similar initialization in read_symbols(). ++ * ++ * If a function has aliases, we want the *first* such ++ * function in the symbol table to be the subfunction's ++ * parent. In that case we overwrite the ++ * initialization done in read_symbols(). ++ * ++ * However this code can't completely replace the ++ * read_symbols() code because this doesn't detect the ++ * case where the parent function's only reference to a ++ * subfunction is through a switch table. ++ */ ++ if (!strstr(insn->func->name, ".cold.") && ++ strstr(insn->jump_dest->func->name, ".cold.")) { ++ insn->func->cfunc = insn->jump_dest->func; ++ insn->jump_dest->func->pfunc = insn->func; ++ ++ } else if (insn->jump_dest->func->pfunc != insn->func->pfunc && ++ insn->jump_dest->offset == insn->jump_dest->func->offset) { ++ ++ /* sibling class */ ++ insn->call_dest = insn->jump_dest->func; ++ insn->jump_dest = NULL; ++ } + } + } + +@@ -1785,6 +1799,17 @@ static bool insn_state_match(struct instruction *insn, struct insn_state *state) + return false; + } + ++static int validate_sibling_call(struct instruction *insn, struct insn_state *state) ++{ ++ if (has_modified_stack_frame(state)) { ++ WARN_FUNC("sibling call from callable instruction with modified stack frame", ++ insn->sec, insn->offset); ++ return 1; ++ } ++ ++ return 0; ++} ++ + /* + * Follow the branch starting at the given instruction, and recursively follow + * any other branches (jumps). Meanwhile, track the frame pointer state at +@@ -1935,9 +1960,14 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, + + case INSN_JUMP_CONDITIONAL: + case INSN_JUMP_UNCONDITIONAL: +- if (insn->jump_dest && +- (!func || !insn->jump_dest->func || +- insn->jump_dest->func->pfunc == func)) { ++ if (func && !insn->jump_dest) { ++ ret = validate_sibling_call(insn, &state); ++ if (ret) ++ return ret; ++ ++ } else if (insn->jump_dest && ++ (!func || !insn->jump_dest->func || ++ insn->jump_dest->func->pfunc == func)) { + ret = validate_branch(file, insn->jump_dest, + state); + if (ret) { +@@ -1945,11 +1975,6 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, + BT_FUNC("(branch)", insn); + return ret; + } +- +- } else if (func && has_modified_stack_frame(&state)) { +- WARN_FUNC("sibling call from callable instruction with modified stack frame", +- sec, insn->offset); +- return 1; + } + + if (insn->type == INSN_JUMP_UNCONDITIONAL) +@@ -1958,11 +1983,10 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, + break; + + case INSN_JUMP_DYNAMIC: +- if (func && list_empty(&insn->alts) && +- has_modified_stack_frame(&state)) { +- WARN_FUNC("sibling call from callable instruction with modified stack frame", +- sec, insn->offset); +- return 1; ++ if (func && list_empty(&insn->alts)) { ++ ret = validate_sibling_call(insn, &state); ++ if (ret) ++ return ret; + } + + return 0; + diff --git a/patches.suse/objtool-Make-handle_insn_ops-unconditional.patch b/patches.suse/objtool-Make-handle_insn_ops-unconditional.patch new file mode 100644 index 0000000..f408e2e --- /dev/null +++ b/patches.suse/objtool-Make-handle_insn_ops-unconditional.patch @@ -0,0 +1,46 @@ +From: Peter Zijlstra +Date: Fri, 24 Apr 2020 16:16:41 +0200 +Subject: objtool: Make handle_insn_ops() unconditional +Git-commit: 60041bcd8f5ab560dabf44dc384f58bbeb5a6a30 +Patch-mainline: v5.8-rc1 +References: bsc#1202396 + +Now that every instruction has a list of stack_ops; we can trivially +distinquish those instructions that do not have stack_ops, their list +is empty. + +This means we can now call handle_insn_ops() unconditionally. + +Suggested-by: Julien Thierry +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Miroslav Benes +Acked-by: Josh Poimboeuf +Link: https://lkml.kernel.org/r/20200428191659.795115188@infradead.org + +Acked-by: Miroslav Benes +--- + tools/objtool/check.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -1972,6 +1972,9 @@ static int validate_branch(struct objtoo + return 0; + } + ++ if (handle_insn_ops(insn, &state)) ++ return 1; ++ + switch (insn->type) { + + case INSN_RETURN: +@@ -2054,9 +2057,6 @@ static int validate_branch(struct objtoo + return 0; + + case INSN_STACK: +- if (handle_insn_ops(insn, &state)) +- return 1; +- + break; + + default: diff --git a/patches.suse/objtool-Remove-INSN_STACK.patch b/patches.suse/objtool-Remove-INSN_STACK.patch new file mode 100644 index 0000000..ee7454f --- /dev/null +++ b/patches.suse/objtool-Remove-INSN_STACK.patch @@ -0,0 +1,231 @@ +From: Peter Zijlstra +Date: Fri, 24 Apr 2020 16:18:58 +0200 +Subject: objtool: Remove INSN_STACK +Git-commit: b09fb65e863733e192d4825a285b4b4998969ce0 +Patch-mainline: v5.8-rc1 +References: bsc#1202396 + +With the unconditional use of handle_insn_ops(), INSN_STACK has lost +its purpose. Remove it. + +Suggested-by: Julien Thierry +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Miroslav Benes +Acked-by: Josh Poimboeuf +Link: https://lkml.kernel.org/r/20200428191659.854203028@infradead.org + +Acked-by: Miroslav Benes +--- + tools/objtool/arch.h | 1 - + tools/objtool/arch/x86/decode.c | 23 ----------------------- + tools/objtool/check.c | 3 --- + 3 files changed, 27 deletions(-) + +--- a/tools/objtool/arch.h ++++ b/tools/objtool/arch.h +@@ -32,7 +32,6 @@ enum insn_type { + INSN_CALL_DYNAMIC, + INSN_RETURN, + INSN_CONTEXT_SWITCH, +- INSN_STACK, + INSN_BUG, + INSN_NOP, + INSN_OTHER, +--- a/tools/objtool/arch/x86/decode.c ++++ b/tools/objtool/arch/x86/decode.c +@@ -142,7 +142,6 @@ int arch_decode_instruction(struct elf * + if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { + + /* add/sub reg, %rsp */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_ADD; + op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; +@@ -155,7 +154,6 @@ int arch_decode_instruction(struct elf * + case 0x50 ... 0x57: + + /* push reg */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_REG; + op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; +@@ -167,7 +165,6 @@ int arch_decode_instruction(struct elf * + case 0x58 ... 0x5f: + + /* pop reg */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_POP; + op->dest.type = OP_DEST_REG; +@@ -179,7 +176,6 @@ int arch_decode_instruction(struct elf * + case 0x68: + case 0x6a: + /* push immediate */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_CONST; + op->dest.type = OP_DEST_PUSH; +@@ -197,7 +193,6 @@ int arch_decode_instruction(struct elf * + + if (modrm == 0xe4) { + /* and imm, %rsp */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_AND; + op->src.reg = CFI_SP; +@@ -216,7 +211,6 @@ int arch_decode_instruction(struct elf * + break; + + /* add/sub imm, %rsp */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_ADD; + op->src.reg = CFI_SP; +@@ -230,7 +224,6 @@ int arch_decode_instruction(struct elf * + if (rex_w && !rex_r && modrm_mod == 3 && modrm_reg == 4) { + + /* mov %rsp, reg */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_REG; + op->src.reg = CFI_SP; +@@ -243,7 +236,6 @@ int arch_decode_instruction(struct elf * + if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { + + /* mov reg, %rsp */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_REG; + op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; +@@ -259,7 +251,6 @@ int arch_decode_instruction(struct elf * + (modrm_mod == 1 || modrm_mod == 2) && modrm_rm == 5) { + + /* mov reg, disp(%rbp) */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_REG; + op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; +@@ -271,7 +262,6 @@ int arch_decode_instruction(struct elf * + } else if (rex_w && !rex_b && modrm_rm == 4 && sib == 0x24) { + + /* mov reg, disp(%rsp) */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_REG; + op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; +@@ -287,7 +277,6 @@ int arch_decode_instruction(struct elf * + if (rex_w && !rex_b && modrm_mod == 1 && modrm_rm == 5) { + + /* mov disp(%rbp), reg */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_REG_INDIRECT; + op->src.reg = CFI_BP; +@@ -300,7 +289,6 @@ int arch_decode_instruction(struct elf * + modrm_mod != 3 && modrm_rm == 4) { + + /* mov disp(%rsp), reg */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_REG_INDIRECT; + op->src.reg = CFI_SP; +@@ -315,7 +303,6 @@ int arch_decode_instruction(struct elf * + case 0x8d: + if (sib == 0x24 && rex_w && !rex_b && !rex_x) { + +- *type = INSN_STACK; + ADD_OP(op) { + if (!insn.displacement.value) { + /* lea (%rsp), reg */ +@@ -333,7 +320,6 @@ int arch_decode_instruction(struct elf * + } else if (rex == 0x48 && modrm == 0x65) { + + /* lea disp(%rbp), %rsp */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_ADD; + op->src.reg = CFI_BP; +@@ -351,7 +337,6 @@ int arch_decode_instruction(struct elf * + * Restoring rsp back to its original value after a + * stack realignment. + */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_ADD; + op->src.reg = CFI_R10; +@@ -369,7 +354,6 @@ int arch_decode_instruction(struct elf * + * Restoring rsp back to its original value after a + * stack realignment. + */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_ADD; + op->src.reg = CFI_R13; +@@ -383,7 +367,6 @@ int arch_decode_instruction(struct elf * + + case 0x8f: + /* pop to mem */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_POP; + op->dest.type = OP_DEST_MEM; +@@ -396,7 +379,6 @@ int arch_decode_instruction(struct elf * + + case 0x9c: + /* pushf */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_CONST; + op->dest.type = OP_DEST_PUSH; +@@ -405,7 +387,6 @@ int arch_decode_instruction(struct elf * + + case 0x9d: + /* popf */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_POP; + op->dest.type = OP_DEST_MEM; +@@ -437,7 +418,6 @@ int arch_decode_instruction(struct elf * + } else if (op2 == 0xa0 || op2 == 0xa8) { + + /* push fs/gs */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_CONST; + op->dest.type = OP_DEST_PUSH; +@@ -446,7 +426,6 @@ int arch_decode_instruction(struct elf * + } else if (op2 == 0xa1 || op2 == 0xa9) { + + /* pop fs/gs */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_POP; + op->dest.type = OP_DEST_MEM; +@@ -463,7 +442,6 @@ int arch_decode_instruction(struct elf * + * mov bp, sp + * pop bp + */ +- *type = INSN_STACK; + ADD_OP(op) + op->dest.type = OP_DEST_LEAVE; + +@@ -511,7 +489,6 @@ int arch_decode_instruction(struct elf * + else if (modrm_reg == 6) { + + /* push from mem */ +- *type = INSN_STACK; + ADD_OP(op) { + op->src.type = OP_SRC_CONST; + op->dest.type = OP_DEST_PUSH; +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -2056,9 +2056,6 @@ static int validate_branch(struct objtoo + } + return 0; + +- case INSN_STACK: +- break; +- + default: + break; + } diff --git a/patches.suse/objtool-Remove-check-preventing-branches-within-alternative.patch b/patches.suse/objtool-Remove-check-preventing-branches-within-alternative.patch new file mode 100644 index 0000000..69ef4f3 --- /dev/null +++ b/patches.suse/objtool-Remove-check-preventing-branches-within-alternative.patch @@ -0,0 +1,42 @@ +From: Julien Thierry +Date: Fri, 27 Mar 2020 15:28:42 +0000 +Subject: objtool: Remove check preventing branches within alternative +Git-commit: 9e98d62aa7ea1375052895650f3e6d362336c5c9 +Patch-mainline: v5.8-rc1 +References: bsc#1202396 + +While jumping from outside an alternative region to the middle of an +alternative region is very likely wrong, jumping from an alternative +region into the same region is valid. It is a common pattern on arm64. + +The first pattern is unlikely to happen in practice and checking only +for this adds a lot of complexity. + +Just remove the current check. + +Suggested-by: Josh Poimboeuf +Signed-off-by: Julien Thierry +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Miroslav Benes +Link: https://lkml.kernel.org/r/20200327152847.15294-6-jthierry@redhat.com + +Acked-by: Miroslav Benes +--- + tools/objtool/check.c | 6 ------ + 1 file changed, 6 deletions(-) + +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -1850,12 +1850,6 @@ static int validate_branch(struct objtoo + insn = first; + sec = insn->sec; + +- if (insn->alt_group && list_empty(&insn->alts)) { +- WARN_FUNC("don't know how to handle branch to middle of alternative instruction group", +- sec, insn->offset); +- return 1; +- } +- + while (1) { + next_insn = next_insn_same_sec(file, insn); + diff --git a/patches.suse/objtool-Rename-elf_open-to-prevent-conflict-with-libelf-from-elftoolchain.patch b/patches.suse/objtool-Rename-elf_open-to-prevent-conflict-with-libelf-from-elftoolchain.patch new file mode 100644 index 0000000..ad8492b --- /dev/null +++ b/patches.suse/objtool-Rename-elf_open-to-prevent-conflict-with-libelf-from-elftoolchain.patch @@ -0,0 +1,67 @@ +From: Michael Forney +Date: Wed, 10 Jul 2019 16:20:11 -0500 +Subject: objtool: Rename elf_open() to prevent conflict with libelf from + elftoolchain +Git-commit: 8e144797f1a67c52e386161863da4614a23ad913 +Patch-mainline: v5.3-rc1 +References: bsc#1202396 + +The elftoolchain version of libelf has a function named elf_open(). + +The function name isn't quite accurate anyway, since it also reads all +the ELF data. Rename it to elf_read(), which is more accurate. + +[ jpoimboe: rename to elf_read(); write commit description ] + +Signed-off-by: Michael Forney +Signed-off-by: Josh Poimboeuf +Signed-off-by: Thomas Gleixner +Link: https://lkml.kernel.org/r/7ce2d1b35665edf19fd0eb6fbc0b17b81a48e62f.1562793604.git.jpoimboe@redhat.com + +Acked-by: Miroslav Benes +--- + tools/objtool/check.c | 2 +- + tools/objtool/elf.c | 2 +- + tools/objtool/elf.h | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index 172f99195726..de8f40730b37 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -2407,7 +2407,7 @@ int check(const char *_objname, bool orc) + + objname = _objname; + +- file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY); ++ file.elf = elf_read(objname, orc ? O_RDWR : O_RDONLY); + if (!file.elf) + return 1; + +diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c +index 76e4f7ceab82..e18698262837 100644 +--- a/tools/objtool/elf.c ++++ b/tools/objtool/elf.c +@@ -401,7 +401,7 @@ static int read_relas(struct elf *elf) + return 0; + } + +-struct elf *elf_open(const char *name, int flags) ++struct elf *elf_read(const char *name, int flags) + { + struct elf *elf; + Elf_Cmd cmd; +diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h +index e44ca5d51871..2fe0b0aa741d 100644 +--- a/tools/objtool/elf.h ++++ b/tools/objtool/elf.h +@@ -74,7 +74,7 @@ struct elf { + }; + + +-struct elf *elf_open(const char *name, int flags); ++struct elf *elf_read(const char *name, int flags); + struct section *find_section_by_name(struct elf *elf, const char *name); + struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); + struct symbol *find_symbol_by_name(struct elf *elf, const char *name); + diff --git a/patches.suse/objtool-Rename-struct-cfi_state.patch b/patches.suse/objtool-Rename-struct-cfi_state.patch new file mode 100644 index 0000000..f16444b --- /dev/null +++ b/patches.suse/objtool-Rename-struct-cfi_state.patch @@ -0,0 +1,68 @@ +From: Peter Zijlstra +Date: Wed, 25 Mar 2020 15:34:50 +0100 +Subject: objtool: Rename struct cfi_state +Git-commit: a3608f5954d07a40fb93764dc6d06195fa52eb14 +Patch-mainline: v5.8-rc1 +References: bsc#1202396 + +There's going to be a new struct cfi_state, rename this one to make +place. + +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Miroslav Benes +Reviewed-by: Alexandre Chartre +Acked-by: Josh Poimboeuf +Link: https://lkml.kernel.org/r/20200416115118.986441913@infradead.org +Signed-off-by: Ingo Molnar +Acked-by: Miroslav Benes +--- + tools/objtool/arch.h | 2 +- + tools/objtool/arch/x86/decode.c | 2 +- + tools/objtool/cfi.h | 2 +- + tools/objtool/check.c | 2 +- + 4 files changed, 4 insertions(+), 4 deletions(-) + +--- a/tools/objtool/arch.h ++++ b/tools/objtool/arch.h +@@ -73,7 +73,7 @@ struct stack_op { + struct list_head list; + }; + +-void arch_initial_func_cfi_state(struct cfi_state *state); ++void arch_initial_func_cfi_state(struct cfi_init_state *state); + + int arch_decode_instruction(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int maxlen, +--- a/tools/objtool/arch/x86/decode.c ++++ b/tools/objtool/arch/x86/decode.c +@@ -488,7 +488,7 @@ int arch_decode_instruction(struct elf * + return 0; + } + +-void arch_initial_func_cfi_state(struct cfi_state *state) ++void arch_initial_func_cfi_state(struct cfi_init_state *state) + { + int i; + +--- a/tools/objtool/cfi.h ++++ b/tools/objtool/cfi.h +@@ -47,7 +47,7 @@ struct cfi_reg { + int offset; + }; + +-struct cfi_state { ++struct cfi_init_state { + struct cfi_reg cfa; + struct cfi_reg regs[CFI_NUM_REGS]; + }; +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -37,7 +37,7 @@ struct alternative { + }; + + const char *objname; +-struct cfi_state initial_func_cfi; ++struct cfi_init_state initial_func_cfi; + + struct instruction *find_insn(struct objtool_file *file, + struct section *sec, unsigned long offset) diff --git a/patches.suse/objtool-Rework-allocating-stack_ops-on-decode.patch b/patches.suse/objtool-Rework-allocating-stack_ops-on-decode.patch new file mode 100644 index 0000000..e680451 --- /dev/null +++ b/patches.suse/objtool-Rework-allocating-stack_ops-on-decode.patch @@ -0,0 +1,442 @@ +From: Peter Zijlstra +Date: Thu, 23 Apr 2020 13:22:10 +0200 +Subject: objtool: Rework allocating stack_ops on decode +Git-commit: 7d989fcadd6e225a61d6490dd15bdbdfc8a53d5c +Patch-mainline: v5.8-rc1 +References: bsc#1202396 + +Wrap each stack_op in a macro that allocates and adds it to the list. +This simplifies trying to figure out what to do with the pre-allocated +stack_op at the end. + +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Alexandre Chartre +Reviewed-by: Miroslav Benes +Acked-by: Josh Poimboeuf +Link: https://lkml.kernel.org/r/20200428191659.736151601@infradead.org + +Acked-by: Miroslav Benes +--- + tools/objtool/arch/x86/decode.c | 237 +++++++++++++++++++++++----------------- + 1 file changed, 139 insertions(+), 98 deletions(-) + +--- a/tools/objtool/arch/x86/decode.c ++++ b/tools/objtool/arch/x86/decode.c +@@ -78,6 +78,11 @@ bool arch_callee_saved_reg(unsigned char + } + } + ++#define ADD_OP(op) \ ++ if (!(op = calloc(1, sizeof(*op)))) \ ++ return -1; \ ++ else for (list_add_tail(&op->list, ops_list); op; op = NULL) ++ + int arch_decode_instruction(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int maxlen, + unsigned int *len, enum insn_type *type, +@@ -89,7 +94,7 @@ int arch_decode_instruction(struct elf * + unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, + rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0, + modrm_reg = 0, sib = 0; +- struct stack_op *op; ++ struct stack_op *op = NULL; + + x86_64 = is_x86_64(elf); + if (x86_64 == -1) +@@ -130,10 +135,6 @@ int arch_decode_instruction(struct elf * + if (insn.sib.nbytes) + sib = insn.sib.bytes[0]; + +- op = calloc(1, sizeof(*op)); +- if (!op) +- return -1; +- + switch (op1) { + + case 0x1: +@@ -142,10 +143,12 @@ int arch_decode_instruction(struct elf * + + /* add/sub reg, %rsp */ + *type = INSN_STACK; +- op->src.type = OP_SRC_ADD; +- op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; +- op->dest.type = OP_DEST_REG; +- op->dest.reg = CFI_SP; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_ADD; ++ op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = CFI_SP; ++ } + } + break; + +@@ -153,9 +156,11 @@ int arch_decode_instruction(struct elf * + + /* push reg */ + *type = INSN_STACK; +- op->src.type = OP_SRC_REG; +- op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; +- op->dest.type = OP_DEST_PUSH; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_REG; ++ op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; ++ op->dest.type = OP_DEST_PUSH; ++ } + + break; + +@@ -163,9 +168,11 @@ int arch_decode_instruction(struct elf * + + /* pop reg */ + *type = INSN_STACK; +- op->src.type = OP_SRC_POP; +- op->dest.type = OP_DEST_REG; +- op->dest.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_POP; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; ++ } + + break; + +@@ -173,8 +180,10 @@ int arch_decode_instruction(struct elf * + case 0x6a: + /* push immediate */ + *type = INSN_STACK; +- op->src.type = OP_SRC_CONST; +- op->dest.type = OP_DEST_PUSH; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_CONST; ++ op->dest.type = OP_DEST_PUSH; ++ } + break; + + case 0x70 ... 0x7f: +@@ -189,11 +198,13 @@ int arch_decode_instruction(struct elf * + if (modrm == 0xe4) { + /* and imm, %rsp */ + *type = INSN_STACK; +- op->src.type = OP_SRC_AND; +- op->src.reg = CFI_SP; +- op->src.offset = insn.immediate.value; +- op->dest.type = OP_DEST_REG; +- op->dest.reg = CFI_SP; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_AND; ++ op->src.reg = CFI_SP; ++ op->src.offset = insn.immediate.value; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = CFI_SP; ++ } + break; + } + +@@ -206,11 +217,13 @@ int arch_decode_instruction(struct elf * + + /* add/sub imm, %rsp */ + *type = INSN_STACK; +- op->src.type = OP_SRC_ADD; +- op->src.reg = CFI_SP; +- op->src.offset = insn.immediate.value * sign; +- op->dest.type = OP_DEST_REG; +- op->dest.reg = CFI_SP; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_ADD; ++ op->src.reg = CFI_SP; ++ op->src.offset = insn.immediate.value * sign; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = CFI_SP; ++ } + break; + + case 0x89: +@@ -218,10 +231,12 @@ int arch_decode_instruction(struct elf * + + /* mov %rsp, reg */ + *type = INSN_STACK; +- op->src.type = OP_SRC_REG; +- op->src.reg = CFI_SP; +- op->dest.type = OP_DEST_REG; +- op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b]; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_REG; ++ op->src.reg = CFI_SP; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b]; ++ } + break; + } + +@@ -229,10 +244,12 @@ int arch_decode_instruction(struct elf * + + /* mov reg, %rsp */ + *type = INSN_STACK; +- op->src.type = OP_SRC_REG; +- op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; +- op->dest.type = OP_DEST_REG; +- op->dest.reg = CFI_SP; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_REG; ++ op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = CFI_SP; ++ } + break; + } + +@@ -243,21 +260,25 @@ int arch_decode_instruction(struct elf * + + /* mov reg, disp(%rbp) */ + *type = INSN_STACK; +- op->src.type = OP_SRC_REG; +- op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; +- op->dest.type = OP_DEST_REG_INDIRECT; +- op->dest.reg = CFI_BP; +- op->dest.offset = insn.displacement.value; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_REG; ++ op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ op->dest.type = OP_DEST_REG_INDIRECT; ++ op->dest.reg = CFI_BP; ++ op->dest.offset = insn.displacement.value; ++ } + + } else if (rex_w && !rex_b && modrm_rm == 4 && sib == 0x24) { + + /* mov reg, disp(%rsp) */ + *type = INSN_STACK; +- op->src.type = OP_SRC_REG; +- op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; +- op->dest.type = OP_DEST_REG_INDIRECT; +- op->dest.reg = CFI_SP; +- op->dest.offset = insn.displacement.value; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_REG; ++ op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ op->dest.type = OP_DEST_REG_INDIRECT; ++ op->dest.reg = CFI_SP; ++ op->dest.offset = insn.displacement.value; ++ } + } + + break; +@@ -267,22 +288,26 @@ int arch_decode_instruction(struct elf * + + /* mov disp(%rbp), reg */ + *type = INSN_STACK; +- op->src.type = OP_SRC_REG_INDIRECT; +- op->src.reg = CFI_BP; +- op->src.offset = insn.displacement.value; +- op->dest.type = OP_DEST_REG; +- op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_REG_INDIRECT; ++ op->src.reg = CFI_BP; ++ op->src.offset = insn.displacement.value; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ } + + } else if (rex_w && !rex_b && sib == 0x24 && + modrm_mod != 3 && modrm_rm == 4) { + + /* mov disp(%rsp), reg */ + *type = INSN_STACK; +- op->src.type = OP_SRC_REG_INDIRECT; +- op->src.reg = CFI_SP; +- op->src.offset = insn.displacement.value; +- op->dest.type = OP_DEST_REG; +- op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_REG_INDIRECT; ++ op->src.reg = CFI_SP; ++ op->src.offset = insn.displacement.value; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; ++ } + } + + break; +@@ -291,27 +316,31 @@ int arch_decode_instruction(struct elf * + if (sib == 0x24 && rex_w && !rex_b && !rex_x) { + + *type = INSN_STACK; +- if (!insn.displacement.value) { +- /* lea (%rsp), reg */ +- op->src.type = OP_SRC_REG; +- } else { +- /* lea disp(%rsp), reg */ +- op->src.type = OP_SRC_ADD; +- op->src.offset = insn.displacement.value; ++ ADD_OP(op) { ++ if (!insn.displacement.value) { ++ /* lea (%rsp), reg */ ++ op->src.type = OP_SRC_REG; ++ } else { ++ /* lea disp(%rsp), reg */ ++ op->src.type = OP_SRC_ADD; ++ op->src.offset = insn.displacement.value; ++ } ++ op->src.reg = CFI_SP; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; + } +- op->src.reg = CFI_SP; +- op->dest.type = OP_DEST_REG; +- op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; + + } else if (rex == 0x48 && modrm == 0x65) { + + /* lea disp(%rbp), %rsp */ + *type = INSN_STACK; +- op->src.type = OP_SRC_ADD; +- op->src.reg = CFI_BP; +- op->src.offset = insn.displacement.value; +- op->dest.type = OP_DEST_REG; +- op->dest.reg = CFI_SP; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_ADD; ++ op->src.reg = CFI_BP; ++ op->src.offset = insn.displacement.value; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = CFI_SP; ++ } + + } else if (rex == 0x49 && modrm == 0x62 && + insn.displacement.value == -8) { +@@ -323,11 +352,13 @@ int arch_decode_instruction(struct elf * + * stack realignment. + */ + *type = INSN_STACK; +- op->src.type = OP_SRC_ADD; +- op->src.reg = CFI_R10; +- op->src.offset = -8; +- op->dest.type = OP_DEST_REG; +- op->dest.reg = CFI_SP; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_ADD; ++ op->src.reg = CFI_R10; ++ op->src.offset = -8; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = CFI_SP; ++ } + + } else if (rex == 0x49 && modrm == 0x65 && + insn.displacement.value == -16) { +@@ -339,11 +370,13 @@ int arch_decode_instruction(struct elf * + * stack realignment. + */ + *type = INSN_STACK; +- op->src.type = OP_SRC_ADD; +- op->src.reg = CFI_R13; +- op->src.offset = -16; +- op->dest.type = OP_DEST_REG; +- op->dest.reg = CFI_SP; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_ADD; ++ op->src.reg = CFI_R13; ++ op->src.offset = -16; ++ op->dest.type = OP_DEST_REG; ++ op->dest.reg = CFI_SP; ++ } + } + + break; +@@ -351,8 +384,10 @@ int arch_decode_instruction(struct elf * + case 0x8f: + /* pop to mem */ + *type = INSN_STACK; +- op->src.type = OP_SRC_POP; +- op->dest.type = OP_DEST_MEM; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_POP; ++ op->dest.type = OP_DEST_MEM; ++ } + break; + + case 0x90: +@@ -362,15 +397,19 @@ int arch_decode_instruction(struct elf * + case 0x9c: + /* pushf */ + *type = INSN_STACK; +- op->src.type = OP_SRC_CONST; +- op->dest.type = OP_DEST_PUSH; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_CONST; ++ op->dest.type = OP_DEST_PUSH; ++ } + break; + + case 0x9d: + /* popf */ + *type = INSN_STACK; +- op->src.type = OP_SRC_POP; +- op->dest.type = OP_DEST_MEM; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_POP; ++ op->dest.type = OP_DEST_MEM; ++ } + break; + + case 0x0f: +@@ -399,15 +438,19 @@ int arch_decode_instruction(struct elf * + + /* push fs/gs */ + *type = INSN_STACK; +- op->src.type = OP_SRC_CONST; +- op->dest.type = OP_DEST_PUSH; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_CONST; ++ op->dest.type = OP_DEST_PUSH; ++ } + + } else if (op2 == 0xa1 || op2 == 0xa9) { + + /* pop fs/gs */ + *type = INSN_STACK; +- op->src.type = OP_SRC_POP; +- op->dest.type = OP_DEST_MEM; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_POP; ++ op->dest.type = OP_DEST_MEM; ++ } + } + + break; +@@ -421,7 +464,8 @@ int arch_decode_instruction(struct elf * + * pop bp + */ + *type = INSN_STACK; +- op->dest.type = OP_DEST_LEAVE; ++ ADD_OP(op) ++ op->dest.type = OP_DEST_LEAVE; + + break; + +@@ -468,8 +512,10 @@ int arch_decode_instruction(struct elf * + + /* push from mem */ + *type = INSN_STACK; +- op->src.type = OP_SRC_CONST; +- op->dest.type = OP_DEST_PUSH; ++ ADD_OP(op) { ++ op->src.type = OP_SRC_CONST; ++ op->dest.type = OP_DEST_PUSH; ++ } + } + + break; +@@ -480,11 +526,6 @@ int arch_decode_instruction(struct elf * + + *immediate = insn.immediate.nbytes ? insn.immediate.value : 0; + +- if (*type == INSN_STACK) +- list_add_tail(&op->list, ops_list); +- else +- free(op); +- + return 0; + } + diff --git a/patches.suse/objtool-Rewrite-alt-skip_orig.patch b/patches.suse/objtool-Rewrite-alt-skip_orig.patch new file mode 100644 index 0000000..a991943 --- /dev/null +++ b/patches.suse/objtool-Rewrite-alt-skip_orig.patch @@ -0,0 +1,89 @@ +From: Peter Zijlstra +Date: Fri, 1 Mar 2019 11:19:03 +0100 +Subject: objtool: Rewrite alt->skip_orig +Git-commit: 764eef4b109ae11e6c987de9c14fc7c482041be0 +Patch-mainline: v5.2-rc1 +References: bsc#1202396 + +Really skip the original instruction flow, instead of letting it +continue with NOPs. + +Since the alternative code flow already continues after the original +instructions, only the alt-original is skipped. + +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Josh Poimboeuf +Cc: Borislav Petkov +Cc: Linus Torvalds +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Signed-off-by: Ingo Molnar +Acked-by: Miroslav Benes +--- + tools/objtool/check.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index ccc66af5907f..5264a305d658 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -31,6 +31,7 @@ + struct alternative { + struct list_head list; + struct instruction *insn; ++ bool skip_orig; + }; + + const char *objname; +@@ -623,9 +624,6 @@ static int add_call_destinations(struct objtool_file *file) + * conditionally jumps to the _end_ of the entry. We have to modify these + * jumps' destinations to point back to .text rather than the end of the + * entry in .altinstr_replacement. +- * +- * 4. It has been requested that we don't validate the !POPCNT feature path +- * which is a "very very small percentage of machines". + */ + static int handle_group_alt(struct objtool_file *file, + struct special_alt *special_alt, +@@ -641,9 +639,6 @@ static int handle_group_alt(struct objtool_file *file, + if (insn->offset >= special_alt->orig_off + special_alt->orig_len) + break; + +- if (special_alt->skip_orig) +- insn->type = INSN_NOP; +- + insn->alt_group = true; + last_orig_insn = insn; + } +@@ -808,6 +803,7 @@ static int add_special_section_alts(struct objtool_file *file) + } + + alt->insn = new_insn; ++ alt->skip_orig = special_alt->skip_orig; + list_add_tail(&alt->list, &orig_insn->alts); + + list_del(&special_alt->list); +@@ -1883,7 +1879,12 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, + insn->visited = true; + + if (!insn->ignore_alts) { ++ bool skip_orig = false; ++ + list_for_each_entry(alt, &insn->alts, list) { ++ if (alt->skip_orig) ++ skip_orig = true; ++ + ret = validate_branch(file, alt->insn, state); + if (ret) { + if (backtrace) +@@ -1891,6 +1892,9 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, + return ret; + } + } ++ ++ if (skip_orig) ++ return 0; + } + + switch (insn->type) { + diff --git a/patches.suse/objtool-Set-insn-func-for-alternatives.patch b/patches.suse/objtool-Set-insn-func-for-alternatives.patch new file mode 100644 index 0000000..9765e9e --- /dev/null +++ b/patches.suse/objtool-Set-insn-func-for-alternatives.patch @@ -0,0 +1,38 @@ +From: Peter Zijlstra +Date: Mon, 25 Feb 2019 10:31:24 +0100 +Subject: objtool: Set insn->func for alternatives +Git-commit: a4d09dde9093a04a9b48fb9e5ef3177bdfaff199 +Patch-mainline: v5.2-rc1 +References: bsc#1202396 + +In preparation of function attributes, we need each instruction to +have a valid link back to its function. + +Therefore make sure we set the function association for alternative +instruction sequences; they are, after all, still part of the function. + +Signed-off-by: Peter Zijlstra (Intel) +Acked-by: Josh Poimboeuf +Cc: Borislav Petkov +Cc: Linus Torvalds +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Signed-off-by: Ingo Molnar +Acked-by: Miroslav Benes +--- + tools/objtool/check.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index 110ea3d84772..950d0f62d22b 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -695,6 +695,7 @@ static int handle_group_alt(struct objtool_file *file, + last_new_insn = insn; + + insn->ignore = orig_insn->ignore_alts; ++ insn->func = orig_insn->func; + + if (insn->type != INSN_JUMP_CONDITIONAL && + insn->type != INSN_JUMP_UNCONDITIONAL) + diff --git a/patches.suse/objtool-Support-conditional-retpolines.patch b/patches.suse/objtool-Support-conditional-retpolines.patch new file mode 100644 index 0000000..dc616e2 --- /dev/null +++ b/patches.suse/objtool-Support-conditional-retpolines.patch @@ -0,0 +1,79 @@ +From: Josh Poimboeuf +Date: Wed, 17 Jul 2019 20:36:57 -0500 +Subject: objtool: Support conditional retpolines +Git-commit: b68b9907069a8d3a65bc16a35360bf8f8603c8fa +Patch-mainline: v5.3-rc1 +References: bsc#1202396 + +A Clang-built kernel is showing the following warning: + + arch/x86/kernel/platform-quirks.o: warning: objtool: x86_early_init_platform_quirks()+0x84: unreachable instruction + +That corresponds to this code: + + 7e: 0f 85 00 00 00 00 jne 84 + 80: R_X86_64_PC32 __x86_indirect_thunk_r11-0x4 + 84: c3 retq + +This is a conditional retpoline sibling call, which is now possible +thanks to retpolines. Objtool hasn't seen that before. It's +incorrectly interpreting the conditional jump as an unconditional +dynamic jump. + +Reported-by: Nick Desaulniers +Signed-off-by: Josh Poimboeuf +Signed-off-by: Thomas Gleixner +Tested-by: Nick Desaulniers +Acked-by: Peter Zijlstra (Intel) +Link: https://lkml.kernel.org/r/30d4c758b267ef487fb97e6ecb2f148ad007b554.1563413318.git.jpoimboe@redhat.com + +Acked-by: Miroslav Benes +--- + tools/objtool/arch.h | 1 + + tools/objtool/check.c | 12 ++++++++++-- + 2 files changed, 11 insertions(+), 2 deletions(-) + +--- a/tools/objtool/arch.h ++++ b/tools/objtool/arch.h +@@ -27,6 +27,7 @@ enum insn_type { + INSN_JUMP_CONDITIONAL, + INSN_JUMP_UNCONDITIONAL, + INSN_JUMP_DYNAMIC, ++ INSN_JUMP_DYNAMIC_CONDITIONAL, + INSN_CALL, + INSN_CALL_DYNAMIC, + INSN_RETURN, +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -514,7 +514,11 @@ static int add_jump_destinations(struct + * Retpoline jumps are really dynamic jumps in + * disguise, so convert them accordingly. + */ +- insn->type = INSN_JUMP_DYNAMIC; ++ if (insn->type == INSN_JUMP_UNCONDITIONAL) ++ insn->type = INSN_JUMP_DYNAMIC; ++ else ++ insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL; ++ + insn->retpoline_safe = true; + continue; + } else { +@@ -1945,13 +1949,17 @@ static int validate_branch(struct objtoo + break; + + case INSN_JUMP_DYNAMIC: ++ case INSN_JUMP_DYNAMIC_CONDITIONAL: + if (func && list_empty(&insn->alts)) { + ret = validate_sibling_call(insn, &state); + if (ret) + return ret; + } + +- return 0; ++ if (insn->type == INSN_JUMP_DYNAMIC) ++ return 0; ++ ++ break; + + case INSN_CONTEXT_SWITCH: + if (func && (!next_insn || !next_insn->hint)) { diff --git a/patches.suse/objtool-Support-multiple-stack_op-per-instruction.patch b/patches.suse/objtool-Support-multiple-stack_op-per-instruction.patch new file mode 100644 index 0000000..b875ff1 --- /dev/null +++ b/patches.suse/objtool-Support-multiple-stack_op-per-instruction.patch @@ -0,0 +1,198 @@ +From: Julien Thierry +Date: Fri, 27 Mar 2020 15:28:47 +0000 +Subject: objtool: Support multiple stack_op per instruction +Git-commit: 65ea47dcf4f936987a5fbf839c97acea00f4f196 +Patch-mainline: v5.8-rc1 +References: bsc#1202396 + +Instruction sets can include more or less complex operations which might +not fit the currently defined set of stack_ops. + +Combining more than one stack_op provides more flexibility to describe +the behaviour of an instruction. This also reduces the need to define +new stack_ops specific to a single instruction set. + +Allow instruction decoders to generate multiple stack_op per +instruction. + +Signed-off-by: Julien Thierry +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Miroslav Benes +Reviewed-by: Alexandre Chartre +Acked-by: Josh Poimboeuf +Link: https://lkml.kernel.org/r/20200327152847.15294-11-jthierry@redhat.com +Signed-off-by: Ingo Molnar +Acked-by: Miroslav Benes +--- + tools/objtool/arch.h | 4 +++- + tools/objtool/arch/x86/decode.c | 13 ++++++++++++- + tools/objtool/check.c | 32 +++++++++++++++++++++++++------- + tools/objtool/check.h | 2 +- + 4 files changed, 41 insertions(+), 10 deletions(-) + +--- a/tools/objtool/arch.h ++++ b/tools/objtool/arch.h +@@ -70,6 +70,7 @@ struct op_src { + struct stack_op { + struct op_dest dest; + struct op_src src; ++ struct list_head list; + }; + + void arch_initial_func_cfi_state(struct cfi_state *state); +@@ -77,7 +78,8 @@ void arch_initial_func_cfi_state(struct + int arch_decode_instruction(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int maxlen, + unsigned int *len, enum insn_type *type, +- unsigned long *immediate, struct stack_op *op); ++ unsigned long *immediate, ++ struct list_head *ops_list); + + bool arch_callee_saved_reg(unsigned char reg); + +--- a/tools/objtool/arch/x86/decode.c ++++ b/tools/objtool/arch/x86/decode.c +@@ -81,13 +81,15 @@ bool arch_callee_saved_reg(unsigned char + int arch_decode_instruction(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int maxlen, + unsigned int *len, enum insn_type *type, +- unsigned long *immediate, struct stack_op *op) ++ unsigned long *immediate, ++ struct list_head *ops_list) + { + struct insn insn; + int x86_64, sign; + unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, + rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0, + modrm_reg = 0, sib = 0; ++ struct stack_op *op; + + x86_64 = is_x86_64(elf); + if (x86_64 == -1) +@@ -128,6 +130,10 @@ int arch_decode_instruction(struct elf * + if (insn.sib.nbytes) + sib = insn.sib.bytes[0]; + ++ op = calloc(1, sizeof(*op)); ++ if (!op) ++ return -1; ++ + switch (op1) { + + case 0x1: +@@ -474,6 +480,11 @@ int arch_decode_instruction(struct elf * + + *immediate = insn.immediate.nbytes ? insn.immediate.value : 0; + ++ if (*type == INSN_STACK) ++ list_add_tail(&op->list, ops_list); ++ else ++ free(op); ++ + return 0; + } + +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -282,6 +282,7 @@ static int decode_instructions(struct ob + } + memset(insn, 0, sizeof(*insn)); + INIT_LIST_HEAD(&insn->alts); ++ INIT_LIST_HEAD(&insn->stack_ops); + clear_insn_state(&insn->state); + + insn->sec = sec; +@@ -291,7 +292,7 @@ static int decode_instructions(struct ob + sec->len - offset, + &insn->len, &insn->type, + &insn->immediate, +- &insn->stack_op); ++ &insn->stack_ops); + if (ret) + goto err; + +@@ -673,6 +674,7 @@ static int handle_group_alt(struct objto + } + memset(fake_jump, 0, sizeof(*fake_jump)); + INIT_LIST_HEAD(&fake_jump->alts); ++ INIT_LIST_HEAD(&fake_jump->stack_ops); + clear_insn_state(&fake_jump->state); + + fake_jump->sec = special_alt->new_sec; +@@ -1317,10 +1319,11 @@ static bool has_valid_stack_frame(struct + return false; + } + +-static int update_insn_state_regs(struct instruction *insn, struct insn_state *state) ++static int update_insn_state_regs(struct instruction *insn, ++ struct insn_state *state, ++ struct stack_op *op) + { + struct cfi_reg *cfa = &state->cfa; +- struct stack_op *op = &insn->stack_op; + + if (cfa->base != CFI_SP && cfa->base != CFI_SP_INDIRECT) + return 0; +@@ -1410,9 +1413,9 @@ static void restore_reg(struct insn_stat + * 41 5d pop %r13 + * c3 retq + */ +-static int update_insn_state(struct instruction *insn, struct insn_state *state) ++static int update_insn_state(struct instruction *insn, struct insn_state *state, ++ struct stack_op *op) + { +- struct stack_op *op = &insn->stack_op; + struct cfi_reg *cfa = &state->cfa; + struct cfi_reg *regs = state->regs; + +@@ -1426,7 +1429,7 @@ static int update_insn_state(struct inst + } + + if (state->type == ORC_TYPE_REGS || state->type == ORC_TYPE_REGS_IRET) +- return update_insn_state_regs(insn, state); ++ return update_insn_state_regs(insn, state, op); + + switch (op->dest.type) { + +@@ -1752,6 +1755,21 @@ static int update_insn_state(struct inst + return 0; + } + ++static int handle_insn_ops(struct instruction *insn, struct insn_state *state) ++{ ++ struct stack_op *op; ++ ++ list_for_each_entry(op, &insn->stack_ops, list) { ++ int res; ++ ++ res = update_insn_state(insn, state, op); ++ if (res) ++ return res; ++ } ++ ++ return 0; ++} ++ + static bool insn_state_match(struct instruction *insn, struct insn_state *state) + { + struct insn_state *state1 = &insn->state, *state2 = state; +@@ -1996,7 +2014,7 @@ static int validate_branch(struct objtoo + return 0; + + case INSN_STACK: +- if (update_insn_state(insn, &state)) ++ if (handle_insn_ops(insn, &state)) + return 1; + + break; +--- a/tools/objtool/check.h ++++ b/tools/objtool/check.h +@@ -51,7 +51,7 @@ struct instruction { + struct instruction *first_jump_src; + struct list_head alts; + struct symbol *func; +- struct stack_op stack_op; ++ struct list_head stack_ops; + struct insn_state state; + struct orc_entry orc; + }; diff --git a/patches.suse/objtool-Track-original-function-across-branches.patch b/patches.suse/objtool-Track-original-function-across-branches.patch new file mode 100644 index 0000000..8338c7d --- /dev/null +++ b/patches.suse/objtool-Track-original-function-across-branches.patch @@ -0,0 +1,117 @@ +From: Josh Poimboeuf +Date: Wed, 17 Jul 2019 20:36:47 -0500 +Subject: objtool: Track original function across branches +Git-commit: c705cecc8431951b4f34178e6b1db51b4a504c43 +Patch-mainline: v5.3-rc1 +References: bsc#1202396 + +If 'insn->func' is NULL, objtool skips some important checks, including +sibling call validation. So if some .fixup code does an invalid sibling +call, objtool ignores it. + +Treat all code branches (including alts) as part of the original +function by keeping track of the original func value from +validate_functions(). + +This improves the usefulness of some clang function fallthrough +warnings, and exposes some additional kernel bugs in the process. + +Signed-off-by: Josh Poimboeuf +Signed-off-by: Thomas Gleixner +Tested-by: Nick Desaulniers +Acked-by: Peter Zijlstra (Intel) +Link: https://lkml.kernel.org/r/505df630f33c9717e1ccde6e4b64c5303135c25f.1563413318.git.jpoimboe@redhat.com + +Acked-by: Miroslav Benes +--- + tools/objtool/check.c | 24 ++++++++++-------------- + 1 file changed, 10 insertions(+), 14 deletions(-) + +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -1788,13 +1788,12 @@ static int validate_sibling_call(struct + * each instruction and validate all the rules described in + * tools/objtool/Documentation/stack-validation.txt. + */ +-static int validate_branch(struct objtool_file *file, struct instruction *first, +- struct insn_state state) ++static int validate_branch(struct objtool_file *file, struct symbol *func, ++ struct instruction *first, struct insn_state state) + { + struct alternative *alt; + struct instruction *insn, *next_insn; + struct section *sec; +- struct symbol *func = NULL; + int ret; + + insn = first; +@@ -1815,9 +1814,6 @@ static int validate_branch(struct objtoo + return 1; + } + +- if (insn->func) +- func = insn->func->pfunc; +- + if (func && insn->ignore) { + WARN_FUNC("BUG: why am I validating an ignored function?", + sec, insn->offset); +@@ -1837,7 +1833,7 @@ static int validate_branch(struct objtoo + + i = insn; + save_insn = NULL; +- func_for_each_insn_continue_reverse(file, insn->func, i) { ++ func_for_each_insn_continue_reverse(file, func, i) { + if (i->save) { + save_insn = i; + break; +@@ -1883,7 +1879,7 @@ static int validate_branch(struct objtoo + if (alt->skip_orig) + skip_orig = true; + +- ret = validate_branch(file, alt->insn, state); ++ ret = validate_branch(file, func, alt->insn, state); + if (ret) { + if (backtrace) + BT_FUNC("(alt)", insn); +@@ -1906,7 +1902,7 @@ static int validate_branch(struct objtoo + + if (state.bp_scratch) { + WARN("%s uses BP as a scratch register", +- insn->func->name); ++ func->name); + return 1; + } + +@@ -1941,8 +1937,8 @@ static int validate_branch(struct objtoo + } else if (insn->jump_dest && + (!func || !insn->jump_dest->func || + insn->jump_dest->func->pfunc == func)) { +- ret = validate_branch(file, insn->jump_dest, +- state); ++ ret = validate_branch(file, func, ++ insn->jump_dest, state); + if (ret) { + if (backtrace) + BT_FUNC("(branch)", insn); +@@ -2011,7 +2007,7 @@ static int validate_unwind_hints(struct + + for_each_insn(file, insn) { + if (insn->hint && !insn->visited) { +- ret = validate_branch(file, insn, state); ++ ret = validate_branch(file, insn->func, insn, state); + if (ret && backtrace) + BT_FUNC("<=== (hint)", insn); + warnings += ret; +@@ -2138,10 +2134,10 @@ static int validate_functions(struct obj + continue; + + insn = find_insn(file, sec, func->offset); +- if (!insn || insn->ignore) ++ if (!insn || insn->ignore || insn->visited) + continue; + +- ret = validate_branch(file, insn, state); ++ ret = validate_branch(file, func, insn, state); + if (ret && backtrace) + BT_FUNC("<=== (func)", insn); + warnings += ret; diff --git a/patches.suse/objtool-Uniquely-identify-alternative-instruction-groups.patch b/patches.suse/objtool-Uniquely-identify-alternative-instruction-groups.patch new file mode 100644 index 0000000..ca0418e --- /dev/null +++ b/patches.suse/objtool-Uniquely-identify-alternative-instruction-groups.patch @@ -0,0 +1,71 @@ +From: Alexandre Chartre +Date: Tue, 14 Apr 2020 12:36:11 +0200 +Subject: objtool: Uniquely identify alternative instruction groups +Git-commit: 13fab06d9a3ad3afdfd51c7f8f87f2ae28444648 +Patch-mainline: v5.8-rc1 +References: bsc#1202396 + +Assign a unique identifier to every alternative instruction group in +order to be able to tell which instructions belong to what +alternative. + +[peterz: extracted from a larger patch] +Signed-off-by: Alexandre Chartre +Signed-off-by: Peter Zijlstra (Intel) +Reviewed-by: Miroslav Benes +Acked-by: Miroslav Benes +--- + tools/objtool/check.c | 6 +++++- + tools/objtool/check.h | 3 ++- + 2 files changed, 7 insertions(+), 2 deletions(-) + +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -658,7 +658,9 @@ static int handle_group_alt(struct objto + struct instruction *orig_insn, + struct instruction **new_insn) + { ++ static unsigned int alt_group_next_index = 1; + struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump = NULL; ++ unsigned int alt_group = alt_group_next_index++; + unsigned long dest_off; + + last_orig_insn = NULL; +@@ -667,7 +669,7 @@ static int handle_group_alt(struct objto + if (insn->offset >= special_alt->orig_off + special_alt->orig_len) + break; + +- insn->alt_group = true; ++ insn->alt_group = alt_group; + last_orig_insn = insn; + } + +@@ -701,6 +703,7 @@ static int handle_group_alt(struct objto + } + + last_new_insn = NULL; ++ alt_group = alt_group_next_index++; + insn = *new_insn; + sec_for_each_insn_from(file, insn) { + if (insn->offset >= special_alt->new_off + special_alt->new_len) +@@ -710,6 +713,7 @@ static int handle_group_alt(struct objto + + insn->ignore = orig_insn->ignore_alts; + insn->func = orig_insn->func; ++ insn->alt_group = alt_group; + + /* + * Since alternative replacement code is copy/pasted by the +--- a/tools/objtool/check.h ++++ b/tools/objtool/check.h +@@ -37,8 +37,9 @@ struct instruction { + unsigned int len; + enum insn_type type; + unsigned long immediate; +- bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; ++ bool visited, dead_end, ignore, hint, save, restore, ignore_alts; + bool retpoline_safe; ++ int alt_group; + struct symbol *call_dest; + struct instruction *jump_dest; + struct instruction *first_jump_src; diff --git a/patches.suse/objtool-Use-Elf_Scn-typedef-instead-of-assuming-struct-name.patch b/patches.suse/objtool-Use-Elf_Scn-typedef-instead-of-assuming-struct-name.patch new file mode 100644 index 0000000..1fdf84a --- /dev/null +++ b/patches.suse/objtool-Use-Elf_Scn-typedef-instead-of-assuming-struct-name.patch @@ -0,0 +1,34 @@ +From: Michael Forney +Date: Wed, 10 Jul 2019 16:17:35 -0500 +Subject: objtool: Use Elf_Scn typedef instead of assuming struct name +Git-commit: 3c3ea5031761fdd144b461d23a077c3a0cf427fa +Patch-mainline: v5.3-rc1 +References: bsc#1202396 + +The libelf implementation might use a different struct name, and the +Elf_Scn typedef is already used throughout the rest of objtool. + +Signed-off-by: Michael Forney +Signed-off-by: Josh Poimboeuf +Signed-off-by: Thomas Gleixner +Link: https://lkml.kernel.org/r/d270e1be2835fc2a10acf67535ff2ebd2145bf43.1562793448.git.jpoimboe@redhat.com + +Acked-by: Miroslav Benes +--- + tools/objtool/elf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c +index e99e1be19ad9..76e4f7ceab82 100644 +--- a/tools/objtool/elf.c ++++ b/tools/objtool/elf.c +@@ -463,7 +463,7 @@ struct section *elf_create_section(struct elf *elf, const char *name, + { + struct section *sec, *shstrtab; + size_t size = entsize * nr; +- struct Elf_Scn *s; ++ Elf_Scn *s; + Elf_Data *data; + + sec = malloc(sizeof(*sec)); + diff --git a/patches.suse/objtool-add-is_static_jump-helper.patch b/patches.suse/objtool-add-is_static_jump-helper.patch index aab4832..2d40385 100644 --- a/patches.suse/objtool-add-is_static_jump-helper.patch +++ b/patches.suse/objtool-add-is_static_jump-helper.patch @@ -20,7 +20,7 @@ Acked-by: Miroslav Benes --- a/tools/objtool/check.c +++ b/tools/objtool/check.c -@@ -104,6 +104,12 @@ static struct instruction *next_insn_sam +@@ -107,6 +107,12 @@ static struct instruction *next_insn_sam for (insn = next_insn_same_sec(file, insn); insn; \ insn = next_insn_same_sec(file, insn)) @@ -33,7 +33,7 @@ Acked-by: Miroslav Benes /* * Check if the function has been manually whitelisted with the * STACK_FRAME_NON_STANDARD macro, or if it should be automatically whitelisted -@@ -495,8 +501,7 @@ static int add_jump_destinations(struct +@@ -498,8 +504,7 @@ static int add_jump_destinations(struct unsigned long dest_off; for_each_insn(file, insn) { @@ -42,10 +42,10 @@ Acked-by: Miroslav Benes + if (!is_static_jump(insn)) continue; - if (insn->ignore) -@@ -695,8 +700,7 @@ static int handle_group_alt(struct objto - + if (insn->ignore || insn->offset == FAKE_JUMP_OFFSET) +@@ -707,8 +712,7 @@ static int handle_group_alt(struct objto insn->ignore = orig_insn->ignore_alts; + insn->func = orig_insn->func; - if (insn->type != INSN_JUMP_CONDITIONAL && - insn->type != INSN_JUMP_UNCONDITIONAL) diff --git a/patches.suse/objtool-add-relocation-check-for-alternative-sections.patch b/patches.suse/objtool-add-relocation-check-for-alternative-sections.patch index 9c6841f..fc87904 100644 --- a/patches.suse/objtool-add-relocation-check-for-alternative-sections.patch +++ b/patches.suse/objtool-add-relocation-check-for-alternative-sections.patch @@ -32,9 +32,9 @@ Acked-by: Miroslav Benes --- a/tools/objtool/check.c +++ b/tools/objtool/check.c -@@ -700,6 +700,27 @@ static int handle_group_alt(struct objto - +@@ -701,6 +701,27 @@ static int handle_group_alt(struct objto insn->ignore = orig_insn->ignore_alts; + insn->func = orig_insn->func; + /* + * Since alternative replacement code is copy/pasted by the diff --git a/patches.suse/objtool-clean-instruction-state-before-each-function-validation.patch b/patches.suse/objtool-clean-instruction-state-before-each-function-validation.patch index ed71c45..f5ee01b 100644 --- a/patches.suse/objtool-clean-instruction-state-before-each-function-validation.patch +++ b/patches.suse/objtool-clean-instruction-state-before-each-function-validation.patch @@ -24,7 +24,7 @@ Acked-by: Miroslav Benes --- a/tools/objtool/check.c +++ b/tools/objtool/check.c -@@ -2108,13 +2108,6 @@ static int validate_functions(struct obj +@@ -2143,13 +2143,6 @@ static int validate_functions(struct obj struct insn_state state; int ret, warnings = 0; @@ -38,8 +38,8 @@ Acked-by: Miroslav Benes for_each_sec(file, sec) { list_for_each_entry(func, &sec->symbol_list, list) { if (func->type != STT_FUNC || func->pfunc != func) -@@ -2124,6 +2117,12 @@ static int validate_functions(struct obj - if (!insn || insn->ignore) +@@ -2159,6 +2152,12 @@ static int validate_functions(struct obj + if (!insn || insn->ignore || insn->visited) continue; + clear_insn_state(&state); @@ -48,6 +48,6 @@ Acked-by: Miroslav Benes + CFI_NUM_REGS * sizeof(struct cfi_reg)); + state.stack_size = initial_func_cfi.cfa.offset; + - ret = validate_branch(file, insn, state); - warnings += ret; - } + ret = validate_branch(file, func, insn, state); + if (ret && backtrace) + BT_FUNC("<=== (func)", insn); diff --git a/patches.suse/objtool-make-bp-scratch-register-warning-more-robust.patch b/patches.suse/objtool-make-bp-scratch-register-warning-more-robust.patch index bf918b1..de2d249 100644 --- a/patches.suse/objtool-make-bp-scratch-register-warning-more-robust.patch +++ b/patches.suse/objtool-make-bp-scratch-register-warning-more-robust.patch @@ -23,14 +23,14 @@ Acked-by: Miroslav Benes --- a/tools/objtool/check.c +++ b/tools/objtool/check.c -@@ -1892,8 +1892,8 @@ static int validate_branch(struct objtoo +@@ -1923,8 +1923,8 @@ static int validate_branch(struct objtoo } if (state.bp_scratch) { - WARN("%s uses BP as a scratch register", -- insn->func->name); +- func->name); + WARN_FUNC("BP used as a scratch register", -+ insn->sec, insn->offset); ++ sec, insn->offset); return 1; } diff --git a/patches.suse/powerpc-Use-sizeof-foo-rather-than-sizeof-struct-foo.patch b/patches.suse/powerpc-Use-sizeof-foo-rather-than-sizeof-struct-foo.patch new file mode 100644 index 0000000..1f8c140 --- /dev/null +++ b/patches.suse/powerpc-Use-sizeof-foo-rather-than-sizeof-struct-foo.patch @@ -0,0 +1,357 @@ +From a0828cf57acce9bf941539e1f633e9a91f9df57d Mon Sep 17 00:00:00 2001 +From: Markus Elfring +Date: Thu, 19 Jan 2017 17:15:30 +0100 +Subject: [PATCH] powerpc: Use sizeof(*foo) rather than sizeof(struct foo) + +References: FATE#322448, bsc#1054914, git-fixes +Patch-mainline: v4.17-rc1 +Git-commit: a0828cf57acce9bf941539e1f633e9a91f9df57d + +It's slightly less error prone to use sizeof(*foo) rather than +specifying the type. + +Signed-off-by: Markus Elfring +[mpe: Consolidate into one patch, rewrite change log] +Signed-off-by: Michael Ellerman +Acked-by: Michal Suchanek +--- + arch/powerpc/kernel/nvram_64.c | 9 +++------ + arch/powerpc/oprofile/cell/spu_task_sync.c | 2 +- + arch/powerpc/oprofile/cell/vma_map.c | 4 ++-- + arch/powerpc/platforms/4xx/msi.c | 2 +- + arch/powerpc/platforms/4xx/ocm.c | 2 +- + arch/powerpc/platforms/cell/axon_msi.c | 2 +- + arch/powerpc/platforms/cell/spider-pci.c | 2 +- + arch/powerpc/platforms/cell/spufs/lscsa_alloc.c | 2 +- + arch/powerpc/platforms/powermac/low_i2c.c | 2 +- + arch/powerpc/platforms/powermac/pfunc_core.c | 4 ++-- + arch/powerpc/platforms/powernv/opal-flash.c | 4 ++-- + arch/powerpc/platforms/powernv/opal-hmi.c | 2 +- + arch/powerpc/platforms/powernv/opal-imc.c | 10 +++++----- + arch/powerpc/platforms/powernv/opal-memory-errors.c | 2 +- + arch/powerpc/platforms/powernv/opal-psr.c | 2 +- + arch/powerpc/platforms/powernv/opal-sensor-groups.c | 4 ++-- + arch/powerpc/platforms/powernv/opal-xscom.c | 2 +- + arch/powerpc/platforms/powernv/pci-ioda.c | 2 +- + arch/powerpc/platforms/ps3/mm.c | 6 ++---- + drivers/macintosh/rack-meter.c | 2 +- + 20 files changed, 31 insertions(+), 36 deletions(-) + +diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c +index 496d6393bd41..ba681dac7b46 100644 +--- a/arch/powerpc/kernel/nvram_64.c ++++ b/arch/powerpc/kernel/nvram_64.c +@@ -207,8 +207,7 @@ int nvram_write_os_partition(struct nvram_os_partition *part, + + tmp_index = part->index; + +- rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), +- &tmp_index); ++ rc = ppc_md.nvram_write((char *)&info, sizeof(info), &tmp_index); + if (rc <= 0) { + pr_err("%s: Failed nvram_write (%d)\n", __func__, rc); + return rc; +@@ -244,9 +243,7 @@ int nvram_read_partition(struct nvram_os_partition *part, char *buff, + tmp_index = part->index; + + if (part->os_partition) { +- rc = ppc_md.nvram_read((char *)&info, +- sizeof(struct err_log_info), +- &tmp_index); ++ rc = ppc_md.nvram_read((char *)&info, sizeof(info), &tmp_index); + if (rc <= 0) { + pr_err("%s: Failed nvram_read (%d)\n", __func__, rc); + return rc; +@@ -1173,7 +1170,7 @@ int __init nvram_scan_partitions(void) + "detected: 0-length partition\n"); + goto out; + } +- tmp_part = kmalloc(sizeof(struct nvram_partition), GFP_KERNEL); ++ tmp_part = kmalloc(sizeof(*tmp_part), GFP_KERNEL); + err = -ENOMEM; + if (!tmp_part) { + printk(KERN_ERR "nvram_scan_partitions: kmalloc failed\n"); +diff --git a/arch/powerpc/oprofile/cell/spu_task_sync.c b/arch/powerpc/oprofile/cell/spu_task_sync.c +index 44d67b167e0b..2668cc414e4e 100644 +--- a/arch/powerpc/oprofile/cell/spu_task_sync.c ++++ b/arch/powerpc/oprofile/cell/spu_task_sync.c +@@ -208,7 +208,7 @@ prepare_cached_spu_info(struct spu *spu, unsigned long objectId) + /* Create cached_info and set spu_info[spu->number] to point to it. + * spu->number is a system-wide value, not a per-node value. + */ +- info = kzalloc(sizeof(struct cached_info), GFP_KERNEL); ++ info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + printk(KERN_ERR "SPU_PROF: " + "%s, line %d: create vma_map failed\n", +diff --git a/arch/powerpc/oprofile/cell/vma_map.c b/arch/powerpc/oprofile/cell/vma_map.c +index c579b16845da..f40e37316dd6 100644 +--- a/arch/powerpc/oprofile/cell/vma_map.c ++++ b/arch/powerpc/oprofile/cell/vma_map.c +@@ -69,8 +69,8 @@ vma_map_add(struct vma_to_fileoffset_map *map, unsigned int vma, + unsigned int size, unsigned int offset, unsigned int guard_ptr, + unsigned int guard_val) + { +- struct vma_to_fileoffset_map *new = +- kzalloc(sizeof(struct vma_to_fileoffset_map), GFP_KERNEL); ++ struct vma_to_fileoffset_map *new = kzalloc(sizeof(*new), GFP_KERNEL); ++ + if (!new) { + printk(KERN_ERR "SPU_PROF: %s, line %d: malloc failed\n", + __func__, __LINE__); +diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c +index 6ea3f248b155..326d34e2aa02 100644 +--- a/arch/powerpc/platforms/cell/axon_msi.c ++++ b/arch/powerpc/platforms/cell/axon_msi.c +@@ -342,7 +342,7 @@ static int axon_msi_probe(struct platform_device *device) + + pr_devel("axon_msi: setting up dn %pOF\n", dn); + +- msic = kzalloc(sizeof(struct axon_msic), GFP_KERNEL); ++ msic = kzalloc(sizeof(*msic), GFP_KERNEL); + if (!msic) { + printk(KERN_ERR "axon_msi: couldn't allocate msic for %pOF\n", + dn); +diff --git a/arch/powerpc/platforms/cell/spider-pci.c b/arch/powerpc/platforms/cell/spider-pci.c +index d1e61e273e64..1200d0dea512 100644 +--- a/arch/powerpc/platforms/cell/spider-pci.c ++++ b/arch/powerpc/platforms/cell/spider-pci.c +@@ -133,7 +133,7 @@ int __init spiderpci_iowa_init(struct iowa_bus *bus, void *data) + pr_debug("SPIDERPCI-IOWA:Bus initialize for spider(%pOF)\n", + np); + +- priv = kzalloc(sizeof(struct spiderpci_iowa_private), GFP_KERNEL); ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + pr_err("SPIDERPCI-IOWA:" + "Can't allocate struct spiderpci_iowa_private"); +diff --git a/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c b/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c +index b847e9403566..d9de848dae47 100644 +--- a/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c ++++ b/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c +@@ -36,7 +36,7 @@ int spu_alloc_lscsa(struct spu_state *csa) + struct spu_lscsa *lscsa; + unsigned char *p; + +- lscsa = vzalloc(sizeof(struct spu_lscsa)); ++ lscsa = vzalloc(sizeof(*lscsa)); + if (!lscsa) + return -ENOMEM; + csa->lscsa = lscsa; +diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c +index 3408f315ef48..fa89f30e7f27 100644 +--- a/arch/powerpc/platforms/powermac/low_i2c.c ++++ b/arch/powerpc/platforms/powermac/low_i2c.c +@@ -492,7 +492,7 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np) + const u32 *psteps, *prate, *addrp; + u32 steps; + +- host = kzalloc(sizeof(struct pmac_i2c_host_kw), GFP_KERNEL); ++ host = kzalloc(sizeof(*host), GFP_KERNEL); + if (host == NULL) { + printk(KERN_ERR "low_i2c: Can't allocate host for %pOF\n", + np); +diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c +index df3c93bef228..e0462fedcdb8 100644 +--- a/arch/powerpc/platforms/powermac/pfunc_core.c ++++ b/arch/powerpc/platforms/powermac/pfunc_core.c +@@ -643,7 +643,7 @@ static int pmf_add_function_prop(struct pmf_device *dev, void *driverdata, + + while (length >= 12) { + /* Allocate a structure */ +- func = kzalloc(sizeof(struct pmf_function), GFP_KERNEL); ++ func = kzalloc(sizeof(*func), GFP_KERNEL); + if (func == NULL) + goto bail; + kref_init(&func->ref); +@@ -719,7 +719,7 @@ int pmf_register_driver(struct device_node *np, + return -EBUSY; + } + +- dev = kzalloc(sizeof(struct pmf_device), GFP_KERNEL); ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + DBG("pmf: no memory !\n"); + return -ENOMEM; +diff --git a/arch/powerpc/platforms/powernv/opal-flash.c b/arch/powerpc/platforms/powernv/opal-flash.c +index 2fa3ac80cb4e..1cb0b895a236 100644 +--- a/arch/powerpc/platforms/powernv/opal-flash.c ++++ b/arch/powerpc/platforms/powernv/opal-flash.c +@@ -418,12 +418,12 @@ static int alloc_image_buf(char *buffer, size_t count) + void *addr; + int size; + +- if (count < sizeof(struct image_header_t)) { ++ if (count < sizeof(image_header)) { + pr_warn("FLASH: Invalid candidate image\n"); + return -EINVAL; + } + +- memcpy(&image_header, (void *)buffer, sizeof(struct image_header_t)); ++ memcpy(&image_header, (void *)buffer, sizeof(image_header)); + image_data.size = be32_to_cpu(image_header.size); + pr_debug("FLASH: Candidate image size = %u\n", image_data.size); + +diff --git a/arch/powerpc/platforms/powernv/opal-hmi.c b/arch/powerpc/platforms/powernv/opal-hmi.c +index c9e1a4ff295c..4efc95b4c7d4 100644 +--- a/arch/powerpc/platforms/powernv/opal-hmi.c ++++ b/arch/powerpc/platforms/powernv/opal-hmi.c +@@ -314,7 +314,7 @@ static int opal_handle_hmi_event(struct notifier_block *nb, + pr_err("HMI: out of memory, Opal message event not handled\n"); + return -ENOMEM; + } +- memcpy(&msg_node->hmi_evt, hmi_evt, sizeof(struct OpalHMIEvent)); ++ memcpy(&msg_node->hmi_evt, hmi_evt, sizeof(*hmi_evt)); + + spin_lock_irqsave(&opal_hmi_evt_lock, flags); + list_add(&msg_node->list, &opal_hmi_evt_list); +diff --git a/arch/powerpc/platforms/powernv/opal-imc.c b/arch/powerpc/platforms/powernv/opal-imc.c +index f6f55ab4980e..2a14fda5ea26 100644 +--- a/arch/powerpc/platforms/powernv/opal-imc.c ++++ b/arch/powerpc/platforms/powernv/opal-imc.c +@@ -110,11 +110,11 @@ static int imc_get_mem_addr_nest(struct device_node *node, + if (nr_chips <= 0) + return -ENODEV; + +- base_addr_arr = kcalloc(nr_chips, sizeof(u64), GFP_KERNEL); ++ base_addr_arr = kcalloc(nr_chips, sizeof(*base_addr_arr), GFP_KERNEL); + if (!base_addr_arr) + return -ENOMEM; + +- chipid_arr = kcalloc(nr_chips, sizeof(u32), GFP_KERNEL); ++ chipid_arr = kcalloc(nr_chips, sizeof(*chipid_arr), GFP_KERNEL); + if (!chipid_arr) + return -ENOMEM; + +@@ -125,8 +125,8 @@ static int imc_get_mem_addr_nest(struct device_node *node, + nr_chips)) + goto error; + +- pmu_ptr->mem_info = kcalloc(nr_chips, sizeof(struct imc_mem_info), +- GFP_KERNEL); ++ pmu_ptr->mem_info = kcalloc(nr_chips, sizeof(*pmu_ptr->mem_info), ++ GFP_KERNEL); + if (!pmu_ptr->mem_info) + goto error; + +@@ -161,7 +161,7 @@ static int imc_pmu_create(struct device_node *parent, int pmu_index, int domain) + u32 offset; + + /* memory for pmu */ +- pmu_ptr = kzalloc(sizeof(struct imc_pmu), GFP_KERNEL); ++ pmu_ptr = kzalloc(sizeof(*pmu_ptr), GFP_KERNEL); + if (!pmu_ptr) + return -ENOMEM; + +diff --git a/arch/powerpc/platforms/powernv/opal-memory-errors.c b/arch/powerpc/platforms/powernv/opal-memory-errors.c +index 8ddc1accf199..dcb42bcb5efa 100644 +--- a/arch/powerpc/platforms/powernv/opal-memory-errors.c ++++ b/arch/powerpc/platforms/powernv/opal-memory-errors.c +@@ -112,7 +112,7 @@ static int opal_memory_err_event(struct notifier_block *nb, + "handled\n"); + return -ENOMEM; + } +- memcpy(&msg_node->msg, msg, sizeof(struct opal_msg)); ++ memcpy(&msg_node->msg, msg, sizeof(msg_node->msg)); + + spin_lock_irqsave(&opal_mem_err_lock, flags); + list_add(&msg_node->list, &opal_memory_err_list); +diff --git a/arch/powerpc/platforms/powernv/opal-psr.c b/arch/powerpc/platforms/powernv/opal-psr.c +index 7313b7fc9071..74986b35cf77 100644 +--- a/arch/powerpc/platforms/powernv/opal-psr.c ++++ b/arch/powerpc/platforms/powernv/opal-psr.c +@@ -136,7 +136,7 @@ void __init opal_psr_init(void) + return; + } + +- psr_attrs = kcalloc(of_get_child_count(psr), sizeof(struct psr_attr), ++ psr_attrs = kcalloc(of_get_child_count(psr), sizeof(*psr_attrs), + GFP_KERNEL); + if (!psr_attrs) + return; +diff --git a/arch/powerpc/platforms/powernv/opal-sensor-groups.c b/arch/powerpc/platforms/powernv/opal-sensor-groups.c +index 7e5a235ebf76..541c9ea04a32 100644 +--- a/arch/powerpc/platforms/powernv/opal-sensor-groups.c ++++ b/arch/powerpc/platforms/powernv/opal-sensor-groups.c +@@ -166,13 +166,13 @@ void __init opal_sensor_groups_init(void) + if (!nr_attrs) + continue; + +- sgs[i].sgattrs = kcalloc(nr_attrs, sizeof(struct sg_attr), ++ sgs[i].sgattrs = kcalloc(nr_attrs, sizeof(*sgs[i].sgattrs), + GFP_KERNEL); + if (!sgs[i].sgattrs) + goto out_sgs_sgattrs; + + sgs[i].sg.attrs = kcalloc(nr_attrs + 1, +- sizeof(struct attribute *), ++ sizeof(*sgs[i].sg.attrs), + GFP_KERNEL); + + if (!sgs[i].sg.attrs) { +diff --git a/arch/powerpc/platforms/powernv/opal-xscom.c b/arch/powerpc/platforms/powernv/opal-xscom.c +index 81c0a943dea9..22d5e1110dbb 100644 +--- a/arch/powerpc/platforms/powernv/opal-xscom.c ++++ b/arch/powerpc/platforms/powernv/opal-xscom.c +@@ -46,7 +46,7 @@ static scom_map_t opal_scom_map(struct device_node *dev, u64 reg, u64 count) + __func__, dev); + return SCOM_MAP_INVALID; + } +- m = kmalloc(sizeof(struct opal_scom_map), GFP_KERNEL); ++ m = kmalloc(sizeof(*m), GFP_KERNEL); + if (!m) + return NULL; + m->chip = be32_to_cpup(gcid); +diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c +index a6c92c78c9b2..6c307f0650bb 100644 +--- a/arch/powerpc/platforms/powernv/pci-ioda.c ++++ b/arch/powerpc/platforms/powernv/pci-ioda.c +@@ -3843,7 +3843,7 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np, + phb_id = be64_to_cpup(prop64); + pr_debug(" PHB-ID : 0x%016llx\n", phb_id); + +- phb = memblock_virt_alloc(sizeof(struct pnv_phb), 0); ++ phb = memblock_virt_alloc(sizeof(*phb), 0); + + /* Allocate PCI controller */ + phb->hose = hose = pcibios_alloc_controller(np); +diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c +index 7f870ec29daf..8c7009d001d9 100644 +--- a/arch/powerpc/platforms/ps3/mm.c ++++ b/arch/powerpc/platforms/ps3/mm.c +@@ -524,8 +524,7 @@ static int dma_sb_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, + int result; + struct dma_chunk *c; + +- c = kzalloc(sizeof(struct dma_chunk), GFP_ATOMIC); +- ++ c = kzalloc(sizeof(*c), GFP_ATOMIC); + if (!c) { + result = -ENOMEM; + goto fail_alloc; +@@ -570,8 +569,7 @@ static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr, + + DBG(KERN_ERR "%s: phy=%#lx, lpar%#lx, len=%#lx\n", __func__, + phys_addr, ps3_mm_phys_to_lpar(phys_addr), len); +- c = kzalloc(sizeof(struct dma_chunk), GFP_ATOMIC); +- ++ c = kzalloc(sizeof(*c), GFP_ATOMIC); + if (!c) { + result = -ENOMEM; + goto fail_alloc; +diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c +index 910b5b6f96b1..190c9efeace5 100644 +--- a/drivers/macintosh/rack-meter.c ++++ b/drivers/macintosh/rack-meter.c +@@ -397,7 +397,7 @@ static int rackmeter_probe(struct macio_dev* mdev, + } + + /* Create and initialize our instance data */ +- rm = kzalloc(sizeof(struct rackmeter), GFP_KERNEL); ++ rm = kzalloc(sizeof(*rm), GFP_KERNEL); + if (rm == NULL) { + printk(KERN_ERR "rackmeter: failed to allocate memory !\n"); + rc = -ENOMEM; +-- +2.35.3 + diff --git a/patches.suse/powerpc-perf-Add-privileged-access-check-for-thread_.patch b/patches.suse/powerpc-perf-Add-privileged-access-check-for-thread_.patch new file mode 100644 index 0000000..39d272b --- /dev/null +++ b/patches.suse/powerpc-perf-Add-privileged-access-check-for-thread_.patch @@ -0,0 +1,38 @@ +From 216c3087a346db8d7c8a064d2b8f0f49e4694934 Mon Sep 17 00:00:00 2001 +From: Madhavan Srinivasan +Date: Tue, 16 Apr 2019 15:18:29 +0530 +Subject: [PATCH] powerpc/perf: Add privileged access check for thread_imc + +References: FATE#322448, bsc#1054914, git-fixes +Patch-mainline: v5.2-rc1 +Git-commit: 216c3087a346db8d7c8a064d2b8f0f49e4694934 + +Add code to restrict user access to thread_imc pmu since +some event report privilege level information. + +Fixes: f74c89bd80fb3 ("powerpc/perf: Add thread IMC PMU support") +Signed-off-by: Madhavan Srinivasan +Signed-off-by: Anju T Sudhakar +Signed-off-by: Michael Ellerman +Acked-by: Michal Suchanek +--- + arch/powerpc/perf/imc-pmu.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c +index 23092a359ce0..975837d85a80 100644 +--- a/arch/powerpc/perf/imc-pmu.c ++++ b/arch/powerpc/perf/imc-pmu.c +@@ -864,6 +864,9 @@ static int thread_imc_event_init(struct perf_event *event) + if (event->attr.type != event->pmu->type) + return -ENOENT; + ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EACCES; ++ + /* Sampling not supported */ + if (event->hw.sample_period) + return -EINVAL; +-- +2.35.3 + diff --git a/patches.suse/powerpc-perf-Fix-loop-exit-condition-in-nest_imc_eve.patch b/patches.suse/powerpc-perf-Fix-loop-exit-condition-in-nest_imc_eve.patch new file mode 100644 index 0000000..37cfedd --- /dev/null +++ b/patches.suse/powerpc-perf-Fix-loop-exit-condition-in-nest_imc_eve.patch @@ -0,0 +1,62 @@ +From 860b7d2286236170a36f94946d03ca9888d32571 Mon Sep 17 00:00:00 2001 +From: Anju T Sudhakar +Date: Tue, 18 Dec 2018 11:50:41 +0530 +Subject: [PATCH] powerpc/perf: Fix loop exit condition in nest_imc_event_init + +References: FATE#322448, bsc#1054914, git-fixes +Patch-mainline: v5.2-rc1 +Git-commit: 860b7d2286236170a36f94946d03ca9888d32571 + +The data structure (i.e struct imc_mem_info) to hold the memory address +information for nest imc units is allocated based on the number of nodes +in the system. + +nest_imc_event_init() traverse this struct array to calculate the memory +base address for the event-cpu. If we fail to find a match for the event +cpu's chip-id in imc_mem_info struct array, then the do-while loop will +iterate until we crash. + +Fix this by changing the loop exit condition based on the number of +non zero vbase elements in the array, since the allocation is done for +nr_chips + 1. + +Reported-by: Dan Carpenter +Fixes: 885dcd709ba91 ("powerpc/perf: Add nest IMC PMU support") +Signed-off-by: Anju T Sudhakar +Reviewed-by: Madhavan Srinivasan +Signed-off-by: Michael Ellerman +Acked-by: Michal Suchanek +--- + arch/powerpc/perf/imc-pmu.c | 2 +- + arch/powerpc/platforms/powernv/opal-imc.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c +index 6159e9edddfd..2d12f0037e3a 100644 +--- a/arch/powerpc/perf/imc-pmu.c ++++ b/arch/powerpc/perf/imc-pmu.c +@@ -499,7 +499,7 @@ static int nest_imc_event_init(struct perf_event *event) + break; + } + pcni++; +- } while (pcni); ++ } while (pcni->vbase != 0); + + if (!flag) + return -ENODEV; +diff --git a/arch/powerpc/platforms/powernv/opal-imc.c b/arch/powerpc/platforms/powernv/opal-imc.c +index 58a07948c76e..3d27f02695e4 100644 +--- a/arch/powerpc/platforms/powernv/opal-imc.c ++++ b/arch/powerpc/platforms/powernv/opal-imc.c +@@ -127,7 +127,7 @@ static int imc_get_mem_addr_nest(struct device_node *node, + nr_chips)) + goto error; + +- pmu_ptr->mem_info = kcalloc(nr_chips, sizeof(*pmu_ptr->mem_info), ++ pmu_ptr->mem_info = kcalloc(nr_chips + 1, sizeof(*pmu_ptr->mem_info), + GFP_KERNEL); + if (!pmu_ptr->mem_info) + goto error; +-- +2.35.3 + diff --git a/patches.suse/powerpc-perf-Return-accordingly-on-invalid-chip-id-i.patch b/patches.suse/powerpc-perf-Return-accordingly-on-invalid-chip-id-i.patch new file mode 100644 index 0000000..f5a8f9d --- /dev/null +++ b/patches.suse/powerpc-perf-Return-accordingly-on-invalid-chip-id-i.patch @@ -0,0 +1,43 @@ +From a913e5e8b43be1d3897a141ce61c1ec071cad89c Mon Sep 17 00:00:00 2001 +From: Anju T Sudhakar +Date: Tue, 27 Nov 2018 13:54:52 +0530 +Subject: [PATCH] powerpc/perf: Return accordingly on invalid chip-id in + +References: FATE#322448, bsc#1054914, git-fixes +Patch-mainline: v5.2-rc1 +Git-commit: a913e5e8b43be1d3897a141ce61c1ec071cad89c + +Nest hardware counter memory resides in a per-chip reserve-memory. +During nest_imc_event_init(), chip-id of the event-cpu is considered to +calculate the base memory addresss for that cpu. Return, proper error +condition if the chip_id calculated is invalid. + +Reported-by: Dan Carpenter +Fixes: 885dcd709ba91 ("powerpc/perf: Add nest IMC PMU support") +Reviewed-by: Madhavan Srinivasan +Signed-off-by: Anju T Sudhakar +Signed-off-by: Michael Ellerman +Acked-by: Michal Suchanek +--- + arch/powerpc/perf/imc-pmu.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c +index b1c37cc3fa98..6159e9edddfd 100644 +--- a/arch/powerpc/perf/imc-pmu.c ++++ b/arch/powerpc/perf/imc-pmu.c +@@ -487,6 +487,11 @@ static int nest_imc_event_init(struct perf_event *event) + * Get the base memory addresss for this cpu. + */ + chip_id = cpu_to_chip_id(event->cpu); ++ ++ /* Return, if chip_id is not valid */ ++ if (chip_id < 0) ++ return -ENODEV; ++ + pcni = pmu->mem_info; + do { + if (pcni->id == chip_id) { +-- +2.35.3 + diff --git a/patches.suse/powerpc-powernv-Return-for-invalid-IMC-domain.patch b/patches.suse/powerpc-powernv-Return-for-invalid-IMC-domain.patch index d55a1ba..10b1e32 100644 --- a/patches.suse/powerpc-powernv-Return-for-invalid-IMC-domain.patch +++ b/patches.suse/powerpc-powernv-Return-for-invalid-IMC-domain.patch @@ -1,4 +1,4 @@ -From e66ec5e9303ae62fb3402088cca8d64e167bed69 Mon Sep 17 00:00:00 2001 +From b59bd3527fe3c1939340df558d7f9d568fc9f882 Mon Sep 17 00:00:00 2001 From: Anju T Sudhakar Date: Mon, 20 May 2019 14:27:53 +0530 Subject: [PATCH] powerpc/powernv: Return for invalid IMC domain @@ -33,10 +33,10 @@ Acked-by: Michal Suchanek 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/platforms/powernv/opal-imc.c b/arch/powerpc/platforms/powernv/opal-imc.c -index 38eccc66c7f4..600d863f7dd2 100644 +index 3e497b91d210..52e9e159bb70 100644 --- a/arch/powerpc/platforms/powernv/opal-imc.c +++ b/arch/powerpc/platforms/powernv/opal-imc.c -@@ -87,6 +87,10 @@ static int imc_pmu_create(struct device_node *parent, int pmu_index, int domain) +@@ -161,6 +161,10 @@ static int imc_pmu_create(struct device_node *parent, int pmu_index, int domain) struct imc_pmu *pmu_ptr; u32 offset; @@ -45,8 +45,8 @@ index 38eccc66c7f4..600d863f7dd2 100644 + return -EINVAL; + /* memory for pmu */ - pmu_ptr = kzalloc(sizeof(struct imc_pmu), GFP_KERNEL); + pmu_ptr = kzalloc(sizeof(*pmu_ptr), GFP_KERNEL); if (!pmu_ptr) -- -2.22.0 +2.35.3 diff --git a/patches.suse/rds-Fix-warning.patch b/patches.suse/rds-Fix-warning.patch index 93f9d9b..9c8172a 100644 --- a/patches.suse/rds-Fix-warning.patch +++ b/patches.suse/rds-Fix-warning.patch @@ -4,7 +4,7 @@ Date: Wed, 19 Dec 2018 20:53:18 -0800 Subject: [PATCH] rds: Fix warning. Git-commit: d84e7bc0595a7e146ad0ddb80b240cea77825245 Patch-mainline: v4.20 -References: bsc#1154848 +References: CVE-2022-21385 bsc#1202897 bsc#1154848 >> net/rds/send.c:1109:42: warning: Using plain integer as NULL pointer diff --git a/patches.suse/spmi-trace-fix-stack-out-of-bound-access-in-SPMI-tracing-functions.patch b/patches.suse/spmi-trace-fix-stack-out-of-bound-access-in-SPMI-tracing-functions.patch new file mode 100644 index 0000000..8a7085b --- /dev/null +++ b/patches.suse/spmi-trace-fix-stack-out-of-bound-access-in-SPMI-tracing-functions.patch @@ -0,0 +1,111 @@ +From: David Collins +Date: Mon, 27 Jun 2022 16:55:12 -0700 +Subject: spmi: trace: fix stack-out-of-bound access in SPMI tracing functions +Git-commit: 2af28b241eea816e6f7668d1954f15894b45d7e3 +Patch-mainline: v6.0-rc1 +References: git-fixes + +trace_spmi_write_begin() and trace_spmi_read_end() both call +memcpy() with a length of "len + 1". This leads to one extra +byte being read beyond the end of the specified buffer. Fix +this out-of-bound memory access by using a length of "len" +instead. + +Here is a KASAN log showing the issue: + +BUG: KASAN: stack-out-of-bounds in trace_event_raw_event_spmi_read_end+0x1d0/0x234 +Read of size 2 at addr ffffffc0265b7540 by task thermal@2.0-ser/1314 +... +Call trace: + dump_backtrace+0x0/0x3e8 + show_stack+0x2c/0x3c + dump_stack_lvl+0xdc/0x11c + print_address_description+0x74/0x384 + kasan_report+0x188/0x268 + kasan_check_range+0x270/0x2b0 + memcpy+0x90/0xe8 + trace_event_raw_event_spmi_read_end+0x1d0/0x234 + spmi_read_cmd+0x294/0x3ac + spmi_ext_register_readl+0x84/0x9c + regmap_spmi_ext_read+0x144/0x1b0 [regmap_spmi] + _regmap_raw_read+0x40c/0x754 + regmap_raw_read+0x3a0/0x514 + regmap_bulk_read+0x418/0x494 + adc5_gen3_poll_wait_hs+0xe8/0x1e0 [qcom_spmi_adc5_gen3] + ... + __arm64_sys_read+0x4c/0x60 + invoke_syscall+0x80/0x218 + el0_svc_common+0xec/0x1c8 + ... + +addr ffffffc0265b7540 is located in stack of task thermal@2.0-ser/1314 at offset 32 in frame: + adc5_gen3_poll_wait_hs+0x0/0x1e0 [qcom_spmi_adc5_gen3] + +this frame has 1 object: + [32, 33) 'status' + +Memory state around the buggy address: + ffffffc0265b7400: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 + ffffffc0265b7480: 04 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 +>ffffffc0265b7500: 00 00 00 00 f1 f1 f1 f1 01 f3 f3 f3 00 00 00 00 + ^ + ffffffc0265b7580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + ffffffc0265b7600: f1 f1 f1 f1 01 f2 07 f2 f2 f2 01 f3 00 00 00 00 +================================================================== + +Fixes: a9fce374815d ("spmi: add command tracepoints for SPMI") +Cc: stable@vger.kernel.org +Reviewed-by: Stephen Boyd +Acked-by: Steven Rostedt (Google) +Signed-off-by: David Collins +Link: https://lore.kernel.org/r/20220627235512.2272783-1-quic_collinsd@quicinc.com +Signed-off-by: Greg Kroah-Hartman +Acked-by: Petr Pavlu +--- + include/trace/events/spmi.h | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/include/trace/events/spmi.h b/include/trace/events/spmi.h +index 8b60efe18ba6..a6819fd85cdf 100644 +--- a/include/trace/events/spmi.h ++++ b/include/trace/events/spmi.h +@@ -21,15 +21,15 @@ TRACE_EVENT(spmi_write_begin, + __field ( u8, sid ) + __field ( u16, addr ) + __field ( u8, len ) +- __dynamic_array ( u8, buf, len + 1 ) ++ __dynamic_array ( u8, buf, len ) + ), + + TP_fast_assign( + __entry->opcode = opcode; + __entry->sid = sid; + __entry->addr = addr; +- __entry->len = len + 1; +- memcpy(__get_dynamic_array(buf), buf, len + 1); ++ __entry->len = len; ++ memcpy(__get_dynamic_array(buf), buf, len); + ), + + TP_printk("opc=%d sid=%02d addr=0x%04x len=%d buf=0x[%*phD]", +@@ -92,7 +92,7 @@ TRACE_EVENT(spmi_read_end, + __field ( u16, addr ) + __field ( int, ret ) + __field ( u8, len ) +- __dynamic_array ( u8, buf, len + 1 ) ++ __dynamic_array ( u8, buf, len ) + ), + + TP_fast_assign( +@@ -100,8 +100,8 @@ TRACE_EVENT(spmi_read_end, + __entry->sid = sid; + __entry->addr = addr; + __entry->ret = ret; +- __entry->len = len + 1; +- memcpy(__get_dynamic_array(buf), buf, len + 1); ++ __entry->len = len; ++ memcpy(__get_dynamic_array(buf), buf, len); + ), + + TP_printk("opc=%d sid=%02d addr=0x%04x ret=%d len=%02d buf=0x[%*phD]", + diff --git a/patches.suse/squashfs-fix-inode-lookup-sanity-checks.patch b/patches.suse/squashfs-fix-inode-lookup-sanity-checks.patch new file mode 100644 index 0000000..982ceea --- /dev/null +++ b/patches.suse/squashfs-fix-inode-lookup-sanity-checks.patch @@ -0,0 +1,68 @@ +From c1b2028315c6b15e8d6725e0d5884b15887d3daa Mon Sep 17 00:00:00 2001 +From: Sean Nyekjaer +Date: Wed, 24 Mar 2021 21:37:32 -0700 +Subject: [PATCH] squashfs: fix inode lookup sanity checks +Git-commit: c1b2028315c6b15e8d6725e0d5884b15887d3daa +Patch-mainline: v5.12-rc5 +References: bsc#1203013 + +When mouting a squashfs image created without inode compression it fails +With: "unable to read inode lookup table" + +It turns out that the BLOCK_OFFSET is missing when checking the +SQUASHFS_METADATA_SIZE agaist the actual size. + +Link: https://lkml.kernel.org/r/20210226092903.1473545-1-sean@geanix.com +Fixes: eabac19e40c0 ("squashfs: add more sanity checks in inode lookup") +Signed-off-by: Sean Nyekjaer +Acked-by: Phillip Lougher +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Acked-by: Anthony Iliopoulos + +--- + fs/squashfs/export.c | 8 ++++++-- + fs/squashfs/squashfs_fs.h | 1 + + 2 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/fs/squashfs/export.c b/fs/squashfs/export.c +index eb02072d28dd..723763746238 100644 +--- a/fs/squashfs/export.c ++++ b/fs/squashfs/export.c +@@ -152,14 +152,18 @@ __le64 *squashfs_read_inode_lookup_table(struct super_block *sb, + start = le64_to_cpu(table[n]); + end = le64_to_cpu(table[n + 1]); + +- if (start >= end || (end - start) > SQUASHFS_METADATA_SIZE) { ++ if (start >= end ++ || (end - start) > ++ (SQUASHFS_METADATA_SIZE + SQUASHFS_BLOCK_OFFSET)) { + kfree(table); + return ERR_PTR(-EINVAL); + } + } + + start = le64_to_cpu(table[indexes - 1]); +- if (start >= lookup_table_start || (lookup_table_start - start) > SQUASHFS_METADATA_SIZE) { ++ if (start >= lookup_table_start || ++ (lookup_table_start - start) > ++ (SQUASHFS_METADATA_SIZE + SQUASHFS_BLOCK_OFFSET)) { + kfree(table); + return ERR_PTR(-EINVAL); + } +diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h +index 8d64edb80ebf..b3fdc8212c5f 100644 +--- a/fs/squashfs/squashfs_fs.h ++++ b/fs/squashfs/squashfs_fs.h +@@ -17,6 +17,7 @@ + + /* size of metadata (inode and directory) blocks */ + #define SQUASHFS_METADATA_SIZE 8192 ++#define SQUASHFS_BLOCK_OFFSET 2 + + /* default size of block device I/O */ + #ifdef CONFIG_SQUASHFS_4K_DEVBLK_SIZE +-- +2.35.3 + diff --git a/patches.suse/squashfs-fix-xattr-id-and-id-lookup-sanity-checks.patch b/patches.suse/squashfs-fix-xattr-id-and-id-lookup-sanity-checks.patch new file mode 100644 index 0000000..baf8e93 --- /dev/null +++ b/patches.suse/squashfs-fix-xattr-id-and-id-lookup-sanity-checks.patch @@ -0,0 +1,74 @@ +From 8b44ca2b634527151af07447a8090a5f3a043321 Mon Sep 17 00:00:00 2001 +From: Phillip Lougher +Date: Wed, 24 Mar 2021 21:37:35 -0700 +Subject: [PATCH] squashfs: fix xattr id and id lookup sanity checks +Git-commit: 8b44ca2b634527151af07447a8090a5f3a043321 +Patch-mainline: v5.12-rc5 +References: bsc#1203013 + +The checks for maximum metadata block size is missing +SQUASHFS_BLOCK_OFFSET (the two byte length count). + +Link: https://lkml.kernel.org/r/2069685113.2081245.1614583677427@webmail.123-reg.co.uk +Fixes: f37aa4c7366e23f ("squashfs: add more sanity checks in id lookup") +Signed-off-by: Phillip Lougher +Cc: Sean Nyekjaer +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Acked-by: Anthony Iliopoulos + +--- + fs/squashfs/id.c | 6 ++++-- + fs/squashfs/xattr_id.c | 6 ++++-- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/fs/squashfs/id.c b/fs/squashfs/id.c +index 11581bf31af4..ea5387679723 100644 +--- a/fs/squashfs/id.c ++++ b/fs/squashfs/id.c +@@ -97,14 +97,16 @@ __le64 *squashfs_read_id_index_table(struct super_block *sb, + start = le64_to_cpu(table[n]); + end = le64_to_cpu(table[n + 1]); + +- if (start >= end || (end - start) > SQUASHFS_METADATA_SIZE) { ++ if (start >= end || (end - start) > ++ (SQUASHFS_METADATA_SIZE + SQUASHFS_BLOCK_OFFSET)) { + kfree(table); + return ERR_PTR(-EINVAL); + } + } + + start = le64_to_cpu(table[indexes - 1]); +- if (start >= id_table_start || (id_table_start - start) > SQUASHFS_METADATA_SIZE) { ++ if (start >= id_table_start || (id_table_start - start) > ++ (SQUASHFS_METADATA_SIZE + SQUASHFS_BLOCK_OFFSET)) { + kfree(table); + return ERR_PTR(-EINVAL); + } +diff --git a/fs/squashfs/xattr_id.c b/fs/squashfs/xattr_id.c +index ead66670b41a..087cab8c78f4 100644 +--- a/fs/squashfs/xattr_id.c ++++ b/fs/squashfs/xattr_id.c +@@ -109,14 +109,16 @@ __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 table_start, + start = le64_to_cpu(table[n]); + end = le64_to_cpu(table[n + 1]); + +- if (start >= end || (end - start) > SQUASHFS_METADATA_SIZE) { ++ if (start >= end || (end - start) > ++ (SQUASHFS_METADATA_SIZE + SQUASHFS_BLOCK_OFFSET)) { + kfree(table); + return ERR_PTR(-EINVAL); + } + } + + start = le64_to_cpu(table[indexes - 1]); +- if (start >= table_start || (table_start - start) > SQUASHFS_METADATA_SIZE) { ++ if (start >= table_start || (table_start - start) > ++ (SQUASHFS_METADATA_SIZE + SQUASHFS_BLOCK_OFFSET)) { + kfree(table); + return ERR_PTR(-EINVAL); + } +-- +2.35.3 + diff --git a/patches.suse/tpm-fix-reference-counting-for-struct-tpm_chip.patch b/patches.suse/tpm-fix-reference-counting-for-struct-tpm_chip.patch new file mode 100644 index 0000000..00b665c --- /dev/null +++ b/patches.suse/tpm-fix-reference-counting-for-struct-tpm_chip.patch @@ -0,0 +1,272 @@ +From 7e0438f83dc769465ee663bb5dcf8cc154940712 Mon Sep 17 00:00:00 2001 +From: Lino Sanfilippo +Date: Wed, 2 Mar 2022 10:43:53 +0100 +Subject: [PATCH] tpm: fix reference counting for struct tpm_chip +Git-commit: 7e0438f83dc769465ee663bb5dcf8cc154940712 +Patch-mainline: v5.18-rc1 +References: CVE-2022-2977 bsc#1202672 + +The following sequence of operations results in a refcount warning: + +1. Open device /dev/tpmrm. +2. Remove module tpm_tis_spi. +3. Write a TPM command to the file descriptor opened at step 1. + +Acked-by: Takashi Iwai + +------------[ cut here ]------------ +WARNING: CPU: 3 PID: 1161 at lib/refcount.c:25 kobject_get+0xa0/0xa4 +refcount_t: addition on 0; use-after-free. +Modules linked in: tpm_tis_spi tpm_tis_core tpm mdio_bcm_unimac brcmfmac +sha256_generic libsha256 sha256_arm hci_uart btbcm bluetooth cfg80211 vc4 +brcmutil ecdh_generic ecc snd_soc_core crc32_arm_ce libaes +raspberrypi_hwmon ac97_bus snd_pcm_dmaengine bcm2711_thermal snd_pcm +snd_timer genet snd phy_generic soundcore [last unloaded: spi_bcm2835] +CPU: 3 PID: 1161 Comm: hold_open Not tainted 5.10.0ls-main-dirty #2 +Hardware name: BCM2711 +[] (unwind_backtrace) from [] (show_stack+0x10/0x14) +[] (show_stack) from [] (dump_stack+0xc4/0xd8) +[] (dump_stack) from [] (__warn+0x104/0x108) +[] (__warn) from [] (warn_slowpath_fmt+0x74/0xb8) +[] (warn_slowpath_fmt) from [] (kobject_get+0xa0/0xa4) +[] (kobject_get) from [] (tpm_try_get_ops+0x14/0x54 [tpm]) +[] (tpm_try_get_ops [tpm]) from [] (tpm_common_write+0x38/0x60 [tpm]) +[] (tpm_common_write [tpm]) from [] (vfs_write+0xc4/0x3c0) +[] (vfs_write) from [] (ksys_write+0x58/0xcc) +[] (ksys_write) from [] (ret_fast_syscall+0x0/0x4c) +Exception stack(0xc226bfa8 to 0xc226bff0) +bfa0: 00000000 000105b4 00000003 beafe664 00000014 00000000 +bfc0: 00000000 000105b4 000103f8 00000004 00000000 00000000 b6f9c000 beafe684 +bfe0: 0000006c beafe648 0001056c b6eb6944 +---[ end trace d4b8409def9b8b1f ]--- + +The reason for this warning is the attempt to get the chip->dev reference +in tpm_common_write() although the reference counter is already zero. + +Since commit 8979b02aaf1d ("tpm: Fix reference count to main device") the +extra reference used to prevent a premature zero counter is never taken, +because the required TPM_CHIP_FLAG_TPM2 flag is never set. + +Fix this by moving the TPM 2 character device handling from +tpm_chip_alloc() to tpm_add_char_device() which is called at a later point +in time when the flag has been set in case of TPM2. + +Commit fdc915f7f719 ("tpm: expose spaces via a device link /dev/tpmrm") +already introduced function tpm_devs_release() to release the extra +reference but did not implement the required put on chip->devs that results +in the call of this function. + +Fix this by putting chip->devs in tpm_chip_unregister(). + +Finally move the new implementation for the TPM 2 handling into a new +function to avoid multiple checks for the TPM_CHIP_FLAG_TPM2 flag in the +good case and error cases. + +Cc: stable@vger.kernel.org +Fixes: fdc915f7f719 ("tpm: expose spaces via a device link /dev/tpmrm") +Fixes: 8979b02aaf1d ("tpm: Fix reference count to main device") +Co-developed-by: Jason Gunthorpe +Signed-off-by: Jason Gunthorpe +Signed-off-by: Lino Sanfilippo +Tested-by: Stefan Berger +Reviewed-by: Jason Gunthorpe +Reviewed-by: Jarkko Sakkinen +Signed-off-by: Jarkko Sakkinen +--- + drivers/char/tpm/tpm-chip.c | 46 +++++------------------------ + drivers/char/tpm/tpm.h | 3 + + drivers/char/tpm/tpm2-space.c | 65 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 76 insertions(+), 38 deletions(-) + +--- a/drivers/char/tpm/tpm-chip.c ++++ b/drivers/char/tpm/tpm-chip.c +@@ -134,14 +134,6 @@ static void tpm_dev_release(struct devic + kfree(chip); + } + +-static void tpm_devs_release(struct device *dev) +-{ +- struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs); +- +- /* release the master device reference */ +- put_device(&chip->dev); +-} +- + /** + * tpm_class_shutdown() - prepare the TPM device for loss of power. + * @dev: device to which the chip is associated. +@@ -211,7 +203,6 @@ struct tpm_chip *tpm_chip_alloc(struct d + chip->dev_num = rc; + + device_initialize(&chip->dev); +- device_initialize(&chip->devs); + + chip->dev.class = tpm_class; + chip->dev.class->shutdown = tpm_class_shutdown; +@@ -219,39 +210,20 @@ struct tpm_chip *tpm_chip_alloc(struct d + chip->dev.parent = pdev; + chip->dev.groups = chip->groups; + +- chip->devs.parent = pdev; +- chip->devs.class = tpmrm_class; +- chip->devs.release = tpm_devs_release; +- /* get extra reference on main device to hold on +- * behalf of devs. This holds the chip structure +- * while cdevs is in use. The corresponding put +- * is in the tpm_devs_release (TPM2 only) +- */ +- if (chip->flags & TPM_CHIP_FLAG_TPM2) +- get_device(&chip->dev); +- + if (chip->dev_num == 0) + chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR); + else + chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num); + +- chip->devs.devt = +- MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES); +- + rc = dev_set_name(&chip->dev, "tpm%d", chip->dev_num); + if (rc) + goto out; +- rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num); +- if (rc) +- goto out; + + if (!pdev) + chip->flags |= TPM_CHIP_FLAG_VIRTUAL; + + cdev_init(&chip->cdev, &tpm_fops); +- cdev_init(&chip->cdevs, &tpmrm_fops); + chip->cdev.owner = THIS_MODULE; +- chip->cdevs.owner = THIS_MODULE; + + chip->work_space.context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!chip->work_space.context_buf) { +@@ -268,7 +240,6 @@ struct tpm_chip *tpm_chip_alloc(struct d + return chip; + + out: +- put_device(&chip->devs); + put_device(&chip->dev); + return ERR_PTR(rc); + } +@@ -317,14 +288,9 @@ static int tpm_add_char_device(struct tp + } + + if (chip->flags & TPM_CHIP_FLAG_TPM2) { +- rc = cdev_device_add(&chip->cdevs, &chip->devs); +- if (rc) { +- dev_err(&chip->devs, +- "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", +- dev_name(&chip->devs), MAJOR(chip->devs.devt), +- MINOR(chip->devs.devt), rc); +- return rc; +- } ++ rc = tpm_devs_add(chip); ++ if (rc) ++ goto err_del_cdev; + } + + /* Make the chip available. */ +@@ -332,6 +298,10 @@ static int tpm_add_char_device(struct tp + idr_replace(&dev_nums_idr, chip, chip->dev_num); + mutex_unlock(&idr_lock); + ++ return 0; ++ ++err_del_cdev: ++ cdev_device_del(&chip->cdev, &chip->dev); + return rc; + } + +@@ -505,7 +505,7 @@ void tpm_chip_unregister(struct tpm_chip + hwrng_unregister(&chip->hwrng); + tpm_bios_log_teardown(chip); + if (chip->flags & TPM_CHIP_FLAG_TPM2) +- cdev_device_del(&chip->cdevs, &chip->devs); ++ tpm_devs_remove(chip); + tpm_del_char_device(chip); + } + EXPORT_SYMBOL_GPL(tpm_chip_unregister); +--- a/drivers/char/tpm/tpm.h ++++ b/drivers/char/tpm/tpm.h +@@ -618,4 +618,7 @@ int tpm2_prepare_space(struct tpm_chip * + u8 *cmd); + int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, + u32 cc, u8 *buf, size_t *bufsiz); ++ ++int tpm_devs_add(struct tpm_chip *chip); ++void tpm_devs_remove(struct tpm_chip *chip); + #endif +--- a/drivers/char/tpm/tpm2-space.c ++++ b/drivers/char/tpm/tpm2-space.c +@@ -531,3 +531,68 @@ int tpm2_commit_space(struct tpm_chip *c + + return 0; + } ++ ++/* ++ * Put the reference to the main device. ++ */ ++static void tpm_devs_release(struct device *dev) ++{ ++ struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs); ++ ++ /* release the master device reference */ ++ put_device(&chip->dev); ++} ++ ++/* ++ * Remove the device file for exposed TPM spaces and release the device ++ * reference. This may also release the reference to the master device. ++ */ ++void tpm_devs_remove(struct tpm_chip *chip) ++{ ++ cdev_device_del(&chip->cdevs, &chip->devs); ++ put_device(&chip->devs); ++} ++ ++/* ++ * Add a device file to expose TPM spaces. Also take a reference to the ++ * main device. ++ */ ++int tpm_devs_add(struct tpm_chip *chip) ++{ ++ int rc; ++ ++ device_initialize(&chip->devs); ++ chip->devs.parent = chip->dev.parent; ++ chip->devs.class = tpmrm_class; ++ ++ /* ++ * Get extra reference on main device to hold on behalf of devs. ++ * This holds the chip structure while cdevs is in use. The ++ * corresponding put is in the tpm_devs_release. ++ */ ++ get_device(&chip->dev); ++ chip->devs.release = tpm_devs_release; ++ chip->devs.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES); ++ cdev_init(&chip->cdevs, &tpmrm_fops); ++ chip->cdevs.owner = THIS_MODULE; ++ ++ rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num); ++ if (rc) ++ goto err_put_devs; ++ ++ rc = cdev_device_add(&chip->cdevs, &chip->devs); ++ if (rc) { ++ dev_err(&chip->devs, ++ "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", ++ dev_name(&chip->devs), MAJOR(chip->devs.devt), ++ MINOR(chip->devs.devt), rc); ++ goto err_put_devs; ++ } ++ ++ return 0; ++ ++err_put_devs: ++ put_device(&chip->devs); ++ ++ return rc; ++} diff --git a/patches.suse/tracepoint-Add-tracepoint_probe_register_may_exist-for-BPF-tracing.patch b/patches.suse/tracepoint-Add-tracepoint_probe_register_may_exist-for-BPF-tracing.patch new file mode 100644 index 0000000..5173a80 --- /dev/null +++ b/patches.suse/tracepoint-Add-tracepoint_probe_register_may_exist-for-BPF-tracing.patch @@ -0,0 +1,147 @@ +From: "Steven Rostedt (VMware)" +Date: Tue, 29 Jun 2021 09:40:10 -0400 +Subject: tracepoint: Add tracepoint_probe_register_may_exist() for BPF tracing +Git-commit: 9913d5745bd720c4266805c8d29952a3702e4eca +Patch-mainline: v5.14-rc1 +References: git-fixes + +All internal use cases for tracepoint_probe_register() is set to not ever +be called with the same function and data. If it is, it is considered a +bug, as that means the accounting of handling tracepoints is corrupted. +If the function and data for a tracepoint is already registered when +tracepoint_probe_register() is called, it will call WARN_ON_ONCE() and +return with EEXISTS. + +The BPF system call can end up calling tracepoint_probe_register() with +the same data, which now means that this can trigger the warning because +of a user space process. As WARN_ON_ONCE() should not be called because +user space called a system call with bad data, there needs to be a way to +register a tracepoint without triggering a warning. + +Enter tracepoint_probe_register_may_exist(), which can be called, but will +not cause a WARN_ON() if the probe already exists. It will still error out +with EEXIST, which will then be sent to the user space that performed the +BPF system call. + +This keeps the previous testing for issues with other users of the +tracepoint code, while letting BPF call it with duplicated data and not +warn about it. + +Link: https://lore.kernel.org/lkml/20210626135845.4080-1-penguin-kernel@I-love.SAKURA.ne.jp/ +Link: https://syzkaller.appspot.com/bug?id=41f4318cf01762389f4d1c1c459da4f542fe5153 + +Cc: stable@vger.kernel.org +Fixes: c4f6699dfcb85 ("bpf: introduce BPF_RAW_TRACEPOINT") +Reported-by: syzbot +Reported-by: Tetsuo Handa +Tested-by: syzbot+721aa903751db87aa244@syzkaller.appspotmail.com +Signed-off-by: Steven Rostedt (VMware) +Acked-by: Petr Pavlu +--- + include/linux/tracepoint.h | 10 ++++++++++ + kernel/trace/bpf_trace.c | 3 ++- + kernel/tracepoint.c | 33 ++++++++++++++++++++++++++++++--- + 3 files changed, 42 insertions(+), 4 deletions(-) + +diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h +index 13f65420f188..ab58696d0ddd 100644 +--- a/include/linux/tracepoint.h ++++ b/include/linux/tracepoint.h +@@ -41,7 +41,17 @@ extern int + tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data, + int prio); + extern int ++tracepoint_probe_register_prio_may_exist(struct tracepoint *tp, void *probe, void *data, ++ int prio); ++extern int + tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data); ++static inline int ++tracepoint_probe_register_may_exist(struct tracepoint *tp, void *probe, ++ void *data) ++{ ++ return tracepoint_probe_register_prio_may_exist(tp, probe, data, ++ TRACEPOINT_DEFAULT_PRIO); ++} + extern void + for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv), + void *priv); +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index 7a52bc172841..f0568b3d6bd1 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -1840,7 +1840,8 @@ static int __bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog * + if (prog->aux->max_ctx_offset > btp->num_args * sizeof(u64)) + return -EINVAL; + +- return tracepoint_probe_register(tp, (void *)btp->bpf_func, prog); ++ return tracepoint_probe_register_may_exist(tp, (void *)btp->bpf_func, ++ prog); + } + + int bpf_probe_register(struct bpf_raw_event_map *btp, struct bpf_prog *prog) +diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c +index 9f478d29b926..976bf8ce8039 100644 +--- a/kernel/tracepoint.c ++++ b/kernel/tracepoint.c +@@ -273,7 +273,8 @@ static void tracepoint_update_call(struct tracepoint *tp, struct tracepoint_func + * Add the probe function to a tracepoint. + */ + static int tracepoint_add_func(struct tracepoint *tp, +- struct tracepoint_func *func, int prio) ++ struct tracepoint_func *func, int prio, ++ bool warn) + { + struct tracepoint_func *old, *tp_funcs; + int ret; +@@ -288,7 +289,7 @@ static int tracepoint_add_func(struct tracepoint *tp, + lockdep_is_held(&tracepoints_mutex)); + old = func_add(&tp_funcs, func, prio); + if (IS_ERR(old)) { +- WARN_ON_ONCE(PTR_ERR(old) != -ENOMEM); ++ WARN_ON_ONCE(warn && PTR_ERR(old) != -ENOMEM); + return PTR_ERR(old); + } + +@@ -343,6 +344,32 @@ static int tracepoint_remove_func(struct tracepoint *tp, + return 0; + } + ++/** ++ * tracepoint_probe_register_prio_may_exist - Connect a probe to a tracepoint with priority ++ * @tp: tracepoint ++ * @probe: probe handler ++ * @data: tracepoint data ++ * @prio: priority of this function over other registered functions ++ * ++ * Same as tracepoint_probe_register_prio() except that it will not warn ++ * if the tracepoint is already registered. ++ */ ++int tracepoint_probe_register_prio_may_exist(struct tracepoint *tp, void *probe, ++ void *data, int prio) ++{ ++ struct tracepoint_func tp_func; ++ int ret; ++ ++ mutex_lock(&tracepoints_mutex); ++ tp_func.func = probe; ++ tp_func.data = data; ++ tp_func.prio = prio; ++ ret = tracepoint_add_func(tp, &tp_func, prio, false); ++ mutex_unlock(&tracepoints_mutex); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(tracepoint_probe_register_prio_may_exist); ++ + /** + * tracepoint_probe_register - Connect a probe to a tracepoint + * @tp: tracepoint +@@ -366,7 +393,7 @@ int tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, + tp_func.func = probe; + tp_func.data = data; + tp_func.prio = prio; +- ret = tracepoint_add_func(tp, &tp_func, prio); ++ ret = tracepoint_add_func(tp, &tp_func, prio, true); + mutex_unlock(&tracepoints_mutex); + return ret; + } + diff --git a/patches.suse/tracing-Fix-race-in-perf_trace_buf-initialization.patch b/patches.suse/tracing-Fix-race-in-perf_trace_buf-initialization.patch new file mode 100644 index 0000000..cd03268 --- /dev/null +++ b/patches.suse/tracing-Fix-race-in-perf_trace_buf-initialization.patch @@ -0,0 +1,115 @@ +From: Prateek Sood +Date: Tue, 15 Oct 2019 11:47:25 +0530 +Subject: tracing: Fix race in perf_trace_buf initialization +Git-commit: 6b1340cc00edeadd52ebd8a45171f38c8de2a387 +Patch-mainline: v5.4-rc5 +References: git-fixes + +A race condition exists while initialiazing perf_trace_buf from +perf_trace_init() and perf_kprobe_init(). + + CPU0 CPU1 +perf_trace_init() + mutex_lock(&event_mutex) + perf_trace_event_init() + perf_trace_event_reg() + total_ref_count == 0 + buf = alloc_percpu() + perf_trace_buf[i] = buf + tp_event->class->reg() //fails perf_kprobe_init() + goto fail perf_trace_event_init() + perf_trace_event_reg() + fail: + total_ref_count == 0 + + total_ref_count == 0 + buf = alloc_percpu() + perf_trace_buf[i] = buf + tp_event->class->reg() + total_ref_count++ + + free_percpu(perf_trace_buf[i]) + perf_trace_buf[i] = NULL + +Any subsequent call to perf_trace_event_reg() will observe total_ref_count > 0, +causing the perf_trace_buf to be always NULL. This can result in perf_trace_buf +getting accessed from perf_trace_buf_alloc() without being initialized. Acquiring +event_mutex in perf_kprobe_init() before calling perf_trace_event_init() should +fix this race. + +The race caused the following bug: + + Unable to handle kernel paging request at virtual address 0000003106f2003c + Mem abort info: + ESR = 0x96000045 + Exception class = DABT (current EL), IL = 32 bits + SET = 0, FnV = 0 + EA = 0, S1PTW = 0 + Data abort info: + ISV = 0, ISS = 0x00000045 + CM = 0, WnR = 1 + user pgtable: 4k pages, 39-bit VAs, pgdp = ffffffc034b9b000 + [0000003106f2003c] pgd=0000000000000000, pud=0000000000000000 + Internal error: Oops: 96000045 [#1] PREEMPT SMP + Process syz-executor (pid: 18393, stack limit = 0xffffffc093190000) + pstate: 80400005 (Nzcv daif +PAN -UAO) + pc : __memset+0x20/0x1ac + lr : memset+0x3c/0x50 + sp : ffffffc09319fc50 + + __memset+0x20/0x1ac + perf_trace_buf_alloc+0x140/0x1a0 + perf_trace_sys_enter+0x158/0x310 + syscall_trace_enter+0x348/0x7c0 + el0_svc_common+0x11c/0x368 + el0_svc_handler+0x12c/0x198 + el0_svc+0x8/0xc + +Ramdumps showed the following: + total_ref_count = 3 + perf_trace_buf = ( + 0x0 -> NULL, + 0x0 -> NULL, + 0x0 -> NULL, + 0x0 -> NULL) + +Link: http://lkml.kernel.org/r/1571120245-4186-1-git-send-email-prsood@codeaurora.org + +Cc: stable@vger.kernel.org +Fixes: e12f03d7031a9 ("perf/core: Implement the 'perf_kprobe' PMU") +Acked-by: Song Liu +Signed-off-by: Prateek Sood +Signed-off-by: Steven Rostedt (VMware) +Acked-by: Petr Pavlu +--- + kernel/trace/trace_event_perf.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c +index 0892e38ed6fb..a9dfa04ffa44 100644 +--- a/kernel/trace/trace_event_perf.c ++++ b/kernel/trace/trace_event_perf.c +@@ -272,9 +272,11 @@ int perf_kprobe_init(struct perf_event *p_event, bool is_retprobe) + goto out; + } + ++ mutex_lock(&event_mutex); + ret = perf_trace_event_init(tp_event, p_event); + if (ret) + destroy_local_trace_kprobe(tp_event); ++ mutex_unlock(&event_mutex); + out: + kfree(func); + return ret; +@@ -282,8 +284,10 @@ int perf_kprobe_init(struct perf_event *p_event, bool is_retprobe) + + void perf_kprobe_destroy(struct perf_event *p_event) + { ++ mutex_lock(&event_mutex); + perf_trace_event_close(p_event); + perf_trace_event_unreg(p_event); ++ mutex_unlock(&event_mutex); + + destroy_local_trace_kprobe(p_event->tp_event); + } + diff --git a/patches.suse/tracing-perf-Use-strndup_user-instead-of-buggy-open-coded-version.patch b/patches.suse/tracing-perf-Use-strndup_user-instead-of-buggy-open-coded-version.patch new file mode 100644 index 0000000..530b055 --- /dev/null +++ b/patches.suse/tracing-perf-Use-strndup_user-instead-of-buggy-open-coded-version.patch @@ -0,0 +1,54 @@ +From: Jann Horn +Date: Wed, 20 Feb 2019 17:54:43 +0100 +Subject: tracing/perf: Use strndup_user() instead of buggy open-coded version +Git-commit: 83540fbc8812a580b6ad8f93f4c29e62e417687e +Patch-mainline: v5.1-rc1 +References: git-fixes + +The first version of this method was missing the check for +`ret == PATH_MAX`; then such a check was added, but it didn't call kfree() +on error, so there was still a small memory leak in the error case. +Fix it by using strndup_user() instead of open-coding it. + +Link: http://lkml.kernel.org/r/20190220165443.152385-1-jannh@google.com + +Cc: Ingo Molnar +Cc: stable@vger.kernel.org +Fixes: 0eadcc7a7bc0 ("perf/core: Fix perf_uprobe_init()") +Reviewed-by: Masami Hiramatsu +Acked-by: Song Liu +Signed-off-by: Jann Horn +Signed-off-by: Steven Rostedt (VMware) +Acked-by: Petr Pavlu +--- + kernel/trace/trace_event_perf.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c +index 76217bbef815..4629a6104474 100644 +--- a/kernel/trace/trace_event_perf.c ++++ b/kernel/trace/trace_event_perf.c +@@ -299,15 +299,13 @@ int perf_uprobe_init(struct perf_event *p_event, + + if (!p_event->attr.uprobe_path) + return -EINVAL; +- path = kzalloc(PATH_MAX, GFP_KERNEL); +- if (!path) +- return -ENOMEM; +- ret = strncpy_from_user( +- path, u64_to_user_ptr(p_event->attr.uprobe_path), PATH_MAX); +- if (ret == PATH_MAX) +- return -E2BIG; +- if (ret < 0) +- goto out; ++ ++ path = strndup_user(u64_to_user_ptr(p_event->attr.uprobe_path), ++ PATH_MAX); ++ if (IS_ERR(path)) { ++ ret = PTR_ERR(path); ++ return (ret == -EINVAL) ? -E2BIG : ret; ++ } + if (path[0] == '\0') { + ret = -EINVAL; + goto out; + diff --git a/patches.suse/tracing-uprobes-Check-the-return-value-of-kstrdup-for-tu-filename.patch b/patches.suse/tracing-uprobes-Check-the-return-value-of-kstrdup-for-tu-filename.patch new file mode 100644 index 0000000..6c73f08 --- /dev/null +++ b/patches.suse/tracing-uprobes-Check-the-return-value-of-kstrdup-for-tu-filename.patch @@ -0,0 +1,39 @@ +From: Xiaoke Wang +Date: Tue, 14 Dec 2021 09:28:02 +0800 +Subject: tracing/uprobes: Check the return value of kstrdup() for tu->filename +Git-commit: 8c7224245557707c613f130431cafbaaa4889615 +Patch-mainline: v5.17-rc1 +References: git-fixes + +kstrdup() returns NULL when some internal memory errors happen, it is +better to check the return value of it so to catch the memory error in +time. + +Link: https://lkml.kernel.org/r/tencent_3C2E330722056D7891D2C83F29C802734B06@qq.com + +Acked-by: Masami Hiramatsu +Fixes: 33ea4b24277b ("perf/core: Implement the 'perf_uprobe' PMU") +Signed-off-by: Xiaoke Wang +Signed-off-by: Steven Rostedt +Acked-by: Petr Pavlu +--- + kernel/trace/trace_uprobe.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c +index 3bd09d612137..08b0e8417302 100644 +--- a/kernel/trace/trace_uprobe.c ++++ b/kernel/trace/trace_uprobe.c +@@ -1609,6 +1609,11 @@ create_local_trace_uprobe(char *name, unsigned long offs, + tu->offset = offs; + tu->path = path; + tu->filename = kstrdup(name, GFP_KERNEL); ++ if (!tu->filename) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ + init_trace_event_call(tu, &tu->tp.call); + + if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) { + diff --git a/patches.suse/usbnet-Fix-linkwatch-use-after-free-on-disconnect.patch b/patches.suse/usbnet-Fix-linkwatch-use-after-free-on-disconnect.patch new file mode 100644 index 0000000..003a64f --- /dev/null +++ b/patches.suse/usbnet-Fix-linkwatch-use-after-free-on-disconnect.patch @@ -0,0 +1,89 @@ +From a69e617e533edddf3fa3123149900f36e0a6dc74 Mon Sep 17 00:00:00 2001 +From: Lukas Wunner +Date: Thu, 23 Jun 2022 14:50:59 +0200 +Subject: [PATCH] usbnet: Fix linkwatch use-after-free on disconnect +Git-commit: a69e617e533edddf3fa3123149900f36e0a6dc74 +References: git-fixes +Patch-mainline: v6.0-rc1 + +usbnet uses the work usbnet_deferred_kevent() to perform tasks which may +sleep. On disconnect, completion of the work was originally awaited in +->ndo_stop(). But in 2003, that was moved to ->disconnect() by historic +commit "[PATCH] USB: usbnet, prevent exotic rtnl deadlock": + + https://git.kernel.org/tglx/history/c/0f138bbfd83c + +The change was made because back then, the kernel's workqueue +implementation did not allow waiting for a single work. One had to wait +for completion of *all* work by calling flush_scheduled_work(), and that +could deadlock when waiting for usbnet_deferred_kevent() with rtnl_mutex +held in ->ndo_stop(). + +The commit solved one problem but created another: It causes a +use-after-free in USB Ethernet drivers aqc111.c, asix_devices.c, +ax88179_178a.c, ch9200.c and smsc75xx.c: + +* If the drivers receive a link change interrupt immediately before + disconnect, they raise EVENT_LINK_RESET in their (non-sleepable) + ->status() callback and schedule usbnet_deferred_kevent(). +* usbnet_deferred_kevent() invokes the driver's ->link_reset() callback, + which calls netif_carrier_{on,off}(). +* That in turn schedules the work linkwatch_event(). + +Because usbnet_deferred_kevent() is awaited after unregister_netdev(), +netif_carrier_{on,off}() may operate on an unregistered netdev and +linkwatch_event() may run after free_netdev(), causing a use-after-free. + +In 2010, usbnet was changed to only wait for a single instance of +usbnet_deferred_kevent() instead of *all* work by commit 23f333a2bfaf +("drivers/net: don't use flush_scheduled_work()"). + +Unfortunately the commit neglected to move the wait back to +->ndo_stop(). Rectify that omission at long last. + +Reported-by: Jann Horn +Link: https://lore.kernel.org/netdev/CAG48ez0MHBbENX5gCdHAUXZ7h7s20LnepBF-pa5M=7Bi-jZrEA@mail.gmail.com/ +Reported-by: Oleksij Rempel +Link: https://lore.kernel.org/netdev/20220315113841.GA22337@pengutronix.de/ +Signed-off-by: Lukas Wunner +Cc: stable@vger.kernel.org +Acked-by: Oliver Neukum +Link: https://lore.kernel.org/r/d1c87ebe9fc502bffcd1576e238d685ad08321e4.1655987888.git.lukas@wunner.de +Signed-off-by: Jakub Kicinski +Signed-off-by: Oliver Neukum +--- + drivers/net/usb/usbnet.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c +index dc79811535c2..713cfc2723b8 100644 +--- a/drivers/net/usb/usbnet.c ++++ b/drivers/net/usb/usbnet.c +@@ -849,13 +849,11 @@ int usbnet_stop (struct net_device *net) + + mpn = !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags); + +- /* deferred work (task, timer, softirq) must also stop. +- * can't flush_scheduled_work() until we drop rtnl (later), +- * else workers could deadlock; so make workers a NOP. +- */ ++ /* deferred work (timer, softirq, task) must also stop */ + dev->flags = 0; + del_timer_sync (&dev->delay); + tasklet_kill (&dev->bh); ++ cancel_work_sync(&dev->kevent); + if (!pm) + usb_autopm_put_interface(dev->intf); + +@@ -1619,8 +1617,6 @@ void usbnet_disconnect (struct usb_interface *intf) + net = dev->net; + unregister_netdev (net); + +- cancel_work_sync(&dev->kevent); +- + usb_scuttle_anchored_urbs(&dev->deferred); + + if (dev->driver_info->unbind) +-- +2.35.3 + diff --git a/patches.suse/x86-speculation-Add-RSB-VM-Exit-protections.patch b/patches.suse/x86-speculation-Add-RSB-VM-Exit-protections.patch index 94a1f45..ceabf7c 100644 --- a/patches.suse/x86-speculation-Add-RSB-VM-Exit-protections.patch +++ b/patches.suse/x86-speculation-Add-RSB-VM-Exit-protections.patch @@ -105,10 +105,10 @@ Signed-off-by: Borislav Petkov --- arch/x86/include/asm/cpufeatures.h | 2 + arch/x86/include/asm/msr-index.h | 4 ++ - arch/x86/include/asm/nospec-branch.h | 35 +++++++++++++++--- + arch/x86/include/asm/nospec-branch.h | 40 +++++++++++++++++---- arch/x86/kernel/cpu/bugs.c | 65 ++++++++++++++++++++++++++++++++++- arch/x86/kernel/cpu/common.c | 10 ++++- - 5 files changed, 106 insertions(+), 10 deletions(-) + 5 files changed, 111 insertions(+), 10 deletions(-) --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -142,11 +142,12 @@ Signed-off-by: Borislav Petkov #define L1D_FLUSH BIT(0) /* --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h -@@ -138,14 +138,28 @@ +@@ -140,14 +140,29 @@ #endif .endm +.macro ISSUE_UNBALANCED_RET_GUARD ++ ANNOTATE_INTRA_FUNCTION_CALL + call .Lunbalanced_ret_guard_\@ + int3 +.Lunbalanced_ret_guard_\@: @@ -172,7 +173,7 @@ Signed-off-by: Borislav Petkov .Lskip_rsb_\@: #endif .endm -@@ -284,13 +298,20 @@ static inline void vmexit_fill_RSB(void) +@@ -286,13 +301,24 @@ static inline void vmexit_fill_RSB(void) #ifdef CONFIG_RETPOLINE unsigned long loops; @@ -187,6 +188,10 @@ Signed-off-by: Borislav Petkov + "jmp .Lunbalanced", X86_FEATURE_RSB_VMEXIT_LITE) + __stringify(__FILL_RETURN_BUFFER(%0,RSB_CLEAR_LOOPS,%1)) + ".Lunbalanced:\n\t" ++ "999: \n\t" ++ ".pushsection .discard.intra_function_calls\n\t" ++ ".long 999b\n\t" ++ ".popsection\n\t" + "call .Lunbalanced_ret_guard\n\t" + "int3\n\t" + ".Lunbalanced_ret_guard:\n\t" diff --git a/patches.suse/x86-speculation-change-fill_return_buffer-to-work-with-objtool.patch b/patches.suse/x86-speculation-change-fill_return_buffer-to-work-with-objtool.patch index 72b60e0..612a847 100644 --- a/patches.suse/x86-speculation-change-fill_return_buffer-to-work-with-objtool.patch +++ b/patches.suse/x86-speculation-change-fill_return_buffer-to-work-with-objtool.patch @@ -31,8 +31,8 @@ Link: https://lkml.kernel.org/r/20200428191700.032079304@infradead.org Acked-by: Borislav Petkov --- - arch/x86/include/asm/nospec-branch.h | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) + arch/x86/include/asm/nospec-branch.h | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -50,7 +50,21 @@ Acked-by: Borislav Petkov /* * Fill the CPU return stack buffer. -@@ -50,9 +52,9 @@ +@@ -38,21 +40,23 @@ + #define __FILL_RETURN_BUFFER(reg, nr, sp) \ + mov $(nr/2), reg; \ + 771: \ ++ ANNOTATE_INTRA_FUNCTION_CALL \ + call 772f; \ + 773: /* speculation trap */ \ + pause; \ + lfence; \ + jmp 773b; \ + 772: \ ++ ANNOTATE_INTRA_FUNCTION_CALL \ + call 774f; \ + 775: /* speculation trap */ \ + pause; \ lfence; \ jmp 775b; \ 774: \ @@ -62,7 +76,7 @@ Acked-by: Borislav Petkov #ifdef __ASSEMBLY__ -@@ -142,10 +144,8 @@ +@@ -142,10 +146,8 @@ */ .macro FILL_RETURN_BUFFER reg:req nr:req ftr:req #ifdef CONFIG_RETPOLINE diff --git a/patches.suse/xen-xenbus-fix-return-type-in-xenbus_file_read.patch b/patches.suse/xen-xenbus-fix-return-type-in-xenbus_file_read.patch new file mode 100644 index 0000000..358c323 --- /dev/null +++ b/patches.suse/xen-xenbus-fix-return-type-in-xenbus_file_read.patch @@ -0,0 +1,50 @@ +Patch-mainline: v6.0-rc1 +Git-commit: 32ad11127b95236dfc52375f3707853194a7f4b4 +References: git-fixes +From: Dan Carpenter +Date: Thu, 4 Aug 2022 10:11:33 +0300 +Subject: [PATCH] xen/xenbus: fix return type in xenbus_file_read() + +This code tries to store -EFAULT in an unsigned int. The +xenbus_file_read() function returns type ssize_t so the negative value +is returned as a positive value to the user. + +This change forces another change to the min() macro. Originally, the +min() macro used "unsigned" type which checkpatch complains about. Also +unsigned type would break if "len" were not capped at MAX_RW_COUNT. Use +size_t for the min(). (No effect on runtime for the min_t() change). + +Fixes: 2fb3683e7b16 ("xen: Add xenbus device driver") +Signed-off-by: Dan Carpenter +Reviewed-by: Oleksandr Tyshchenko +Link: https://lore.kernel.org/r/YutxJUaUYRG/VLVc@kili +Signed-off-by: Juergen Gross +--- + drivers/xen/xenbus/xenbus_dev_frontend.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c +index 597af455a522..0792fda49a15 100644 +--- a/drivers/xen/xenbus/xenbus_dev_frontend.c ++++ b/drivers/xen/xenbus/xenbus_dev_frontend.c +@@ -128,7 +128,7 @@ static ssize_t xenbus_file_read(struct file *filp, + { + struct xenbus_file_priv *u = filp->private_data; + struct read_buffer *rb; +- unsigned i; ++ ssize_t i; + int ret; + + mutex_lock(&u->reply_mutex); +@@ -148,7 +148,7 @@ static ssize_t xenbus_file_read(struct file *filp, + rb = list_entry(u->read_buffers.next, struct read_buffer, list); + i = 0; + while (i < len) { +- unsigned sz = min((unsigned)len - i, rb->len - rb->cons); ++ size_t sz = min_t(size_t, len - i, rb->len - rb->cons); + + ret = copy_to_user(ubuf + i, &rb->msg[rb->cons], sz); + +-- +2.35.3 + diff --git a/patches.suse/xprtrdma-Fix-trace-point-use-after-free-race.patch b/patches.suse/xprtrdma-Fix-trace-point-use-after-free-race.patch new file mode 100644 index 0000000..9d2cffc --- /dev/null +++ b/patches.suse/xprtrdma-Fix-trace-point-use-after-free-race.patch @@ -0,0 +1,83 @@ +From: Chuck Lever +Date: Sun, 19 Apr 2020 20:03:05 -0400 +Subject: xprtrdma: Fix trace point use-after-free race +Git-commit: bdb2ce82818577ba6e57b7d68b698b8d17329281 +Patch-mainline: v5.7-rc4 +References: git-fixes + +It's not safe to use resources pointed to by the @send_wr of +ib_post_send() _after_ that function returns. Those resources are +typically freed by the Send completion handler, which can run before +ib_post_send() returns. + +Thus the trace points currently around ib_post_send() in the +client's RPC/RDMA transport are a hazard, even when they are +disabled. Rearrange them so that they touch the Work Request only +_before_ ib_post_send() is invoked. + +Fixes: ab03eff58eb5 ("xprtrdma: Add trace points in RPC Call transmit paths") +Signed-off-by: Chuck Lever +Signed-off-by: Anna Schumaker +Acked-by: Petr Pavlu +--- + include/trace/events/rpcrdma.h | 12 ++++-------- + net/sunrpc/xprtrdma/verbs.c | 2 +- + 2 files changed, 5 insertions(+), 9 deletions(-) + +diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h +index 051f26fedc4d..72f043876019 100644 +--- a/include/trace/events/rpcrdma.h ++++ b/include/trace/events/rpcrdma.h +@@ -692,11 +692,10 @@ TRACE_EVENT(xprtrdma_prepsend_failed, + + TRACE_EVENT(xprtrdma_post_send, + TP_PROTO( +- const struct rpcrdma_req *req, +- int status ++ const struct rpcrdma_req *req + ), + +- TP_ARGS(req, status), ++ TP_ARGS(req), + + TP_STRUCT__entry( + __field(const void *, req) +@@ -705,7 +704,6 @@ TRACE_EVENT(xprtrdma_post_send, + __field(const void *, req) + __field(int, num_sge) + __field(int, signaled) +- __field(int, status) + ), + + TP_fast_assign( +@@ -718,13 +716,11 @@ TRACE_EVENT(xprtrdma_post_send, + __entry->num_sge = req->rl_sendctx->sc_wr.num_sge; + __entry->signaled = req->rl_sendctx->sc_wr.send_flags & + IB_SEND_SIGNALED; +- __entry->status = status; + ), + +- TP_printk("req=%p, %d SGEs%s, status=%d", ++ TP_printk("req=%p, %d SGEs%s", + __entry->req, __entry->num_sge, +- (__entry->signaled ? ", signaled" : ""), +- __entry->status ++ (__entry->signaled ? ", signaled" : "") + ) + ); + +diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c +index 29ae982d69cf..05c4d3a9cda2 100644 +--- a/net/sunrpc/xprtrdma/verbs.c ++++ b/net/sunrpc/xprtrdma/verbs.c +@@ -1356,8 +1356,8 @@ int rpcrdma_post_sends(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) + --ep->rep_send_count; + } + ++ trace_xprtrdma_post_send(req); + rc = ia->ri_ops->ro_send(ia, req); +- trace_xprtrdma_post_send(req, rc); + if (rc) + return -ENOTCONN; + return 0; + diff --git a/scripts/lib/SUSE/MyBS.pm b/scripts/lib/SUSE/MyBS.pm index 71cf2cc..4517ccd 100644 --- a/scripts/lib/SUSE/MyBS.pm +++ b/scripts/lib/SUSE/MyBS.pm @@ -12,6 +12,8 @@ use HTTP::Request; use File::Temp qw(tempfile); use Config::IniFiles; use Digest::MD5; +use IPC::Open2; +use MIME::Base64; use SUSE::MyBS::Buildresults; @@ -62,7 +64,7 @@ sub new { die join("\n", @Config::IniFiles::errors), "\n"; } my %cred; - for my $kw (qw(user pass passx keyring gnome_keyring credentials_mgr_class)) { + for my $kw (qw(user pass passx sshkey keyring gnome_keyring credentials_mgr_class)) { for my $section ($api_url, "$api_url/", $self->{url}->host) { if (exists($config{$section}) && exists($config{$section}{$kw})) { @@ -71,52 +73,74 @@ sub new { } } } - if (exists($cred{credentials_mgr_class})) { - if ($cred{credentials_mgr_class} eq "osc.credentials.ObfuscatedConfigFileCredentialsManager") { - $cred{passx}=$cred{pass}; - } elsif ($cred{credentials_mgr_class} eq "osc.credentials.KeyringCredentialsManager:pass.Keyring") { - # emulate by invoking the pass command directly + if (exists($cred{sshkey})) { + my $sshkey = $cred{sshkey}; + my $home = $ENV{'HOME'} . "/"; + + $sshkey =~ s,^~[/],$home,; + $sshkey="~/.ssh/" . $sshkey unless $sshkey =~ /^\//; + $sshkey =~ s,^~[/],$home,; + die "Cannot access SSH key file $sshkey\n" unless -r $sshkey; + $self->{sshkey} = $sshkey; + $self->{user} = $cred{user}; + if ( -x "/usr/lib/osc/ssh-keygen") { + print STDERR "Using OBS keygen in /usr/lib/osc/ssh-keygen\n"; + $self->{keygen} = "/usr/lib/osc/ssh-keygen"; + } else { + $self->{keygen} = "ssh-keygen"; + } + } else { + if (exists($cred{credentials_mgr_class})) { + if ($cred{credentials_mgr_class} eq "osc.credentials.ObfuscatedConfigFileCredentialsManager") { + $cred{passx}=$cred{pass}; + } elsif ($cred{credentials_mgr_class} eq "osc.credentials.KeyringCredentialsManager:pass.Keyring") { + # emulate by invoking the pass command directly + my $api = $api_url; + $api =~ s/^https?:\/\///; + open(my $secret, "pass show $api/$cred{user} |") + or die "Failed to invoke pass\n"; + $cred{pass} = <$secret>; + close($secret); + die "Failed to obtain secret from pass\n" + if !$cred{pass}; + chomp($cred{pass}); + } + } + if (exists($cred{passx})) { + # Not available on SLES10, hence the 'require' + require MIME::Base64; + require IO::Uncompress::Bunzip2; + my $bz2 = MIME::Base64::decode_base64($cred{passx}); + $cred{pass} = ""; + IO::Uncompress::Bunzip2::bunzip2(\$bz2 => \$cred{pass}) + or die "Decoding password for $api_url failed: $IO::Uncompress::Bunzip2::Bunzip2Error\n"; + } + if (!exists($cred{pass}) && (exists($cred{keyring}) || exists($cred{gnome_keyring}))) { my $api = $api_url; $api =~ s/^https?:\/\///; - open(my $secret, "pass show $api/$cred{user} |") - or die "Failed to invoke pass\n"; + open(my $secret, "secret-tool lookup service $api username $cred{user} |") + or die "Please install the \"secret-tool\" package to use a keyring\n"; $cred{pass} = <$secret>; close($secret); - die "Failed to obtain secret from pass\n" - if !$cred{pass}; + die "Failed to obtain secret from secret-tool\n" + if !$cred{pass}; chomp($cred{pass}); } } - if (exists($cred{passx})) { - # Not available on SLES10, hence the 'require' - require MIME::Base64; - require IO::Uncompress::Bunzip2; - my $bz2 = MIME::Base64::decode_base64($cred{passx}); - $cred{pass} = ""; - IO::Uncompress::Bunzip2::bunzip2(\$bz2 => \$cred{pass}) - or die "Decoding password for $api_url failed: $IO::Uncompress::Bunzip2::Bunzip2Error\n"; - } - if (!exists($cred{pass}) && (exists($cred{keyring}) || exists($cred{gnome_keyring}))) { - my $api = $api_url; - $api =~ s/^https?:\/\///; - open(my $secret, "secret-tool lookup service $api username $cred{user} |") - or die "Please install the \"secret-tool\" package to use a keyring\n"; - $cred{pass} = <$secret>; - close($secret); - die "Failed to obtain secret from secret-tool\n" - if !$cred{pass}; - chomp($cred{pass}); - } - if (!exists($cred{user}) || !exists($cred{pass})) { - die "Error: Username or password for $api_url not set in ~/.oscrc\n" . - "Error: Run `osc -A $api_url ls' once\n"; + if (!exists($cred{user}) || (!exists($cred{pass}) && !exists($cred{sshkey}))) { + die "Error: Username or password for $api_url not set in ~/.oscrc\n" . + "Error: Run `osc -A $api_url ls' once\n"; } $self->{ua} = LWP::UserAgent->new; my $realm = "Use your developer account"; $realm = "Use your SUSE developer account" if $api_url =~ /opensuse/; - $self->{ua}->credentials($self->{url}->host_port, $realm, - $cred{user}, $cred{pass}); + if (exists($self->{sshkey})) { + $self->{realm} = $realm; + } else { + $self->{ua}->credentials($self->{url}->host_port, $realm, + $cred{user}, $cred{pass}); + } if ($self->{ua}->can('ssl_opts')) { $self->{ua}->ssl_opts(verify_hostname => 1); } @@ -142,11 +166,52 @@ sub new { return $self; } +sub ssh_auth { + my $self = $_[0]; + my $now = time(); + my $key = $self->{sshkey}; + my $realm = $self->{realm}; + my $user = $self->{user}; + my $data = "(created): $now"; + my $keygen = $self->{keygen}; + + my $pid = open2(my $reader, my $writer, $keygen, '-Y', 'sign', '-f', $key, '-n', $realm, '-q'); + print $writer $data; + close $writer; + my $sig = do { + local $/ = undef; + <$reader>; + }; + die "Failed to get SSH signature.\n" unless $sig =~ /\A-----BEGIN SSH SIGNATURE-----\n\K.*(?=\n-----END SSH SIGNATURE-----\Z)/ms; + $sig = $&; + $sig = encode_base64(decode_base64($sig), ''); + $sig = "keyId=\"$user\",algorithm=\"ssh\",headers=\"(created)\",created=$now,signature=\"$sig\""; + $sig = "Signature $sig"; + + waitpid $pid, 0; + + return $sig; +} + sub api { my ($self, $method, $path, $data) = @_; my $url = $self->{url} . $path; my $req = HTTP::Request->new($method => $url); + my $cookies = $self->{cookies}; + if (keys % { $cookies } ) { + my @cookies = (); + foreach my $cookie (keys % { $cookies } ) { + @cookies = (@cookies, "$cookie=" . $cookies->{$cookie}); + } + my $cookies = join("; ", @cookies); + #print "Cookies: $cookies\n"; + $req->header("Cookie" => $cookies); + } else { + if (exists($self->{sshkey})) { + $req->header("Authorization", $self->ssh_auth()); + } + } if ($data) { $req->add_content($data); $req->header("Content-type" => "application/octet-stream"); @@ -159,6 +224,14 @@ sub api { #print STDERR $res->as_string(); die "$method $path: @{[$res->message()]} (HTTP @{[$res->code()]})\n"; } + my $headers = $res->headers(); + my $cookie = $headers->{'set-cookie'}; + if ($cookie) { + my @cookie = split /\s*([^=;]+)\s*=\s*([^=;]+)\s*;?/, $cookie; + #print "Cookie: $cookie[1]=$cookie[2]\n"; + $self->{cookies}{$cookie[1]} = $cookie[2]; + } + return $res->content(); } diff --git a/scripts/sequence-patch.sh b/scripts/sequence-patch.sh index ce51db4..15f9409 100755 --- a/scripts/sequence-patch.sh +++ b/scripts/sequence-patch.sh @@ -38,7 +38,7 @@ esac usage() { cat <> $PATCH_DIR/series rapidquilt push -a -d $PATCH_DIR -p $PWD $fuzz $DRY_RUN status=$? - - PATCHES=( ${PATCHES_AFTER[@]} ) } apply_fast_patches() { @@ -100,20 +98,83 @@ apply_fast_patches() { echo "Logfile: $PATCH_LOG" status=1 fi - - PATCHES=( ${PATCHES_AFTER[@]} ) } SKIPPED_PATCHES= # Patch kernel normally +apply_one_patch() { + echo "[ $PATCH ]" + echo "[ $PATCH ]" >> $PATCH_LOG + backup_dir=$PATCH_DIR/.pc/$PATCH + + LAST_LOG=$(patch -d $PATCH_DIR --backup --prefix=$backup_dir/ -p1 -E $fuzz \ + --no-backup-if-mismatch --force < $PATCH 2>&1) + STATUS=$? + + if [ $STATUS -ne 0 ]; then + restore_files $backup_dir $PATCH_DIR + + if $SKIP_REVERSE; then + patch -R -d $PATCH_DIR -p1 -E $fuzz --force --dry-run \ + < $PATCH > /dev/null 2>&1 + ST=$? + if [ $ST -eq 0 ]; then + LAST_LOG="[ skipped: can be reverse-applied ]" + [ -n "$QUIET" ] && echo "$LAST_LOG" + STATUS=0 + SKIPPED_PATCHES="$SKIPPED_PATCHES $PATCH" + PATCH="# $PATCH" + remove_rejects $backup_dir $PATCH_DIR + fi + fi + + # Backup directory is no longer needed + rm -rf $backup_dir + else + if $QUILT; then + echo "$PATCH" >> $PATCH_DIR/.pc/applied-patches + fi + fi + + if ! $QUILT; then + rm -rf $PATCH_DIR/.pc/ + fi + echo "$LAST_LOG" >> $PATCH_LOG + [ -z "$QUIET" ] && echo "$LAST_LOG" + if [ $STATUS -ne 0 ]; then + [ -n "$QUIET" ] && echo "$LAST_LOG" + echo "Patch $PATCH failed (rolled back)." + echo "Logfile: $PATCH_LOG" + status=1 + return 1 + else + echo "$SERIES_PFX$PATCH" >> $PATCH_DIR/series + fi + + return 0 +} + apply_patches() { - set -- "${PATCHES[@]}" - n=0 - while [ $# -gt 0 ]; do - PATCH="$1" - if ! $QUILT && test "$PATCH" = "$LIMIT"; then - STEP_BY_STEP=1 - echo "Stopping before $PATCH" + for ((n=0; n<${#PATCHES_BEFORE[@]}; n++)); do + PATCH=${PATCHES_BEFORE[n]} + if [ ! -r "$PATCH" ]; then + echo "Patch $PATCH not found." + status=1 + break + fi + apply_one_patch || break + done +} + +apply_rest_patches() { + STEP_BY_STEP=1 + echo "Stopping before ${PATCHES[0]}" + for ((n=0; n<${#PATCHES[@]}; n++)); do + PATCH=${PATCHES[n]} + if [ ! -r "$PATCH" ]; then + echo "Patch $PATCH not found." + status=1 + break fi if [ -n "$STEP_BY_STEP" ]; then while true; do @@ -124,7 +185,7 @@ apply_patches() { break ;; ([nN]) - break 2 # break out of outer loop + break 2 # break out of outer loop ;; ([aA]) unset STEP_BY_STEP @@ -133,68 +194,7 @@ apply_patches() { esac done fi - - if [ ! -r "$PATCH" ]; then - echo "Patch $PATCH not found." - status=1 - break - fi - echo "[ $PATCH ]" - echo "[ $PATCH ]" >> $PATCH_LOG - backup_dir=$PATCH_DIR/.pc/$PATCH - - LAST_LOG=$(patch -d $PATCH_DIR --backup --prefix=$backup_dir/ -p1 -E $fuzz \ - --no-backup-if-mismatch --force < $PATCH 2>&1) - STATUS=$? - - if [ $STATUS -ne 0 ]; then - restore_files $backup_dir $PATCH_DIR - - if $SKIP_REVERSE; then - patch -R -d $PATCH_DIR -p1 -E $fuzz --force --dry-run \ - < $PATCH > /dev/null 2>&1 - ST=$? - if [ $ST -eq 0 ]; then - LAST_LOG="[ skipped: can be reverse-applied ]" - [ -n "$QUIET" ] && echo "$LAST_LOG" - STATUS=0 - SKIPPED_PATCHES="$SKIPPED_PATCHES $PATCH" - PATCH="# $PATCH" - remove_rejects $backup_dir $PATCH_DIR - fi - fi - - # Backup directory is no longer needed - rm -rf $backup_dir - else - if $QUILT; then - echo "$PATCH" >> $PATCH_DIR/.pc/applied-patches - fi - fi - - if ! $QUILT; then - rm -rf $PATCH_DIR/.pc/ - fi - echo "$LAST_LOG" >> $PATCH_LOG - [ -z "$QUIET" ] && echo "$LAST_LOG" - if [ $STATUS -ne 0 ]; then - [ -n "$QUIET" ] && echo "$LAST_LOG" - echo "Patch $PATCH failed (rolled back)." - echo "Logfile: $PATCH_LOG" - status=1 - break - else - echo "$SERIES_PFX$PATCH" >> $PATCH_DIR/series - fi - - shift - if $QUILT; then - unset PATCHES[$n] - fi - let n++ - if $QUILT && test "$PATCH" = "$LIMIT"; then - break - fi + apply_one_patch || break done } @@ -615,6 +615,12 @@ else apply_patches fi +PATCHES=( ${PATCHES_AFTER[@]} ) + +if ! $QUILT && [ -z "$FAST$RAPID" ]; then + apply_rest_patches +fi + if [ -n "$DRY_RUN" ]; then exit $status fi diff --git a/series.conf b/series.conf index bf7b54a..88cbc74 100644 --- a/series.conf +++ b/series.conf @@ -29410,6 +29410,7 @@ patches.suse/0004-lib-raid6-altivec-Add-vpermxor-implementation-for-ra.patch patches.suse/0040-lib-raid6-Build-proper-raid6test-files-on-powerpc.patch patches.suse/powerpc-Remove-unused-flush_dcache_phys_range.patch + patches.suse/powerpc-Use-sizeof-foo-rather-than-sizeof-struct-foo.patch patches.suse/powerpc-Use-feature-bit-for-RTC-presence-rather-than.patch patches.suse/powerpc-Book-E-Remove-unused-CPU_FTR_L2CSR-bit.patch patches.suse/powerpc-Free-up-CPU-feature-bits-on-64-bit-machines.patch @@ -47943,6 +47944,7 @@ patches.suse/pinctrl-sh-pfc-sh73a0-Fix-fsic_spdif-pin-groups.patch patches.suse/platform_data-mlxreg-additions-for-Mellanox-watchdog.patch patches.suse/tracing-do-not-free-iter-trace-in-fail-path-of-tracing_open_pipe.patch + patches.suse/tracing-perf-Use-strndup_user-instead-of-buggy-open-coded-version.patch patches.suse/tracing-use-strncpy-instead-of-memcpy-for-string-keys-in-hist-triggers.patch patches.suse/0001-xen-pciback-Don-t-disable-PCI_COMMAND-on-PCI-device-.patch patches.suse/0001-x86-respect-memory-size-limiting-via-mem-parameter.patch @@ -48744,6 +48746,10 @@ patches.suse/perf-x86-intel-pt-remove-software-double-buffering-pmu-capability.patch patches.suse/tty-rocket-fix-incorrect-forward-declaration-of-rp_i.patch patches.suse/sched-x86-save-flags-on-context-switch.patch + patches.suse/objtool-Set-insn-func-for-alternatives.patch + patches.suse/objtool-Add-backtrace-support.patch + patches.suse/objtool-Rewrite-alt-skip_orig.patch + patches.suse/objtool-Fix-sibling-call-detection.patch patches.suse/cpu-speculation-add-mitigations-cmdline-option.patch patches.suse/x86-speculation-support-mitigations-cmdline-option.patch patches.suse/powerpc-speculation-support-mitigations-cmdline-option.patch @@ -49829,6 +49835,9 @@ patches.suse/powerpc-perf-init-pmu-from-core-book3s.patch patches.suse/powerpc-perf-Add-generic-compat-mode-pmu-driver.patch patches.suse/powerpc-perf-Remove-PM_BR_CMPL_ALT-from-power9-event.patch + patches.suse/powerpc-perf-Return-accordingly-on-invalid-chip-id-i.patch + patches.suse/powerpc-perf-Fix-loop-exit-condition-in-nest_imc_eve.patch + patches.suse/powerpc-perf-Add-privileged-access-check-for-thread_.patch patches.suse/powerpc-book3s-64-check-for-NULL-pointer-in-pgd_allo.patch patches.suse/pwm-Fix-deadlock-warning-when-removing-PWM-device.patch patches.suse/pwm-tiehrpwm-Update-shadow-register-for-disabling-PW.patch @@ -49967,6 +49976,7 @@ patches.suse/memory-tegra-Fix-integer-overflow-on-tick-value-calc.patch patches.suse/soc-mediatek-pwrap-Zero-initialize-rdata-in-pwrap_in.patch patches.suse/soc-rockchip-Set-the-proper-PWM-for-rk3288.patch + patches.suse/objtool-Don-t-use-ignore-flag-for-fake-jumps.patch patches.suse/objtool-fix-function-fallthrough-detection.patch patches.suse/0001-locking-rwsem-Prevent-decrement-of-reader-count-befo.patch patches.suse/perf-x86-amd-iommu-make-the-amd_iommu_attr_groups-symbol-static.patch @@ -51454,7 +51464,12 @@ patches.suse/kvm-svm-fix-detection-of-amd-errata-1096 patches.suse/kvm-x86-vpmu-refine-kvm_pmu-err-msg-when-event-creation-failed patches.suse/kvm-nvmx-do-not-use-dangling-shadow-vmcs-after-guest-reset + patches.suse/objtool-Use-Elf_Scn-typedef-instead-of-assuming-struct-name.patch + patches.suse/objtool-Rename-elf_open-to-prevent-conflict-with-libelf-from-elftoolchain.patch patches.suse/stacktrace-force-user_ds-for-stack_trace_save_user.patch + patches.suse/objtool-Track-original-function-across-branches.patch + patches.suse/objtool-Convert-insn-type-to-enum.patch + patches.suse/objtool-Support-conditional-retpolines.patch patches.suse/x86-boot-fix-memory-leak-in-default_get_smp_config.patch patches.suse/msft-hv-1901-x86-hyper-v-Zero-out-the-VP-ASSIST-PAGE-on-allocatio.patch patches.suse/Input-synaptics-whitelist-Lenovo-T580-SMBus-intertou.patch @@ -52951,6 +52966,7 @@ patches.suse/edac-ghes-fix-use-after-free-in-ghes_edac-remove-path.patch patches.suse/regulator-ti-abb-Fix-timeout-in-ti_abb_wait_txdone-t.patch patches.suse/regulator-pfuze100-regulator-Variable-val-in-pfuze10.patch + patches.suse/tracing-Fix-race-in-perf_trace_buf-initialization.patch patches.suse/ALSA-hda-realtek-Add-support-for-ALC711.patch patches.suse/ASoC-wm_adsp-Don-t-generate-kcontrols-without-READ-f.patch patches.suse/ASoc-rockchip-i2s-Fix-RPM-imbalance.patch @@ -55842,6 +55858,7 @@ patches.suse/dmaengine-dmatest-Fix-iteration-non-stop-logic.patch patches.suse/nfs-Fix-potential-posix_acl-refcnt-leak-in-nfs3_set_.patch patches.suse/NFSv4.1-fix-handling-of-backchannel-binding-in-BIND_.patch + patches.suse/xprtrdma-Fix-trace-point-use-after-free-race.patch patches.suse/PM-ACPI-Output-correct-message-on-target-power-state.patch patches.suse/PM-hibernate-Freeze-kernel-threads-in-software_resum.patch patches.suse/iommu-amd-fix-legacy-interrupt-remapping-for-x2apic-enabled-system @@ -56054,7 +56071,18 @@ patches.suse/printk-handle-blank-console-arguments-passed-in.patch patches.suse/objtool-clean-instruction-state-before-each-function-validation.patch patches.suse/objtool-ignore-empty-alternatives.patch + patches.suse/objtool-Support-multiple-stack_op-per-instruction.patch + patches.suse/objtool-Rename-struct-cfi_state.patch + patches.suse/objtool-Fix-CFI-insn_state-propagation.patch + patches.suse/objtool-Remove-check-preventing-branches-within-alternative.patch + patches.suse/objtool-Uniquely-identify-alternative-instruction-groups.patch + patches.suse/objtool-Fix-ORC-vs-alternatives.patch + patches.suse/objtool-Rework-allocating-stack_ops-on-decode.patch + patches.suse/objtool-Make-handle_insn_ops-unconditional.patch + patches.suse/objtool-Remove-INSN_STACK.patch + patches.suse/objtool-Add-support-for-intra-function-calls.patch patches.suse/x86-speculation-change-fill_return_buffer-to-work-with-objtool.patch + patches.suse/objtool-Allow-no-op-CFI-ops-in-alternatives.patch patches.suse/efi-efivars-Add-missing-kobject_put-in-sysfs-entry-c.patch patches.suse/x86-cpu-add-a-steppings-field-to-struct-x86_cpu_id.patch patches.suse/x86-cpu-amd-make-erratum-1054-a-legacy-erratum.patch @@ -59346,6 +59374,8 @@ patches.suse/net-mlx5e-Fix-error-path-for-ethtool-set-priv-flag.patch patches.suse/arm64-kdump-update-ppos-when-reading-elfcorehdr.patch patches.suse/RDMA-cxgb4-Fix-adapter-LE-hash-errors-while-destroyi.patch + patches.suse/squashfs-fix-inode-lookup-sanity-checks.patch + patches.suse/squashfs-fix-xattr-id-and-id-lookup-sanity-checks.patch patches.suse/drm-msm-fix-shutdown-hook-in-case-GPU-components-fai.patch patches.suse/bus-omap_l3_noc-mark-l3-irqs-as-IRQF_NO_THREAD.patch patches.suse/0009-dm-verity-fix-DM_VERITY_OPTS_MAX-value.patch @@ -60300,6 +60330,7 @@ patches.suse/ASoC-hisilicon-fix-missing-clk_disable_unprepare-on-.patch patches.suse/ASoC-tegra-Set-driver_name-tegra-for-all-machine-dri.patch patches.suse/ASoC-soc-core-Fix-the-error-return-code-in-snd_soc_o.patch + patches.suse/tracepoint-Add-tracepoint_probe_register_may_exist-for-BPF-tracing.patch patches.suse/0001-xarray-iov_iter_fault_in_readable-should-do-nothing-in-xarray-case.patch patches.suse/leds-ktd2692-Fix-an-error-handling-path.patch patches.suse/Input-usbtouchscreen-fix-control-request-directions.patch @@ -61216,6 +61247,7 @@ patches.suse/char-mwave-Adjust-io-port-register-size.patch patches.suse/PCI-Add-function-1-DMA-alias-quirk-for-Marvell-88SE9.patch patches.suse/livepatch-Avoid-CPU-hogging-with-cond_resched.patch + patches.suse/tracing-uprobes-Check-the-return-value-of-kstrdup-for-tu-filename.patch patches.suse/tracing-kprobes-nmissed-not-showed-correctly-for-kretprobe.patch patches.suse/Input-ti_am335x_tsc-set-ADCREFM-for-X-configuration.patch patches.suse/Input-ti_am335x_tsc-fix-STEPCONFIG-setup-for-Z2.patch @@ -61336,6 +61368,7 @@ patches.suse/af_key-add-__GFP_ZERO-flag-for-compose_sadb_supporte.patch patches.suse/Input-aiptek-properly-check-endpoint-type.patch patches.suse/kvm-emulate-fix-setcc-emulation-function-offsets-with-sls.patch + patches.suse/tpm-fix-reference-counting-for-struct-tpm_chip.patch patches.suse/arm64-module-remove-NOLOAD-from-linker-script.patch patches.suse/arm64-mm-avoid-fixmap-race-condition-when-create-pud-mapping.patch patches.suse/hwrng-cavium-HW_RANDOM_CAVIUM-should-depend-on-ARCH_.patch @@ -61476,6 +61509,7 @@ patches.suse/drbd-fix-an-invalid-memory-access-caused-by-incorrect-use-of-list-iterator patches.suse/scsi-virtio-scsi-Eliminate-anonymous-module_init-module_exit patches.suse/scsi-zorro7xx-Fix-a-resource-leak-in-zorro7xx_remove_one + patches.suse/SUNRPC-Fix-the-svc_deferred_event-trace-class.patch patches.suse/veth-Ensure-eth-header-is-in-skb-s-linear-part.patch patches.suse/mm-page_alloc-fix-build_zonerefs_node.patch patches.suse/smp-Fix-offline-cpu-check-in-flush_smp_call_function.patch @@ -61675,6 +61709,7 @@ patches.suse/xen-netback-avoid-entering-xenvif_rx_next_skb-with-a.patch patches.suse/kvm-emulate-do-not-adjust-size-of-fastop-and-setcc-subroutines.patch patches.suse/serial-mvebu-uart-correctly-report-configured-baudra.patch + patches.suse/mm-Force-TLB-flush-for-PFNMAP-mappings-before-unlink_file_vma.patch patches.suse/xfrm-xfrm_policy-fix-a-possible-double-xfrm_pols_put.patch patches.suse/lkdtm-disable-return-thunks-in-rodata-c.patch patches.suse/netfilter-nf_queue-do-not-allow-packet-truncation-be.patch @@ -61682,7 +61717,11 @@ patches.suse/ACPI-CPPC-Do-not-prevent-CPPC-from-working-in-the-fu.patch patches.suse/crypto-arm64-gcm-Select-AEAD-for-GHASH_ARM64_CE.patch patches.suse/crypto-inside-secure-Add-missing-MODULE_DEVICE_TABLE.patch + patches.suse/usbnet-Fix-linkwatch-use-after-free-on-disconnect.patch patches.suse/usbnet-smsc95xx-Fix-deadlock-on-runtime-resume.patch + patches.suse/spmi-trace-fix-stack-out-of-bound-access-in-SPMI-tracing-functions.patch + patches.suse/KVM-x86-Mark-TSS-busy-during-LTR-emulation-_after_-a.patch + patches.suse/KVM-x86-Set-error-code-to-segment-selector-on-LLDT-L.patch patches.suse/KVM-nVMX-Set-UMIP-bit-CR4_FIXED1-MSR-when-emulating-.patch patches.suse/PCI-dwc-Deallocate-EPC-memory-on-dw_pcie_ep_init-err.patch patches.suse/scsi-qla2xxx-edif-Reduce-Initiator-Initiator-thrashi.patch @@ -61728,14 +61767,26 @@ patches.suse/scsi-qla2xxx-Update-manufacturer-details.patch patches.suse/scsi-qla2xxx-Update-version-to-10.02.07.800-k.patch patches.suse/md-raid-destroy-the-bitmap-after-destroying-the-thre.patch + patches.suse/ext4-check-if-directory-block-is-within-i_size.patch + patches.suse/ext4-make-sure-ext4_append-always-allocates-new-bloc.patch patches.suse/xfs-fix-null-pointer-dereference-in-xfs_getbmap.patch patches.suse/powerpc-powernv-Avoid-crashing-if-rng-is-NULL.patch patches.suse/powerpc-powernv-kvm-Use-darn-for-H_RANDOM-on-Power9.patch patches.suse/powerpc-powernv-rename-remaining-rng-powernv_-functi.patch patches.suse/powerpc-xive-Fix-refcount-leak-in-xive_get_max_prio.patch patches.suse/iommu-vt-d-avoid-invalid-memory-access-via-node_online-NUMA_NO_N + patches.suse/fuse-limit-nsec.patch patches.suse/x86-speculation-Add-RSB-VM-Exit-protections.patch patches.suse/x86-speculation-Add-LFENCE-to-RSB-fill-sequence.patch + patches.suse/ceph-don-t-truncate-file-in-atomic_open.patch + patches.suse/net_sched-cls_route-remove-from-list-when-handle-is-.patch + patches.suse/xen-xenbus-fix-return-type-in-xenbus_file_read.patch + patches.suse/net_sched-cls_route-disallow-handle-of-0.patch + patches.suse/af_key-Do-not-call-xfrm_probe_algs-in-parallel.patch + patches.suse/mm-rmap-Fix-anon_vma-degree-ambiguity-leading-to-double-reuse.patch + + # netdev/net + patches.suse/netfilter-nf_conntrack_irc-Fix-forged-IP-logic.patch # dhowells/linux-fs keys-uefi patches.suse/0001-KEYS-Allow-unrestricted-boot-time-addition-of-keys-t.patch @@ -61765,6 +61816,7 @@ patches.suse/SUNRPC-improve-swap-handling-scheduling-and-PF_MEMAL.patch patches.suse/SUNRPC-xprt-async-tasks-mustn-t-block-waiting-for-me.patch patches.suse/net-tipc-validate-domain-record-count-on-input.patch + patches.suse/netfilter-nf_conntrack_irc-Tighten-matching-on-DCC-m.patch ######################################################## # end of sorted patches @@ -62121,6 +62173,7 @@ patches.suse/reiserfs-don-t-panic-on-bad-directory-entries.patch patches.suse/reiserfs-fix-extended-attributes-on-the-root-directory.patch patches.suse/ext4-dont-warn-when-enabling-DAX.patch + patches.suse/ext4-Fix-check-for-block-being-out-of-directory-size.patch ######################################################## # NFS @@ -62189,6 +62242,7 @@ patches.suse/nvme-check-for-nvme_ctrl_live-in-nvme_report_ns_ids.patch patches.suse/nvme-loop-introduce-no-merge-flag-for-biovec.patch patches.suse/nvme-return-BLK_STS_TRANSPORT-unless-DNR.patch + patches.suse/lightnvm-remove-lightnvm-implemenation.patch patches.suse/md-display-timeout-error.patch patches.suse/nvme-multipath-disable-native-NVMe-multipath-per-def.patch @@ -62749,6 +62803,7 @@ patches.kabi/kabi-return-type-change-of-secure_ipv-46-_port_ephem.patch patches.kabi/sctp-handle-kabi-change-in-struct-sctp_endpoint.patch patches.kabi/qed-fixup-kabi-for-qed_rdma_create_qp_in_params.patch + patches.kabi/kABI-Fix-kABI-after-mm-rmap-Fix-anon_vma-degree-ambi.patch ######################################################## # You'd better have a good reason for adding a patch