5.18.3-rc1 review
Subsystems (3)
Greg Kroah-Hartman
maintainerPATCH 693/879 RISC-V: Split out the XIP fixups into their own file
In reply to Greg Kroah-HartmanFrom: Palmer Dabbelt <[email protected]>
[ Upstream commit e7681beba992d5a196476d5d79dfcb48f2a2c477 ]
This was broken by the original refactoring (as the XIP definitions depend on <asm/pgtable.h>) and then more broken by the merge (as I accidentally took the old version). This fixes both breakages, while also pulling this out of <asm/asm.h> to avoid polluting most assembly files with the XIP fixups.
--- arch/riscv/include/asm/asm.h | 26 ------------------------- arch/riscv/include/asm/xip_fixup.h | 31 ++++++++++++++++++++++++++++++ arch/riscv/kernel/head.S | 1 + arch/riscv/kernel/suspend_entry.S | 1 + 4 files changed, 33 insertions(+), 26 deletions(-) create mode 100644 arch/riscv/include/asm/xip_fixup.h
arch/riscv/include/asm/asm.h +0 -26
@@ -67,30 +67,4 @@#error "Unexpected __SIZEOF_SHORT__"#endif -#ifdef __ASSEMBLY__ - -/* Common assembly source macros */ - -#ifdef CONFIG_XIP_KERNEL -.macro XIP_FIXUP_OFFSET reg - REG_L t0, _xip_fixup - add \reg, \reg, t0 -.endm -.macro XIP_FIXUP_FLASH_OFFSET reg - la t1, __data_loc - REG_L t1, _xip_phys_offset - sub \reg, \reg, t1 - add \reg, \reg, t0 -.endm -_xip_fixup: .dword CONFIG_PHYS_RAM_BASE - CONFIG_XIP_PHYS_ADDR - XIP_OFFSET -_xip_phys_offset: .dword CONFIG_XIP_PHYS_ADDR + XIP_OFFSET -#else -.macro XIP_FIXUP_OFFSET reg -.endm -.macro XIP_FIXUP_FLASH_OFFSET reg -.endm -#endif /* CONFIG_XIP_KERNEL */ - -#endif /* __ASSEMBLY__ */ -#endif /* _ASM_RISCV_ASM_H */
arch/riscv/include/asm/xip_fixup.h new file +31 -0
@@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* +* XIP fixup macros, only useful in assembly. +*/ +#ifndef _ASM_RISCV_XIP_FIXUP_H +#define _ASM_RISCV_XIP_FIXUP_H + +#include <linux/pgtable.h> + +#ifdef CONFIG_XIP_KERNEL +.macro XIP_FIXUP_OFFSET reg + REG_L t0, _xip_fixup + add \reg, \reg, t0 +.endm +.macro XIP_FIXUP_FLASH_OFFSET reg + la t1, __data_loc + REG_L t1, _xip_phys_offset + sub \reg, \reg, t1 + add \reg, \reg, t0 +.endm + +_xip_fixup: .dword CONFIG_PHYS_RAM_BASE - CONFIG_XIP_PHYS_ADDR - XIP_OFFSET +_xip_phys_offset: .dword CONFIG_XIP_PHYS_ADDR + XIP_OFFSET +#else +.macro XIP_FIXUP_OFFSET reg +.endm +.macro XIP_FIXUP_FLASH_OFFSET reg +.endm +#endif /* CONFIG_XIP_KERNEL */ + +#endif
arch/riscv/kernel/head.S +1 -0
@@ -14,6 +14,7 @@ #include <asm/cpu_ops_sbi.h> #include <asm/hwcap.h> #include <asm/image.h> +#include <asm/xip_fixup.h> #include "efi-header.S" __HEAD
arch/riscv/kernel/suspend_entry.S +1 -0
@@ -8,6 +8,7 @@ #include <asm/asm.h> #include <asm/asm-offsets.h> #include <asm/csr.h> +#include <asm/xip_fixup.h> .text .altmacro
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 694/879 RISC-V: Fix the XIP build
In reply to Greg Kroah-HartmanFrom: Palmer Dabbelt <[email protected]>
[ Upstream commit d9e418d0ca1c464fe361468b772d4aa870d54e63 ]
A handful of functions unused functions were enabled during XIP builds, which themselves didn't build correctly. This just disables the functions entirely.
--- arch/riscv/mm/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/riscv/mm/init.c +1 -1
@@ -677,7 +677,7 @@ static __init pgprot_t pgprot_from_va(uintptr_t va) }#endif /* CONFIG_STRICT_KERNEL_RWX */ -#ifdef CONFIG_64BIT +#if defined(CONFIG_64BIT ) && !defined(CONFIG_XIP_KERNEL )static void __init disable_pgtable_l5 (void ) { pgtable_l5_enabled = false;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 695/879 MIPS: RALINK: Define pci_remap_iospace under CONFIG_PCI_DRIVERS_GENERIC
In reply to Greg Kroah-HartmanFrom: Tiezhu Yang <[email protected]>
[ Upstream commit 7e4fd16b38923028b01d3dbadf4ca973d885c53e ]
kernel test robot reports a build error used with clang compiler and mips-randconfig [1]:
ld.lld: error: undefined symbol: pci_remap_iospace
we can see the following configs in the mips-randconfig file:
CONFIG_RALINK=y
CONFIG_SOC_MT7620=y
CONFIG_PCI_DRIVERS_LEGACY=y
CONFIG_PCI=yCONFIG_RALINK is set, so pci_remap_iospace is defined in the related arch/mips/include/asm/mach-ralink/spaces.h header file:
#define pci_remap_iospace pci_remap_iospace
CONFIG_PCI is set, so pci_remap_iospace() in drivers/pci/pci.c is not built due to pci_remap_iospace is defined under CONFIG_RALINK.
#ifndef pci_remap_iospace
int pci_remap_iospace(const struct resource *res, ...)
$ objdump -d drivers/pci/pci.o | grep pci_remap_iospace
00004cc8 <devm_pci_remap_iospace>:
4d18: 10400008 beqz v0,4d3c <devm_pci_remap_iospace+0x74>
4d2c: 1040000c beqz v0,4d60 <devm_pci_remap_iospace+0x98>
4d70: 1000fff3 b 4d40 <devm_pci_remap_iospace+0x78>In addition, CONFIG_PCI_DRIVERS_GENERIC is not set, so pci_remap_iospace() in arch/mips/pci/pci-generic.c is not built too.
#ifdef pci_remap_iospace
int pci_remap_iospace(const struct resource *res, ...)
For the above reasons, undefined reference pci_remap_iospace() looks like reasonable.
Here are simple steps to reproduce used with gcc and defconfig:
cd mips.git
make vocore2_defconfig # set RALINK, SOC_MT7620, PCI_DRIVERS_LEGACY
make menuconfig # set PCI
make
there exists the following build error:
LD vmlinux.o
MODPOST vmlinux.symvers
MODINFO modules.builtin.modinfo
GEN modules.builtin
LD .tmp_vmlinux.kallsyms1
drivers/pci/pci.o: In function `devm_pci_remap_iospace':
pci.c:(.text+0x4d24): undefined reference to `pci_remap_iospace' Makefile:1158: recipe for target 'vmlinux' failed
make: *** [vmlinux] Error 1
Define pci_remap_iospace under CONFIG_PCI_DRIVERS_GENERIC can fix the build error, with this patch, no build error remains. This patch is similar with commit e538e8649892 ("MIPS: asm: pci: define arch-specific 'pci_remap_iospace()' dependent on 'CONFIG_PCI_DRIVERS_GENERIC'").
[1] https://lore.kernel.org/lkml/[email protected]/
--- arch/mips/include/asm/mach-ralink/spaces.h | 2 ++ 1 file changed, 2 insertions(+)
arch/mips/include/asm/mach-ralink/spaces.h +2 -0
@@ -6,7 +6,9 @@#define PCI_IOSIZE SZ_64K#define IO_SPACE_LIMIT (PCI_IOSIZE - 1) +#ifdef CONFIG_PCI_DRIVERS_GENERIC #define pci_remap_iospace pci_remap_iospace +#endif #include <asm/mach-generic/spaces.h> #endif
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 696/879 perf build: Fix btf__load_from_kernel_by_id() feature check
In reply to Greg Kroah-HartmanFrom: Jiri Olsa <[email protected]>
[ Upstream commit 73534617dfa3c4cd95fe5ffaeff5315e9ffc2de6 ]
The btf__load_from_kernel_by_id() only takes one arg, not two.
Committer notes:
I tested it just with an older libbpf, one where btf__load_from_kernel_by_id() wasn't introduced yet.
A test with a newer dynamic libbpf would fail because the btf__load_from_kernel_by_id() is there, but takes just one arg.
--- .../build/feature/test-libbpf-btf__load_from_kernel_by_id.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
tools/build/feature/test-libbpf-btf__load_from_kernel_by_id.c +3 -2
@@ -1,7 +1,8 @@// SPDX-License-Identifier: GPL-2.0 -#include <bpf/libbpf.h> +#include <bpf/btf.h> int main (void ) { -return btf__load_from_kernel_by_id (20151128 ,NULL ); +btf__load_from_kernel_by_id (20151128 ); +return 0 ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 697/879 perf c2c: Use stdio interface if slang is not supported
In reply to Greg Kroah-HartmanFrom: Leo Yan <[email protected]>
[ Upstream commit c4040212bc97d16040712a410335f93bc94d2262 ]
If the slang lib is not installed on the system, perf c2c tool disables TUI mode and roll back to use stdio mode; but the flag 'c2c.use_stdio' is missed to set true and thus it wrongly applies UI quirks in the function ui_quirks().
This commit forces to use stdio interface if slang is not supported, and it can avoid to apply the UI quirks and show the correct metric header.
Before:
=================================================
Shared Cache Line Distribution Pareto
=================================================
-------------------------------------------------------------------------------
0 0 0 99 0 0 0 0xaaaac17d6000
-------------------------------------------------------------------------------
0.00% 0.00% 6.06% 0.00% 0.00% 0.00% 0x20 N/A 0 0xaaaac17c25ac 0 0 43 375 18469 2 [.] 0x00000000000025ac memstress memstress[25ac] 0
0.00% 0.00% 93.94% 0.00% 0.00% 0.00% 0x29 N/A 0 0xaaaac17c3e88 0 0 173 180 135 2 [.] 0x0000000000003e88 memstress memstress[3e88] 0After:
=================================================
Shared Cache Line Distribution Pareto
=================================================
-------------------------------------------------------------------------------
0 0 0 99 0 0 0 0xaaaac17d6000
-------------------------------------------------------------------------------
0.00% 0.00% 6.06% 0.00% 0.00% 0.00% 0x20 N/A 0 0xaaaac17c25ac 0 0 43 375 18469 2 [.] 0x00000000000025ac memstress memstress[25ac] 0
0.00% 0.00% 93.94% 0.00% 0.00% 0.00% 0x29 N/A 0 0xaaaac17c3e88 0 0 173 180 135 2 [.] 0x0000000000003e88 memstress memstress[3e88] 0--- tools/perf/builtin-c2c.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
tools/perf/builtin-c2c.c +4 -2
@@ -2735,9 +2735,7 @@ static int perf_c2c__report(int argc, const char **argv) "the input file to process"),OPT_INCR ('N' ,"node-info" , &c2c.node_info,"show extra node info in report (repeat for more info)" ), -#ifdef HAVE_SLANG_SUPPORTOPT_BOOLEAN (0 ,"stdio" , &c2c.use_stdio,"Use the stdio interface" ), -#endifOPT_BOOLEAN (0 ,"stats" , &c2c.stats_only,"Display only statistic tables (implies --stdio)" ), OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full,
@@ -2767,6 +2765,10 @@ static int perf_c2c__report(int argc, const char **argv)if (argc)usage_with_options (report_c2c_usage, options); +#ifndef HAVE_SLANG_SUPPORT + c2c.use_stdio = true; +#endif +if (c2c.stats_only) c2c.use_stdio = true;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 698/879 rtla: Avoid record NULL pointer dereference
In reply to Greg Kroah-HartmanFrom: Wan Jiabing <[email protected]>
[ Upstream commit 2a6b52ed72c822b5ee146a6a00ea66614fe02653 ]
Fix the following null/deref_null.cocci errors:
./tools/tracing/rtla/src/osnoise_hist.c:870:31-36: ERROR: record is NULL but dereferenced. ./tools/tracing/rtla/src/osnoise_top.c:650:31-36: ERROR: record is NULL but dereferenced. ./tools/tracing/rtla/src/timerlat_hist.c:905:31-36: ERROR: record is NULL but dereferenced. ./tools/tracing/rtla/src/timerlat_top.c:700:31-36: ERROR: record is NULL but dereferenced.
"record" is NULL before calling osnoise_init_trace_tool. Add a tag "out_free" to avoid dereferring a NULL pointer.
--- tools/tracing/rtla/src/osnoise_hist.c | 5 +++-- tools/tracing/rtla/src/osnoise_top.c | 9 +++++---- tools/tracing/rtla/src/timerlat_hist.c | 11 ++++++----- tools/tracing/rtla/src/timerlat_top.c | 11 ++++++----- 4 files changed, 20 insertions(+), 16 deletions(-)
tools/tracing/rtla/src/osnoise_hist.c +3 -2
@@ -809,7 +809,7 @@ int osnoise_hist_main(int argc, char *argv[]) retval =set_comm_sched_attr ("osnoise/" , ¶ms->sched_param);if (retval) {err_msg ("Failed to set sched parameters\n" ); - goto out_hist; + goto out_free; } }
@@ -819,7 +819,7 @@ int osnoise_hist_main(int argc, char *argv[]) record =osnoise_init_trace_tool ("osnoise" );if (!record) {err_msg ("Failed to enable the trace instance\n" ); - goto out_hist; + goto out_free; }if (params->events) {
@@ -869,6 +869,7 @@ int osnoise_hist_main(int argc, char *argv[]) out_hist:trace_events_destroy (&record->trace, params->events); params->events =NULL ; +out_free:osnoise_free_histogram (tool->data); out_destroy:osnoise_destroy_tool (record);
tools/tracing/rtla/src/osnoise_top.c +5 -4
@@ -572,7 +572,7 @@ int osnoise_top_main(int argc, char **argv) retval =osnoise_top_apply_config (tool, params);if (retval) {err_msg ("Could not apply config\n" ); - goto out_top; + goto out_free; } trace = &tool->trace;
@@ -580,14 +580,14 @@ int osnoise_top_main(int argc, char **argv) retval =enable_osnoise (trace);if (retval) {err_msg ("Failed to enable osnoise tracer\n" ); - goto out_top; + goto out_free; }if (params->set_sched) { retval =set_comm_sched_attr ("osnoise/" , ¶ms->sched_param);if (retval) {err_msg ("Failed to set sched parameters\n" ); - goto out_top; + goto out_free; } }
@@ -597,7 +597,7 @@ int osnoise_top_main(int argc, char **argv) record =osnoise_init_trace_tool ("osnoise" );if (!record) {err_msg ("Failed to enable the trace instance\n" ); - goto out_top; + goto out_free; }if (params->events) {
@@ -649,6 +649,7 @@ int osnoise_top_main(int argc, char **argv) out_top:trace_events_destroy (&record->trace, params->events); params->events =NULL ; +out_free:osnoise_free_top (tool->data);osnoise_destroy_tool (record);osnoise_destroy_tool (tool);
tools/tracing/rtla/src/timerlat_hist.c +6 -5
@@ -821,7 +821,7 @@ int timerlat_hist_main(int argc, char *argv[]) retval =timerlat_hist_apply_config (tool, params);if (retval) {err_msg ("Could not apply config\n" ); - goto out_hist; + goto out_free; } trace = &tool->trace;
@@ -829,14 +829,14 @@ int timerlat_hist_main(int argc, char *argv[]) retval =enable_timerlat (trace);if (retval) {err_msg ("Failed to enable timerlat tracer\n" ); - goto out_hist; + goto out_free; }if (params->set_sched) { retval =set_comm_sched_attr ("timerlat/" , ¶ms->sched_param);if (retval) {err_msg ("Failed to set sched parameters\n" ); - goto out_hist; + goto out_free; } }
@@ -844,7 +844,7 @@ int timerlat_hist_main(int argc, char *argv[]) dma_latency_fd =set_cpu_dma_latency (params->dma_latency);if (dma_latency_fd <0 ) {err_msg ("Could not set /dev/cpu_dma_latency.\n" ); - goto out_hist; + goto out_free; } }
@@ -854,7 +854,7 @@ int timerlat_hist_main(int argc, char *argv[]) record =osnoise_init_trace_tool ("timerlat" );if (!record) {err_msg ("Failed to enable the trace instance\n" ); - goto out_hist; + goto out_free; }if (params->events) {
@@ -904,6 +904,7 @@ int timerlat_hist_main(int argc, char *argv[])close (dma_latency_fd);trace_events_destroy (&record->trace, params->events); params->events =NULL ; +out_free:timerlat_free_histogram (tool->data);osnoise_destroy_tool (record);osnoise_destroy_tool (tool);
tools/tracing/rtla/src/timerlat_top.c +6 -5
@@ -612,7 +612,7 @@ int timerlat_top_main(int argc, char *argv[]) retval =timerlat_top_apply_config (top, params);if (retval) {err_msg ("Could not apply config\n" ); - goto out_top; + goto out_free; } trace = &top->trace;
@@ -620,14 +620,14 @@ int timerlat_top_main(int argc, char *argv[]) retval =enable_timerlat (trace);if (retval) {err_msg ("Failed to enable timerlat tracer\n" ); - goto out_top; + goto out_free; }if (params->set_sched) { retval =set_comm_sched_attr ("timerlat/" , ¶ms->sched_param);if (retval) {err_msg ("Failed to set sched parameters\n" ); - goto out_top; + goto out_free; } }
@@ -635,7 +635,7 @@ int timerlat_top_main(int argc, char *argv[]) dma_latency_fd =set_cpu_dma_latency (params->dma_latency);if (dma_latency_fd <0 ) {err_msg ("Could not set /dev/cpu_dma_latency.\n" ); - goto out_top; + goto out_free; } }
@@ -645,7 +645,7 @@ int timerlat_top_main(int argc, char *argv[]) record =osnoise_init_trace_tool ("timerlat" );if (!record) {err_msg ("Failed to enable the trace instance\n" ); - goto out_top; + goto out_free; }if (params->events) {
@@ -699,6 +699,7 @@ int timerlat_top_main(int argc, char *argv[])close (dma_latency_fd);trace_events_destroy (&record->trace, params->events); params->events =NULL ; +out_free:timerlat_free_top (top->data);osnoise_destroy_tool (record);osnoise_destroy_tool (top);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 699/879 rtla: Dont overwrite existing directory mode
In reply to Greg Kroah-HartmanFrom: John Kacur <[email protected]>
[ Upstream commit 39c3d84cb5b52792a7323a338334d8d65b2dbe3f ]
The mode on /usr/bin is often 555 these days,
but make install on rtla overwrites this with 755
Fix this by preserving the current directory if it exists.
--- tools/tracing/rtla/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/tracing/rtla/Makefile +2 -1
@@ -23,6 +23,7 @@ $(call allow-override,LD_SO_CONF_PATH,/etc/ld.so.conf.d/) $(call allow-override,LDCONFIG,ldconfig) INSTALL = install +MKDIR = mkdir FOPTS := -flto=auto -ffat-lto-objects -fexceptions -fstack-protector-strong \ -fasynchronous-unwind-tables -fstack-clash-protection WOPTS := -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -Wno-maybe-uninitialized
@@ -68,7 +69,7 @@ static: $(OBJ) .PHONY: install install: doc_install - $(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) + $(MKDIR) -p $(DESTDIR)$(BINDIR) $(INSTALL) rtla -m 755 $(DESTDIR)$(BINDIR) $(STRIP) $(DESTDIR)$(BINDIR)/rtla @test ! -f $(DESTDIR)$(BINDIR)/osnoise || rm $(DESTDIR)$(BINDIR)/osnoise
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 700/879 rtla: Minor grammar fix for rtla README
In reply to Greg Kroah-HartmanFrom: John Kacur <[email protected]>
[ Upstream commit 22d146f7c1e97f4870e4497c0202939a031f740c ]
- Change to "The rtla meta-tool includes"
- Remove an unnecessary "But, "
- Adjust the formatting of the paragraph resulting from the changes.
- Simplify the wording for the libraries and tools.
--- tools/tracing/rtla/README.txt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
tools/tracing/rtla/README.txt +5 -7
@@ -1,15 +1,13 @@ RTLA: Real-Time Linux Analysis tools -The rtla is a meta-tool that includes a set of commands that -aims to analyze the real-time properties of Linux. But, instead of -testing Linux as a black box, rtla leverages kernel tracing -capabilities to provide precise information about the properties -and root causes of unexpected results. +The rtla meta-tool includes a set of commands that aims to analyze +the real-time properties of Linux. Instead of testing Linux as a black box, +rtla leverages kernel tracing capabilities to provide precise information +about the properties and root causes of unexpected results. Installing RTLA -RTLA depends on some libraries and tools. More precisely, it depends on the -following libraries: +RTLA depends on the following libraries and tools: - libtracefs - libtraceevent
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 701/879 rtla: Fix __set_sched_attr error message
In reply to Greg Kroah-HartmanFrom: Daniel Bristot de Oliveira <[email protected]>
[ Upstream commit 941a53c39a151e9aceef153cdfaed0f166ba01b7 ]
rtla's function __set_sched_attr() was borrowed from stalld, but I forgot to update the error message to something meaningful for rtla.
Update the error message from:
boost_with_deadline failed to boost pid PID: STRERROR
to a proper one:
Failed to set sched attributes to the pid PID: STRERROR
--- tools/tracing/rtla/src/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/tracing/rtla/src/utils.c +1 -1
@@ -255,7 +255,7 @@ int __set_sched_attr(int pid, struct sched_attr *attr) retval =sched_setattr (pid, attr, flags);if (retval <0 ) { -err_msg ("boost_with_deadline failed to boost pid %d: %s\n" , +err_msg ("Failed to set sched attributes to the pid %d: %s\n" , pid,strerror (errno));return 1 ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 702/879 rtla: Remove procps-ng dependency
In reply to Greg Kroah-HartmanFrom: Daniel Bristot de Oliveira <[email protected]>
[ Upstream commit dada03db9bb1984826e61cfcf1418ac73848324d ]
Daniel Wagner reported to me that readproc.h got deprecated. Also, while the procps-ng library was available on Fedora, it was not available on RHEL, which is a piece of evidence that it was not that used.
rtla uses procps-ng only to find the PID of the tracers' workload.
I used the procps-ng library to avoid reinventing the wheel. But in this case, reinventing the wheel took me less time than the time we already took trying to work around problems.
Implement a function that reads /proc/ entries, checking if:
- the entry is a directory
- the directory name is composed only of digits (PID)
- the directory contains the comm file
- the comm file contains a comm that matches the tracers' workload prefix.
- then return true; otherwise, return false.
And use it instead of procps-ng.
--- tools/tracing/rtla/Makefile | 2 +- tools/tracing/rtla/README.txt | 1 - tools/tracing/rtla/src/utils.c | 106 ++++++++++++++++++++++++++------- tools/tracing/rtla/src/utils.h | 3 +- 4 files changed, 88 insertions(+), 24 deletions(-)
tools/tracing/rtla/Makefile +1 -1
@@ -32,7 +32,7 @@ TRACEFS_HEADERS := $$($(PKG_CONFIG) --cflags libtracefs) CFLAGS := -O -g -DVERSION=\"$(VERSION)\" $(FOPTS) $(MOPTS) $(WOPTS) $(TRACEFS_HEADERS) LDFLAGS := -ggdb -LIBS := $$($(PKG_CONFIG) --libs libtracefs) -lprocps +LIBS := $$($(PKG_CONFIG) --libs libtracefs) SRC := $(wildcard src/*.c) HDR := $(wildcard src/*.h)
tools/tracing/rtla/README.txt +0 -1
@@ -11,7 +11,6 @@ RTLA depends on the following libraries and tools: - libtracefs - libtraceevent - - procps It also depends on python3-docutils to compile man pages.
tools/tracing/rtla/src/utils.c +85 -21
135 lines not on this page · raw message
tools/tracing/rtla/src/utils.h +2 -1
@@ -6,6 +6,7 @@* '18446744073709551615\0' */ #define BUFF_U64_STR_SIZE 24 +#define MAX_PATH 1024#define container_of (ptr, type, member)({ \ const typeof(((type *)0)->member) *__mptr = (ptr); \
@@ -53,5 +54,5 @@ struct sched_attr { };int parse_prio (char *arg,struct sched_attr *sched_param); -int set_comm_sched_attr (const char *comm,struct sched_attr *attr); +int set_comm_sched_attr (const char *comm_prefix,struct sched_attr *attr);int set_cpu_dma_latency (int32_t latency);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 703/879 tracing/timerlat: Notify IRQ new max latency only if stop tracing is set
In reply to Greg Kroah-HartmanFrom: Daniel Bristot de Oliveira <[email protected]>
[ Upstream commit aa748949b4e665f473bc5abdc5f66029cb5f5522 ]
Currently, the notification of a new max latency is sent from timerlat's IRQ handler anytime a new max latency is found.
While this behavior is not wrong, the send IPI overhead itself will increase the thread latency and that is not the desired effect (tracing overhead).
Moreover, the thread will notify a new max latency again because the thread latency as it is always higher than the IRQ latency that woke it up.
The only case in which it is helpful to notify a new max latency from IRQ is when stop tracing (for the IRQ) is set, as in this case, the thread will not be dispatched.
Notify a new max latency from the IRQ handler only if stop tracing is set for the IRQ handler.
--- kernel/trace/trace_osnoise.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
kernel/trace/trace_osnoise.c +5 -4
@@ -1578,11 +1578,12 @@ static enum hrtimer_restart timerlat_irq(struct hrtimer *timer)trace_timerlat_sample (&s); -notify_new_max_latency (diff); - -if (osnoise_data.stop_tracing) -if (time_to_us (diff) >= osnoise_data.stop_tracing) +if (osnoise_data.stop_tracing) { +if (time_to_us (diff) >= osnoise_data.stop_tracing) {osnoise_stop_tracing (); +notify_new_max_latency (diff); + } + }wake_up_process (tlat->kthread);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 704/879 perf jevents: Fix event syntax error caused by ExtSel
In reply to Greg Kroah-HartmanFrom: Zhengjun Xing <[email protected]>
[ Upstream commit f4df0dbbe62ee8e4405a57b27ccd54393971c773 ]
In the origin code, when "ExtSel" is 1, the eventcode will change to "eventcode |= 1 << 21”. For event “UNC_Q_RxL_CREDITS_CONSUMED_VN0.DRS", its "ExtSel" is "1", its eventcode will change from 0x1E to 0x20001E, but in fact the eventcode should <=0x1FF, so this will cause the parse fail:
# perf stat -e "UNC_Q_RxL_CREDITS_CONSUMED_VN0.DRS" -a sleep 0.1
event syntax error: '.._RxL_CREDITS_CONSUMED_VN0.DRS'
\___ value too big for format, maximum is 511On the perf kernel side, the kernel assumes the valid bits are continuous. It will adjust the 0x100 (bit 8 for perf tool) to bit 21 in HW.
DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
So the perf tool follows the kernel side and just set bit8 other than bit21.
--- tools/perf/pmu-events/jevents.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/pmu-events/jevents.c +1 -1
@@ -612,7 +612,7 @@ static int json_events(const char *fn, }else if (json_streq (map, field,"ExtSel" )) {char *code =NULL ;addfield (map, &code,"" ,"" , val); - eventcode |=strtoul (code,NULL ,0 ) <<21 ; + eventcode |=strtoul (code,NULL ,0 ) <<8 ;free (code); }else if (json_streq (map, field,"EventName" )) {addfield (map, &je.name,"" ,"" , val);
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 705/879 video: fbdev: vesafb: Fix a use-after-free due early fb_info cleanup
In reply to Greg Kroah-HartmanFrom: Javier Martinez Canillas <[email protected]>
[ Upstream commit acde4003efc16480375543638484d8f13f2e99a3 ]
Commit b3c9a924aab6 ("fbdev: vesafb: Cleanup fb_info in .fb_destroy rather than .remove") fixed a use-after-free error due the vesafb driver freeing the fb_info in the .remove handler instead of doing it in .fb_destroy.
This can happen if the .fb_destroy callback is executed after the .remove callback, since the former tries to access a pointer freed by the latter.
But that change didn't take into account that another possible scenario is that .fb_destroy is called before the .remove callback. For example, if no process has the fbdev chardev opened by the time the driver is removed.
If that's the case, fb_info will be freed when unregister_framebuffer() is called, making the fb_info pointer accessed in vesafb_remove() after that to no longer be valid.
To prevent that, move the expression containing the info->par to happen before the unregister_framebuffer() function call.
--- drivers/video/fbdev/vesafb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/video/fbdev/vesafb.c +3 -2
@@ -490,11 +490,12 @@ static int vesafb_remove(struct platform_device *pdev) {struct fb_info *info =platform_get_drvdata (pdev); -/* vesafb_destroy takes care of info cleanup */ -unregister_framebuffer (info);if (((struct vesafb_par *)(info->par))->region)release_region (0x3c0 ,32 ); +/* vesafb_destroy takes care of info cleanup */ +unregister_framebuffer (info); +return 0 ; }
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 706/879 NFSv4: Fix free of uninitialized nfs4_label on referral lookup.
In reply to Greg Kroah-HartmanFrom: Benjamin Coddington <[email protected]>
[ Upstream commit c3ed222745d9ad7b69299b349a64ba533c64a34f ]
Send along the already-allocated fattr along with nfs4_fs_locations, and drop the memcpy of fattr. We end up growing two more allocations, but this fixes up a crash as:
PID: 790 TASK: ffff88811b43c000 CPU: 0 COMMAND: "ls"
#0 [ffffc90000857920] panic at ffffffff81b9bfde
#1 [ffffc900008579c0] do_trap at ffffffff81023a9b
#2 [ffffc90000857a10] do_error_trap at ffffffff81023b78 #3 [ffffc90000857a58] exc_stack_segment at ffffffff81be1f45 #4 [ffffc90000857a80] asm_exc_stack_segment at ffffffff81c009de #5 [ffffc90000857b08] nfs_lookup at ffffffffa0302322 [nfs] #6 [ffffc90000857b70] __lookup_slow at ffffffff813a4a5f #7 [ffffc90000857c60] walk_component at ffffffff813a86c4 #8 [ffffc90000857cb8] path_lookupat at ffffffff813a9553 #9 [ffffc90000857cf0] filename_lookup at ffffffff813ab86b
--- fs/nfs/nfs4namespace.c | 9 +++++++-- fs/nfs/nfs4proc.c | 15 +++++++-------- fs/nfs/nfs4state.c | 9 ++++++++- fs/nfs/nfs4xdr.c | 4 ++-- include/linux/nfs_xdr.h | 2 +- 5 files changed, 25 insertions(+), 14 deletions(-)
fs/nfs/nfs4namespace.c +7 -2
@@ -417,6 +417,9 @@ static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client) fs_locations =kmalloc (sizeof (struct nfs4_fs_locations ),GFP_KERNEL );if (!fs_locations) goto out_free; + fs_locations->fattr =nfs_alloc_fattr (); +if (!fs_locations->fattr) + goto out_free_2;/* Get locations */ dentry = ctx->clone_data.dentry;
@@ -427,14 +430,16 @@ static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client) err =nfs4_proc_fs_locations (client,d_inode (parent), &dentry->d_name, fs_locations, page);dput (parent);if (err !=0 ) - goto out_free_2; + goto out_free_3; err = -ENOENT ;if (fs_locations->nlocations <=0 || fs_locations->fs_path.ncomponents <=0 ) - goto out_free_2; + goto out_free_3; err =nfs_follow_referral (fc, fs_locations); +out_free_3: +kfree (fs_locations->fattr); out_free_2:kfree (fs_locations); out_free:
fs/nfs/nfs4proc.c +7 -8
@@ -4243,6 +4243,8 @@ static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir,if (locations ==NULL ) goto out; + locations->fattr = fattr; + status =nfs4_proc_fs_locations (client, dir, name, locations, page);if (status !=0 ) goto out;
@@ -4252,17 +4254,14 @@ static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir,* referral. Cause us to drop into the exception handler, which * will kick off migration recovery. */ -if (nfs_fsid_equal (&NFS_SERVER (dir)->fsid, &locations->fattr.fsid)) { +if (nfs_fsid_equal (&NFS_SERVER (dir)->fsid, &fattr->fsid)) {dprintk ("%s: server did not return a different fsid for" " a referral at %s\n" , __func__, name->name); status = -NFS4ERR_MOVED ; goto out; }/* Fixup attributes for the nfs_lookup() call to nfs_fhget() */ -nfs_fixup_referral_attributes (&locations->fattr); - -/* replace the lookup nfs_fattr with the locations nfs_fattr */ -memcpy (fattr, &locations->fattr,sizeof (struct nfs_fattr )); +nfs_fixup_referral_attributes (fattr);memset (fhandle,0 ,sizeof (struct nfs_fh )); out:if (page)
@@ -7902,7 +7901,7 @@ static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,else bitmask[1 ] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID ; -nfs_fattr_init (&fs_locations->fattr); +nfs_fattr_init (fs_locations->fattr); fs_locations->server = server; fs_locations->nlocations =0 ; status =nfs4_call_sync (client, server, &msg, &args.seq_args, &res.seq_res,0 );
@@ -7967,7 +7966,7 @@ static int _nfs40_proc_get_locations(struct nfs_server *server,unsigned long now = jiffies;int status; -nfs_fattr_init (&locations->fattr); +nfs_fattr_init (locations->fattr); locations->server = server; locations->nlocations =0 ;
@@ -8032,7 +8031,7 @@ static int _nfs41_proc_get_locations(struct nfs_server *server, };int status; -nfs_fattr_init (&locations->fattr); +nfs_fattr_init (locations->fattr); locations->server = server; locations->nlocations =0 ;
fs/nfs/nfs4state.c +8 -1
@@ -2106,6 +2106,11 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *creddprintk ("<-- %s: no memory\n" , __func__); goto out; } + locations->fattr =nfs_alloc_fattr (); +if (locations->fattr ==NULL ) { +dprintk ("<-- %s: no memory\n" , __func__); + goto out; + } inode =d_inode (server->super->s_root); result = nfs4_proc_get_locations(server, NFS_FH(inode), locations,
@@ -2120,7 +2125,7 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *credif (!locations->nlocations) goto out; -if (!(locations->fattr.valid &NFS_ATTR_FATTR_V4_LOCATIONS )) { +if (!(locations->fattr->valid &NFS_ATTR_FATTR_V4_LOCATIONS )) {dprintk ("<-- %s: No fs_locations data, migration skipped\n" , __func__); goto out;
@@ -2145,6 +2150,8 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred out:if (page !=NULL )__free_page (page); +if (locations !=NULL ) +kfree (locations->fattr);kfree (locations);if (result) { pr_err("NFS: migration recovery failed (server %s)\n",
fs/nfs/nfs4xdr.c +2 -2
@@ -7051,7 +7051,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,if (res->migration) {xdr_enter_page (xdr,PAGE_SIZE ); status =decode_getfattr_generic (xdr, - &res->fs_locations->fattr, + res->fs_locations->fattr,NULL , res->fs_locations, res->fs_locations->server);if (status)
@@ -7064,7 +7064,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, goto out;xdr_enter_page (xdr,PAGE_SIZE ); status =decode_getfattr_generic (xdr, - &res->fs_locations->fattr, + res->fs_locations->fattr,NULL , res->fs_locations, res->fs_locations->server); }
include/linux/nfs_xdr.h +1 -1
@@ -1212,7 +1212,7 @@ struct nfs4_fs_location {#define NFS4_FS_LOCATIONS_MAXENTRIES 10struct nfs4_fs_locations { -struct nfs_fattr fattr; +struct nfs_fattr *fattr;const struct nfs_server *server;struct nfs4_pathname fs_path;int nlocations;
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 707/879 NFSv4.1 mark qualified async operations as MOVEABLE tasks
In reply to Greg Kroah-HartmanFrom: Olga Kornievskaia <[email protected]>
[ Upstream commit 118f09eda21d392e1eeb9f8a4bee044958cccf20 ]
Mark async operations such as RENAME, REMOVE, COMMIT MOVEABLE for the nfsv4.1+ sessions.
--- fs/nfs/nfs4proc.c | 26 ++++++++++++++------------ fs/nfs/pagelist.c | 3 +++ fs/nfs/unlink.c | 8 ++++++++ fs/nfs/write.c | 4 ++++ include/linux/nfs_fs_sb.h | 1 + 5 files changed, 30 insertions(+), 12 deletions(-)
fs/nfs/nfs4proc.c +14 -12
@@ -1162,7 +1162,7 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, {unsigned short task_flags =0 ; -if (server->nfs_client->cl_minorversion) +if (server->caps &NFS_CAP_MOVEABLE ) task_flags =RPC_TASK_MOVEABLE ;return nfs4_do_call_sync (clnt, server, msg, args, res, task_flags); }
@@ -2568,7 +2568,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, };int status; -if (server->nfs_client->cl_minorversion) +if (nfs_server_capable (dir,NFS_CAP_MOVEABLE )) task_setup_data.flags |=RPC_TASK_MOVEABLE ;kref_get (&data->kref);
@@ -3733,7 +3733,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait) };int status = -ENOMEM ; -if (server->nfs_client->cl_minorversion) +if (nfs_server_capable (state->inode,NFS_CAP_MOVEABLE )) task_setup_data.flags |=RPC_TASK_MOVEABLE ; nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_CLEANUP,
@@ -4403,7 +4403,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, };unsigned short task_flags =0 ; -if (server->nfs_client->cl_minorversion) +if (nfs_server_capable (dir,NFS_CAP_MOVEABLE )) task_flags =RPC_TASK_MOVEABLE ;/* Is this is an attribute revalidation, subject to softreval? */
@@ -6611,10 +6611,13 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred, .rpc_client = server->client, .rpc_message = &msg, .callback_ops = &nfs4_delegreturn_ops, - .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT | RPC_TASK_MOVEABLE, + .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT, };int status =0 ; +if (nfs_server_capable (inode,NFS_CAP_MOVEABLE )) + task_setup_data.flags |=RPC_TASK_MOVEABLE ; + data =kzalloc (sizeof (*data),GFP_KERNEL );if (data ==NULL )return -ENOMEM ;
@@ -6928,10 +6931,8 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, .workqueue = nfsiod_workqueue, .flags = RPC_TASK_ASYNC, }; -struct nfs_client *client = -NFS_SERVER (lsp->ls_state->inode)->nfs_client; -if (client->cl_minorversion) +if (nfs_server_capable (lsp->ls_state->inode,NFS_CAP_MOVEABLE )) task_setup_data.flags |=RPC_TASK_MOVEABLE ; nfs4_state_protect(NFS_SERVER(lsp->ls_state->inode)->nfs_client,
@@ -7202,9 +7203,8 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f .flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF, };int ret; -struct nfs_client *client =NFS_SERVER (state->inode)->nfs_client; -if (client->cl_minorversion) +if (nfs_server_capable (state->inode,NFS_CAP_MOVEABLE )) task_setup_data.flags |=RPC_TASK_MOVEABLE ; data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file),
@@ -10390,7 +10390,8 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { | NFS_CAP_POSIX_LOCK |NFS_CAP_STATEID_NFSV41 |NFS_CAP_ATOMIC_OPEN_V1 - | NFS_CAP_LGOPEN, + |NFS_CAP_LGOPEN + | NFS_CAP_MOVEABLE, .init_client = nfs41_init_client, .shutdown_client = nfs41_shutdown_client, .match_stateid = nfs41_match_stateid,
@@ -10425,7 +10426,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = { | NFS_CAP_LAYOUTSTATS |NFS_CAP_CLONE |NFS_CAP_LAYOUTERROR - | NFS_CAP_READ_PLUS, + |NFS_CAP_READ_PLUS + | NFS_CAP_MOVEABLE, .init_client = nfs41_init_client, .shutdown_client = nfs41_shutdown_client, .match_stateid = nfs41_match_stateid,
fs/nfs/pagelist.c +3 -0
@@ -767,6 +767,9 @@ int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr, .flags = RPC_TASK_ASYNC | flags, }; +if (nfs_server_capable (hdr->inode,NFS_CAP_MOVEABLE )) + task_setup_data.flags |=RPC_TASK_MOVEABLE ; + hdr->rw_ops->rw_initiate (hdr, &msg, rpc_ops, &task_setup_data, how); dprintk("NFS: initiated pgio call "
fs/nfs/unlink.c +8 -0
@@ -102,6 +102,10 @@ static void nfs_do_call_unlink(struct inode *inode, struct nfs_unlinkdata *data) };struct rpc_task *task;struct inode *dir =d_inode (data->dentry->d_parent); + +if (nfs_server_capable (inode,NFS_CAP_MOVEABLE )) + task_setup_data.flags |=RPC_TASK_MOVEABLE ; +nfs_sb_active (dir->i_sb); data->args.fh =NFS_FH (dir);nfs_fattr_init (data->res.dir_attr);
@@ -344,6 +348,10 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir, .flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF, }; +if (nfs_server_capable (old_dir,NFS_CAP_MOVEABLE ) && +nfs_server_capable (new_dir,NFS_CAP_MOVEABLE )) + task_setup_data.flags |=RPC_TASK_MOVEABLE ; + data =kzalloc (sizeof (*data),GFP_KERNEL );if (data ==NULL )return ERR_PTR (-ENOMEM );
fs/nfs/write.c +4 -0
@@ -1709,6 +1709,10 @@ int nfs_initiate_commit(struct rpc_clnt *clnt, struct nfs_commit_data *data, .flags = RPC_TASK_ASYNC | flags, .priority = priority, }; + +if (nfs_server_capable (data->inode,NFS_CAP_MOVEABLE )) + task_setup_data.flags |=RPC_TASK_MOVEABLE ; +/* Set up the initial task struct. */ nfs_ops->commit_setup (data, &msg, &task_setup_data.rpc_client);trace_nfs_initiate_commit (data);
include/linux/nfs_fs_sb.h +1 -0
@@ -287,4 +287,5 @@ struct nfs_server {#define NFS_CAP_XATTR (1U << 28)#define NFS_CAP_READ_PLUS (1U << 29)#define NFS_CAP_FS_LOCATIONS (1U << 30) +#define NFS_CAP_MOVEABLE (1U << 31)#endif
Signature · 1 line
2.35.1
Greg Kroah-Hartman
maintainerPATCH 708/879 f2fs: fix to avoid f2fs_bug_on() in dec_valid_node_count()
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit 4d17e6fe9293d57081ffdc11e1cf313e25e8fd9e upstream.
As Yanming reported in bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=215897
I have encountered a bug in F2FS file system in kernel v5.17.
The kernel should enable CONFIG_KASAN=y and CONFIG_KASAN_INLINE=y. You can reproduce the bug by running the following commands:
The kernel message is shown below:
kernel BUG at fs/f2fs/f2fs.h:2511!
Call Trace: f2fs_remove_inode_page+0x2a2/0x830 f2fs_evict_inode+0x9b7/0x1510 evict+0x282/0x4e0 do_unlinkat+0x33a/0x540 __x64_sys_unlinkat+0x8e/0xd0 do_syscall_64+0x3b/0x90 entry_SYSCALL_64_after_hwframe+0x44/0xae
The root cause is: .total_valid_block_count or .total_valid_node_count could fuzzed to zero, then once dec_valid_node_count() was called, it will cause BUG_ON(), this patch fixes to print warning info and set SBI_NEED_FSCK into CP instead of panic.
--- fs/f2fs/f2fs.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
fs/f2fs/f2fs.h +10 -4
@@ -2605,11 +2605,17 @@ static inline void dec_valid_node_count( {spin_lock (&sbi->stat_lock); -f2fs_bug_on (sbi, !sbi->total_valid_block_count); -f2fs_bug_on (sbi, !sbi->total_valid_node_count); +if (unlikely (!sbi->total_valid_block_count || + !sbi->total_valid_node_count)) { +f2fs_warn (sbi,"dec_valid_node_count: inconsistent block counts, total_valid_block:%u, total_valid_node:%u" , + sbi->total_valid_block_count, + sbi->total_valid_node_count); +set_sbi_flag (sbi,SBI_NEED_FSCK ); + }else { + sbi->total_valid_block_count--; + sbi->total_valid_node_count--; + } - sbi->total_valid_node_count--; - sbi->total_valid_block_count--;if (sbi->reserved_blocks && sbi->current_reserved_blocks < sbi->reserved_blocks) sbi->current_reserved_blocks++;
Greg Kroah-Hartman
maintainerPATCH 709/879 f2fs: fix to do sanity check on block address in f2fs_do_zero_range()
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit 25f8236213a91efdf708b9d77e9e51b6fc3e141c upstream.
As Yanming reported in bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=215894
I have encountered a bug in F2FS file system in kernel v5.17.
I have uploaded the system call sequence as case.c, and a fuzzed image can be found in google net disk
The kernel should enable CONFIG_KASAN=y and CONFIG_KASAN_INLINE=y. You can reproduce the bug by running the following commands:
kernel BUG at fs/f2fs/segment.c:2291!
Call Trace: f2fs_invalidate_blocks+0x193/0x2d0 f2fs_fallocate+0x2593/0x4a70 vfs_fallocate+0x2a5/0xac0 ksys_fallocate+0x35/0x70 __x64_sys_fallocate+0x8e/0xf0 do_syscall_64+0x3b/0x90 entry_SYSCALL_64_after_hwframe+0x44/0xae
The root cause is, after image was fuzzed, block mapping info in inode will be inconsistent with SIT table, so in f2fs_fallocate(), it will cause panic when updating SIT with invalid blkaddr.
Let's fix the issue by adding sanity check on block address before updating SIT table with it.
--- fs/f2fs/file.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
fs/f2fs/file.c +12 -4
@@ -1437,11 +1437,19 @@ static int f2fs_do_zero_range(struct dno ret = -ENOSPC ;break ; } -if (dn->data_blkaddr !=NEW_ADDR ) { -f2fs_invalidate_blocks (sbi, dn->data_blkaddr); - dn->data_blkaddr =NEW_ADDR ; -f2fs_set_data_blkaddr (dn); + +if (dn->data_blkaddr ==NEW_ADDR ) +continue ; + +if (!f2fs_is_valid_blkaddr (sbi, dn->data_blkaddr, +DATA_GENERIC_ENHANCE )) { + ret = -EFSCORRUPTED ; +break ; } + +f2fs_invalidate_blocks (sbi, dn->data_blkaddr); + dn->data_blkaddr =NEW_ADDR ; +f2fs_set_data_blkaddr (dn); }f2fs_update_extent_cache_range (dn, start,0 , index - start);
Greg Kroah-Hartman
maintainerPATCH 710/879 f2fs: fix to clear dirty inode in f2fs_evict_inode()
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit f2db71053dc0409fae785096ad19cce4c8a95af7 upstream.
As Yanming reported in bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=215904
The kernel message is shown below:
kernel BUG at fs/f2fs/inode.c:825!
Call Trace: evict+0x282/0x4e0 __dentry_kill+0x2b2/0x4d0 shrink_dentry_list+0x17c/0x4f0 shrink_dcache_parent+0x143/0x1e0 do_one_tree+0x9/0x30 shrink_dcache_for_umount+0x51/0x120 generic_shutdown_super+0x5c/0x3a0 kill_block_super+0x90/0xd0 kill_f2fs_super+0x225/0x310 deactivate_locked_super+0x78/0xc0 cleanup_mnt+0x2b7/0x480 task_work_run+0xc8/0x150 exit_to_user_mode_prepare+0x14a/0x150 syscall_exit_to_user_mode+0x1d/0x40 do_syscall_64+0x48/0x90
The root cause is: inode node and dnode node share the same nid, so during f2fs_evict_inode(), dnode node truncation will invalidate its NAT entry, so when truncating inode node, it fails due to invalid NAT entry, result in inode is still marked as dirty, fix this issue by clearing dirty for inode and setting SBI_NEED_FSCK flag in filesystem.
output from dump.f2fs:
[print_node_info: 354] Node ID [0xf:15] is inode
i_nid[0] [0x f : 15]
--- fs/f2fs/inode.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
fs/f2fs/inode.c +15 -1
@@ -796,8 +796,22 @@ retry:f2fs_lock_op (sbi); err =f2fs_remove_inode_page (inode);f2fs_unlock_op (sbi); -if (err == -ENOENT ) +if (err == -ENOENT ) { err =0 ; + +/* +* in fuzzed image, another node may has the same +* block address as inode's, if it was truncated +* previously, truncation of inode node will fail. +*/ +if (is_inode_flag_set (inode,FI_DIRTY_INODE )) { +f2fs_warn (F2FS_I_SB (inode), +"f2fs_evict_inode: inconsistent node id, ino:%lu" , + inode->i_ino); +f2fs_inode_synced (inode); +set_sbi_flag (sbi,SBI_NEED_FSCK ); + } + } }/* give more chances, if ENOMEM case */
Greg Kroah-Hartman
maintainerPATCH 711/879 f2fs: fix deadloop in foreground GC
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit cfd66bb715fd11fde3338d0660cffa1396adc27d upstream.
As Yanming reported in bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=215914
The root cause is: in a very small sized image, it's very easy to exceed threshold of foreground GC, if we calculate free space and dirty data based on section granularity, in corner case, has_not_enough_free_secs() will always return true, result in deadloop in f2fs_gc().
So this patch refactors has_not_enough_free_secs() as below to fix this issue:
1. calculate needed space based on block granularity, and separate all blocks to two parts, section part, and block part, comparing section part to free section, and comparing block part to free space in openned log.
2. account F2FS_DIRTY_NODES, F2FS_DIRTY_IMETA and F2FS_DIRTY_DENTS as node block consumer;
3. account F2FS_DIRTY_DENTS as data block consumer;
--- fs/f2fs/segment.h | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-)
fs/f2fs/segment.h +20 -12
@@ -572,11 +572,10 @@ static inline int reserved_sections(strureturn GET_SEC_FROM_SEG (sbi,reserved_segments (sbi)); } -static inline bool has_curseg_enough_space (struct f2fs_sb_info *sbi) +static inline bool has_curseg_enough_space (struct f2fs_sb_info *sbi, +unsigned int node_blocks,unsigned int dent_blocks) { -unsigned int node_blocks =get_pages (sbi,F2FS_DIRTY_NODES ) + -get_pages (sbi,F2FS_DIRTY_DENTS ); -unsigned int dent_blocks =get_pages (sbi,F2FS_DIRTY_DENTS ); +unsigned int segno, left_blocks;int i;
@@ -602,19 +601,28 @@ static inline bool has_curseg_enough_spastatic inline bool has_not_enough_free_secs (struct f2fs_sb_info *sbi,int freed,int needed) { -int node_secs =get_blocktype_secs (sbi,F2FS_DIRTY_NODES ); -int dent_secs =get_blocktype_secs (sbi,F2FS_DIRTY_DENTS ); -int imeta_secs =get_blocktype_secs (sbi,F2FS_DIRTY_IMETA ); +unsigned int total_node_blocks =get_pages (sbi,F2FS_DIRTY_NODES ) + +get_pages (sbi,F2FS_DIRTY_DENTS ) + +get_pages (sbi,F2FS_DIRTY_IMETA ); +unsigned int total_dent_blocks =get_pages (sbi,F2FS_DIRTY_DENTS ); +unsigned int node_secs = total_node_blocks /BLKS_PER_SEC (sbi); +unsigned int dent_secs = total_dent_blocks /BLKS_PER_SEC (sbi); +unsigned int node_blocks = total_node_blocks %BLKS_PER_SEC (sbi); +unsigned int dent_blocks = total_dent_blocks %BLKS_PER_SEC (sbi); +unsigned int free, need_lower, need_upper;if (unlikely (is_sbi_flag_set (sbi,SBI_POR_DOING )))return false; -if (free_sections (sbi) + freed ==reserved_sections (sbi) + needed && -has_curseg_enough_space (sbi)) + free =free_sections (sbi) + freed; + need_lower = node_secs + dent_secs +reserved_sections (sbi) + needed; + need_upper = need_lower + (node_blocks ?1 :0 ) + (dent_blocks ?1 :0 ); + +if (free > need_upper)return false; -return (free_sections (sbi) + freed) <= - (node_secs +2 * dent_secs + imeta_secs + -reserved_sections (sbi) + needed); +else if (free <= need_lower) +return true; +return !has_curseg_enough_space (sbi, node_blocks, dent_blocks); }static inline bool f2fs_is_checkpoint_ready (struct f2fs_sb_info *sbi)
Greg Kroah-Hartman
maintainerPATCH 712/879 f2fs: dont need inode lock for system hidden quota
In reply to Greg Kroah-HartmanFrom: Jaegeuk Kim <[email protected]>
commit 6213f5d4d23c50d393a31dc8e351e63a1fd10dbe upstream.
Let's avoid false-alarmed lockdep warning.
[ 58.914674] [T1501146] -> #2 (&sb->s_type->i_mutex_key#20){+.+.}-{3:3}:
[ 58.915975] [T1501146] system_server: down_write+0x7c/0xe0
[ 58.916738] [T1501146] system_server: f2fs_quota_sync+0x60/0x1a8
[ 58.917563] [T1501146] system_server: block_operations+0x16c/0x43c
[ 58.918410] [T1501146] system_server: f2fs_write_checkpoint+0x114/0x318
[ 58.919312] [T1501146] system_server: f2fs_issue_checkpoint+0x178/0x21c
[ 58.920214] [T1501146] system_server: f2fs_sync_fs+0x48/0x6c
[ 58.920999] [T1501146] system_server: f2fs_do_sync_file+0x334/0x738
[ 58.921862] [T1501146] system_server: f2fs_sync_file+0x30/0x48
[ 58.922667] [T1501146] system_server: __arm64_sys_fsync+0x84/0xf8
[ 58.923506] [T1501146] system_server: el0_svc_common.llvm.12821150825140585682+0xd8/0x20c
[ 58.924604] [T1501146] system_server: do_el0_svc+0x28/0xa0
[ 58.925366] [T1501146] system_server: el0_svc+0x24/0x38
[ 58.926094] [T1501146] system_server: el0_sync_handler+0x88/0xec
[ 58.926920] [T1501146] system_server: el0_sync+0x1b4/0x1c0[ 58.927681] [T1501146] -> #1 (&sbi->cp_global_sem){+.+.}-{3:3}:
[ 58.928889] [T1501146] system_server: down_write+0x7c/0xe0
[ 58.929650] [T1501146] system_server: f2fs_write_checkpoint+0xbc/0x318
[ 58.930541] [T1501146] system_server: f2fs_issue_checkpoint+0x178/0x21c
[ 58.931443] [T1501146] system_server: f2fs_sync_fs+0x48/0x6c
[ 58.932226] [T1501146] system_server: sync_filesystem+0xac/0x130
[ 58.933053] [T1501146] system_server: generic_shutdown_super+0x38/0x150
[ 58.933958] [T1501146] system_server: kill_block_super+0x24/0x58
[ 58.934791] [T1501146] system_server: kill_f2fs_super+0xcc/0x124
[ 58.935618] [T1501146] system_server: deactivate_locked_super+0x90/0x120
[ 58.936529] [T1501146] system_server: deactivate_super+0x74/0xac
[ 58.937356] [T1501146] system_server: cleanup_mnt+0x128/0x168
[ 58.938150] [T1501146] system_server: __cleanup_mnt+0x18/0x28
[ 58.938944] [T1501146] system_server: task_work_run+0xb8/0x14c
[ 58.939749] [T1501146] system_server: do_notify_resume+0x114/0x1e8
[ 58.940595] [T1501146] system_server: work_pending+0xc/0x5f0[ 58.941375] [T1501146] -> #0 (&sbi->gc_lock){+.+.}-{3:3}:
[ 58.942519] [T1501146] system_server: __lock_acquire+0x1270/0x2868
[ 58.943366] [T1501146] system_server: lock_acquire+0x114/0x294
[ 58.944169] [T1501146] system_server: down_write+0x7c/0xe0
[ 58.944930] [T1501146] system_server: f2fs_issue_checkpoint+0x13c/0x21c
[ 58.945831] [T1501146] system_server: f2fs_sync_fs+0x48/0x6c
[ 58.946614] [T1501146] system_server: f2fs_do_sync_file+0x334/0x738
[ 58.947472] [T1501146] system_server: f2fs_ioc_commit_atomic_write+0xc8/0x14c
[ 58.948439] [T1501146] system_server: __f2fs_ioctl+0x674/0x154c
[ 58.949253] [T1501146] system_server: f2fs_ioctl+0x54/0x88
[ 58.950018] [T1501146] system_server: __arm64_sys_ioctl+0xa8/0x110
[ 58.950865] [T1501146] system_server: el0_svc_common.llvm.12821150825140585682+0xd8/0x20c
[ 58.951965] [T1501146] system_server: do_el0_svc+0x28/0xa0
[ 58.952727] [T1501146] system_server: el0_svc+0x24/0x38
[ 58.953454] [T1501146] system_server: el0_sync_handler+0x88/0xec
[ 58.954279] [T1501146] system_server: el0_sync+0x1b4/0x1c0--- fs/f2fs/super.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
fs/f2fs/super.c +4 -2
@@ -2684,7 +2684,8 @@ int f2fs_quota_sync(struct super_block *if (!sb_has_quota_active (sb, cnt))continue ; -inode_lock (dqopt->files[cnt]); +if (!f2fs_sb_has_quota_ino (sbi)) +inode_lock (dqopt->files[cnt]);/* * do_quotactl
@@ -2703,7 +2704,8 @@ int f2fs_quota_sync(struct super_block *f2fs_up_read (&sbi->quota_sem);f2fs_unlock_op (sbi); -inode_unlock (dqopt->files[cnt]); +if (!f2fs_sb_has_quota_ino (sbi)) +inode_unlock (dqopt->files[cnt]);if (ret)break ;
Greg Kroah-Hartman
maintainerPATCH 713/879 f2fs: fix to do sanity check on total_data_blocks
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit 6b8beca0edd32075a769bfe4178ca00c0dcd22a9 upstream.
As Yanming reported in bugzilla:
https://bugzilla.kernel.org/show_bug.cgi?id=215916
The kernel message is shown below:
kernel BUG at fs/f2fs/segment.c:2560!
Call Trace: allocate_segment_by_default+0x228/0x440 f2fs_allocate_data_block+0x13d1/0x31f0 do_write_page+0x18d/0x710 f2fs_outplace_write_data+0x151/0x250 f2fs_do_write_data_page+0xef9/0x1980 move_data_page+0x6af/0xbc0 do_garbage_collect+0x312f/0x46f0 f2fs_gc+0x6b0/0x3bc0 f2fs_balance_fs+0x921/0x2260 f2fs_write_single_data_page+0x16be/0x2370 f2fs_write_cache_pages+0x428/0xd00 f2fs_write_data_pages+0x96e/0xd50 do_writepages+0x168/0x550 __writeback_single_inode+0x9f/0x870 writeback_sb_inodes+0x47d/0xb20 __writeback_inodes_wb+0xb2/0x200 wb_writeback+0x4bd/0x660 wb_workfn+0x5f3/0xab0 process_one_work+0x79f/0x13e0 worker_thread+0x89/0xf60 kthread+0x26a/0x300 ret_from_fork+0x22/0x30 RIP: 0010:new_curseg+0xe8d/0x15f0
The root cause is: ckpt.valid_block_count is inconsistent with SIT table, stat info indicates filesystem has free blocks, but SIT table indicates filesystem has no free segment.
So that during garbage colloection, it triggers panic when LFS allocator fails to find free segment.
This patch tries to fix this issue by checking consistency in between ckpt.valid_block_count and block accounted from SIT.
--- fs/f2fs/f2fs.h | 4 ++-- fs/f2fs/segment.c | 33 ++++++++++++++++++++++----------- fs/f2fs/segment.h | 1 + 3 files changed, 25 insertions(+), 13 deletions(-)
fs/f2fs/f2fs.h +2 -2
@@ -1117,8 +1117,8 @@ enum count_type {*/ #define PAGE_TYPE_OF_BIO (type) ((type) > META ? META : (type))enum page_type { -DATA , -NODE , +DATA =0 , +NODE =1 ,/* should not change this */ META ,NR_PAGE_TYPE ,META_FLUSH ,
fs/f2fs/segment.c +22 -11
@@ -4460,7 +4460,7 @@ static int build_sit_entries(struct f2fsunsigned int i, start, end;unsigned int readed, start_blk =0 ;int err =0 ; -block_t total_node_blocks =0 ; +block_t sit_valid_blocks[2 ] = {0 ,0 }; do { readed = f2fs_ra_meta_pages(sbi, start_blk, BIO_MAX_VECS,
@@ -4485,8 +4485,8 @@ static int build_sit_entries(struct f2fsif (err)return err;seg_info_from_raw_sit (se, &sit); -if (IS_NODESEG (se->type)) - total_node_blocks += se->valid_blocks; + + sit_valid_blocks[SE_PAGETYPE (se)] += se->valid_blocks;if (f2fs_block_unit_discard (sbi)) {/* build discard map only one time */
@@ -4526,15 +4526,15 @@ static int build_sit_entries(struct f2fs sit =sit_in_journal (journal, i); old_valid_blocks = se->valid_blocks; -if (IS_NODESEG (se->type)) - total_node_blocks -= old_valid_blocks; + + sit_valid_blocks[SE_PAGETYPE (se)] -= old_valid_blocks; err =check_block_count (sbi, start, &sit);if (err)break ;seg_info_from_raw_sit (se, &sit); -if (IS_NODESEG (se->type)) - total_node_blocks += se->valid_blocks; + + sit_valid_blocks[SE_PAGETYPE (se)] += se->valid_blocks;if (f2fs_block_unit_discard (sbi)) {if (is_set_ckpt_flags (sbi,CP_TRIMMED_FLAG )) {
@@ -4556,13 +4556,24 @@ static int build_sit_entries(struct f2fs }up_read (&curseg->journal_rwsem); -if (!err && total_node_blocks !=valid_node_count (sbi)) { +if (err) +return err; + +if (sit_valid_blocks[NODE ] !=valid_node_count (sbi)) {f2fs_err (sbi,"SIT is corrupted node# %u vs %u" , - total_node_blocks,valid_node_count (sbi)); - err = -EFSCORRUPTED ; + sit_valid_blocks[NODE ],valid_node_count (sbi)); +return -EFSCORRUPTED ; + } + +if (sit_valid_blocks[DATA ] + sit_valid_blocks[NODE ] > +valid_user_blocks (sbi)) { +f2fs_err (sbi,"SIT is corrupted data# %u %u vs %u" , + sit_valid_blocks[DATA ], sit_valid_blocks[NODE ], +valid_user_blocks (sbi)); +return -EFSCORRUPTED ; } -return err; +return 0 ; }static void init_free_segmap (struct f2fs_sb_info *sbi)
fs/f2fs/segment.h +1 -0
@@ -24,6 +24,7 @@#define IS_DATASEG (t) ((t) <= CURSEG_COLD_DATA)#define IS_NODESEG (t) ((t) >= CURSEG_HOT_NODE && (t) <= CURSEG_COLD_NODE) +#define SE_PAGETYPE (se) ((IS_NODESEG((se)->type) ? NODE : DATA))static inline void sanity_check_seg_type (struct f2fs_sb_info *sbi,unsigned short seg_type)
Greg Kroah-Hartman
maintainerPATCH 714/879 f2fs: dont use casefolded comparison for "." and ".."
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
commit b5639bb4313b9d455fc9fc4768d23a5e4ca8cb9d upstream.
Tryng to rename a directory that has all following properties fails with EINVAL and triggers the 'WARN_ON_ONCE(!fscrypt_has_encryption_key(dir))' in f2fs_match_ci_name():
- The directory is casefolded
- The directory is encrypted
- The directory's encryption key is not yet set up
- The parent directory is *not* encrypted
The problem is incorrect handling of the lookup of ".." to get the parent reference to update. fscrypt_setup_filename() treats ".." (and ".") specially, as it's never encrypted. It's passed through as-is, and setting up the directory's key is not attempted. As the name isn't a no-key name, f2fs treats it as a "normal" name and attempts a casefolded comparison. That breaks the assumption of the WARN_ON_ONCE() in f2fs_match_ci_name() which assumes that for encrypted directories, casefolded comparisons only happen when the directory's key is set up.
We could just remove this WARN_ON_ONCE(). However, since casefolding is always a no-op on "." and ".." anyway, let's instead just not casefold these names. This results in the standard bytewise comparison.
--- fs/f2fs/dir.c | 3 ++- fs/f2fs/f2fs.h | 10 +++++----- fs/f2fs/hash.c | 11 ++++++----- 3 files changed, 13 insertions(+), 11 deletions(-)
fs/f2fs/dir.c +2 -1
@@ -82,7 +82,8 @@ int f2fs_init_casefolded_name(const stru#if IS_ENABLED (CONFIG_UNICODE )struct super_block *sb = dir->i_sb; -if (IS_CASEFOLDED (dir)) { +if (IS_CASEFOLDED (dir) && + !is_dot_dotdot (fname->usr_fname->name, fname->usr_fname->len)) { fname->cf_name.name =f2fs_kmem_cache_alloc (f2fs_cf_name_slab,GFP_NOFS , false,F2FS_SB (sb));if (!fname->cf_name.name)
fs/f2fs/f2fs.h +5 -5
@@ -508,11 +508,11 @@ struct f2fs_filename {#if IS_ENABLED (CONFIG_UNICODE )/* * For casefolded directories: the casefolded name, but it's left NULL -* if the original name is not valid Unicode, if the directory is both -* casefolded and encrypted and its encryption key is unavailable, or if -* the filesystem is doing an internal operation where usr_fname is also -* NULL. In all these cases we fall back to treating the name as an -* opaque byte sequence. +* if the original name is not valid Unicode, if the original name is +* "." or "..", if the directory is both casefolded and encrypted and +* its encryption key is unavailable, or if the filesystem is doing an +* internal operation where usr_fname is also NULL. In all these cases +* we fall back to treating the name as an opaque byte sequence. */ struct fscrypt_str cf_name;#endif
fs/f2fs/hash.c +6 -5
@@ -91,7 +91,7 @@ static u32 TEA_hash_name(const u8 *p, si/* * Compute @fname->hash. For all directories, @fname->disk_name must be set. * For casefolded directories, @fname->usr_fname must be set, and also -* @fname->cf_name if the filename is valid Unicode. +* @fname->cf_name if the filename is valid Unicode and is not "." or "..". */ void f2fs_hash_filename (const struct inode *dir,struct f2fs_filename *fname) {
@@ -110,10 +110,11 @@ void f2fs_hash_filename(const struct ino/* * If the casefolded name is provided, hash it instead of the * on-disk name. If the casefolded name is *not* provided, that -* should only be because the name wasn't valid Unicode, so fall -* back to treating the name as an opaque byte sequence. Note -* that to handle encrypted directories, the fallback must use -* usr_fname (plaintext) rather than disk_name (ciphertext). +* should only be because the name wasn't valid Unicode or was +* "." or "..", so fall back to treating the name as an opaque +* byte sequence. Note that to handle encrypted directories, +* the fallback must use usr_fname (plaintext) rather than +* disk_name (ciphertext). */ WARN_ON_ONCE (!fname->usr_fname->name);if (fname->cf_name.name) {
Greg Kroah-Hartman
maintainerPATCH 715/879 f2fs: fix fallocate to use file_modified to update permissions consistently
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit 958ed92922028ec67f504dcdc72bfdfd0f43936a upstream.
This patch tries to fix permission consistency issue as all other mainline filesystems.
Since the initial introduction of (posix) fallocate back at the turn of the century, it has been possible to use this syscall to change the user-visible contents of files. This can happen by extending the file size during a preallocation, or through any of the newer modes (punch, zero, collapse, insert range). Because the call can be used to change file contents, we should treat it like we do any other modification to a file -- update the mtime, and drop set[ug]id privileges/capabilities.
The VFS function file_modified() does all this for us if pass it a locked inode, so let's make fallocate drop permissions correctly.
--- fs/f2fs/file.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/f2fs/file.c +4 -0
@@ -1774,6 +1774,10 @@ static long f2fs_fallocate(struct file *inode_lock (inode); + ret =file_modified (file); +if (ret) + goto out; +if (mode &FALLOC_FL_PUNCH_HOLE ) {if (offset >= inode->i_size) goto out;
Greg Kroah-Hartman
maintainerPATCH 716/879 f2fs: fix to do sanity check for inline inode
In reply to Greg Kroah-HartmanFrom: Chao Yu <[email protected]>
commit 677a82b44ebf263d4f9a0cfbd576a6ade797a07b upstream.
Yanming reported a kernel bug in Bugzilla kernel [1], which can be reproduced. The bug message is:
The kernel message is shown below:
kernel BUG at fs/inode.c:611!
Call Trace: evict+0x282/0x4e0 __dentry_kill+0x2b2/0x4d0 dput+0x2dd/0x720 do_renameat2+0x596/0x970 __x64_sys_rename+0x78/0x90 do_syscall_64+0x3b/0x90
[1] https://bugzilla.kernel.org/show_bug.cgi?id=215895
The bug is due to fuzzed inode has both inline_data and encrypted flags. During f2fs_evict_inode(), as the inode was deleted by rename(), it will cause inline data conversion due to conflicting flags. The page cache will be polluted and the panic will be triggered in clear_inode().
Try fixing the bug by doing more sanity checks for inline data inode in sanity_check_inode().
--- fs/f2fs/f2fs.h | 1 + fs/f2fs/inline.c | 29 ++++++++++++++++++++++++----- fs/f2fs/inode.c | 3 +-- 3 files changed, 26 insertions(+), 7 deletions(-)
fs/f2fs/f2fs.h +1 -0
@@ -4052,6 +4052,7 @@ extern struct kmem_cache *f2fs_inode_ent* inline.c */ bool f2fs_may_inline_data (struct inode *inode); +bool f2fs_sanity_check_inline_data (struct inode *inode);bool f2fs_may_inline_dentry (struct inode *inode);void f2fs_do_read_inline_data (struct page *page,struct page *ipage); void f2fs_truncate_inline_inode(struct inode *inode,
fs/f2fs/inline.c +24 -5
@@ -14,21 +14,40 @@#include "node.h" #include <trace/events/f2fs.h> -bool f2fs_may_inline_data (struct inode *inode) +static bool support_inline_data (struct inode *inode) {if (f2fs_is_atomic_file (inode))return false; -if (!S_ISREG (inode->i_mode) && !S_ISLNK (inode->i_mode))return false; -if (i_size_read (inode) >MAX_INLINE_DATA (inode))return false; +return true; +} + +bool f2fs_may_inline_data (struct inode *inode) +{ +if (!support_inline_data (inode)) +return false; + +return !f2fs_post_read_required (inode); +} -if (f2fs_post_read_required (inode)) +bool f2fs_sanity_check_inline_data (struct inode *inode) +{ +if (!f2fs_has_inline_data (inode))return false; -return true; +if (!support_inline_data (inode)) +return true; + +/* +* used by sanity_check_inode(), when disk layout fields has not +* been synchronized to inmem fields. +*/ +return (S_ISREG (inode->i_mode) && + (file_is_encrypt (inode) ||file_is_verity (inode) || + (F2FS_I (inode)->i_flags &F2FS_COMPR_FL ))); }bool f2fs_may_inline_dentry (struct inode *inode)
fs/f2fs/inode.c +1 -2
@@ -276,8 +276,7 @@ static bool sanity_check_inode(struct in } } -if (f2fs_has_inline_data (inode) && - (!S_ISREG (inode->i_mode) && !S_ISLNK (inode->i_mode))) { +if (f2fs_sanity_check_inline_data (inode)) {set_sbi_flag (sbi,SBI_NEED_FSCK );f2fs_warn (sbi,"%s: inode (ino=%lx, mode=%u) should not have inline_data, run fsck to fix" , __func__, inode->i_ino, inode->i_mode);
Greg Kroah-Hartman
maintainerPATCH 717/879 objtool: Fix objtool regression on x32 systems
In reply to Greg Kroah-HartmanFrom: Mikulas Patocka <[email protected]>
commit 22682a07acc308ef78681572e19502ce8893c4d4 upstream.
Commit c087c6e7b551 ("objtool: Fix type of reloc::addend") failed to appreciate cross building from ILP32 hosts, where 'int' == 'long' and the issue persists.
As such, use s64/int64_t/Elf64_Sxword for this field and suffer the pain that is ISO C99 printf formats for it.
--- tools/objtool/check.c | 9 +++++---- tools/objtool/elf.c | 2 +- tools/objtool/include/objtool/elf.h | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-)
tools/objtool/check.c +5 -4
@@ -5,6 +5,7 @@#include <string.h> #include <stdlib.h> +#include <inttypes.h> #include <sys/mman.h> #include <arch/elf.h>
@@ -560,12 +561,12 @@ static int add_dead_ends(struct objtool_else if (reloc->addend == reloc->sym->sec->sh.sh_size) { insn =find_last_insn (file, reloc->sym->sec);if (!insn) { -WARN ("can't find unreachable insn at %s+0x%lx" , +WARN ("can't find unreachable insn at %s+0x%" PRIx64, reloc->sym->sec->name, reloc->addend);return -1 ; } }else { -WARN ("can't find unreachable insn at %s+0x%lx" , +WARN ("can't find unreachable insn at %s+0x%" PRIx64, reloc->sym->sec->name, reloc->addend);return -1 ; }
@@ -595,12 +596,12 @@ reachable:else if (reloc->addend == reloc->sym->sec->sh.sh_size) { insn =find_last_insn (file, reloc->sym->sec);if (!insn) { -WARN ("can't find reachable insn at %s+0x%lx" , +WARN ("can't find reachable insn at %s+0x%" PRIx64, reloc->sym->sec->name, reloc->addend);return -1 ; } }else { -WARN ("can't find reachable insn at %s+0x%lx" , +WARN ("can't find reachable insn at %s+0x%" PRIx64, reloc->sym->sec->name, reloc->addend);return -1 ; }
tools/objtool/elf.c +1 -1
@@ -546,7 +546,7 @@ static struct section *elf_create_reloc_ int reltype);int elf_add_reloc (struct elf *elf,struct section *sec,unsigned long offset, -unsigned int type,struct symbol *sym,long addend) +unsigned int type,struct symbol *sym,s64 addend) {struct reloc *reloc;
tools/objtool/include/objtool/elf.h +2 -2
@@ -73,7 +73,7 @@ struct reloc {struct symbol *sym;unsigned long offset;unsigned int type; -long addend; +s64 addend;int idx;bool jump_table_start; };
@@ -135,7 +135,7 @@ struct elf *elf_open_read(const char *nastruct section *elf_create_section (struct elf *elf,const char *name,unsigned int sh_flags,size_t entsize,int nr);int elf_add_reloc (struct elf *elf,struct section *sec,unsigned long offset, -unsigned int type,struct symbol *sym,long addend); +unsigned int type,struct symbol *sym,s64 addend);int elf_add_reloc_to_insn (struct elf *elf,struct section *sec,unsigned long offset,unsigned int type,struct section *insn_sec,unsigned long insn_off);
Greg Kroah-Hartman
maintainerPATCH 718/879 objtool: Fix symbol creation
In reply to Greg Kroah-HartmanFrom: Peter Zijlstra <[email protected]>
commit ead165fa1042247b033afad7be4be9b815d04ade upstream.
Nathan reported objtool failing with the following messages:
warning: objtool: no non-local symbols !?
warning: objtool: gelf_update_symshndx: invalid section index
The problem is due to commit 4abff6d48dbc ("objtool: Fix code relocs vs weak symbols") failing to consider the case where an object would have no non-local symbols.
The problem that commit tries to address is adding a STB_LOCAL symbol to the symbol table in light of the ELF spec's requirement that:
In each symbol table, all symbols with STB_LOCAL binding preced the weak and global symbols. As ``Sections'' above describes, a symbol table section's sh_info section header member holds the symbol table index for the first non-local symbol.
The approach taken is to find this first non-local symbol, move that to the end and then re-use the freed spot to insert a new local symbol and increment sh_info.
Except it never considered the case of object files without global symbols and got a whole bunch of details wrong -- so many in fact that it is a wonder it ever worked :/
Specifically:
- It failed to re-hash the symbol on the new index, so a subsequent find_symbol_by_index() would not find it at the new location and a query for the old location would now return a non-deterministic choice between the old and new symbol.
- It failed to appreciate that the GElf wrappers are not a valid disk format (it works because GElf is basically Elf64 and we only support x86_64 atm.)
- It failed to fully appreciate how horrible the libelf API really is and got the gelf_update_symshndx() call pretty much completely wrong; with the direct consequence that if inserting a second STB_LOCAL symbol would require moving the same STB_GLOBAL symbol again it would completely come unstuck.
Write a new elf_update_symbol() function that wraps all the magic required to update or create a new symbol at a given index.
Specifically, gelf_update_sym*() require an @ndx argument that is relative to the @data argument; this means you have to manually iterate the section data descriptor list and update @ndx.
--- tools/objtool/elf.c | 198 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 129 insertions(+), 69 deletions(-)
tools/objtool/elf.c +129 -69
@@ -374,6 +374,9 @@ static void elf_add_symbol(struct elf *estruct list_head *entry;struct rb_node *pnode; +INIT_LIST_HEAD (&sym->pv_target); + sym->alias = sym; + sym->type =GELF_ST_TYPE (sym->sym.st_info); sym->bind =GELF_ST_BIND (sym->sym.st_info);
@@ -435,8 +438,6 @@ static int read_symbols(struct elf *elf)return -1 ; }memset (sym,0 ,sizeof (*sym)); -INIT_LIST_HEAD (&sym->pv_target); - sym->alias = sym; sym->idx = i;
@@ -600,24 +601,21 @@ static void elf_dirty_reloc_sym(struct e }/* -* Move the first global symbol, as per sh_info, into a new, higher symbol -* index. This fees up the shndx for a new local symbol. +* The libelf API is terrible; gelf_update_sym*() takes a data block relative +* index value, *NOT* the symbol index. As such, iterate the data blocks and +* adjust index until it fits. +* +* If no data block is found, allow adding a new data block provided the index +* is only one past the end. */ -static int elf_move_global_symbol (struct elf *elf,struct section *symtab, -struct section *symtab_shndx) +static int elf_update_symbol (struct elf *elf,struct section *symtab, +struct section *symtab_shndx,struct symbol *sym) { -Elf_Data *data, *shndx_data =NULL ; -Elf32_Word first_non_local; -struct symbol *sym; -Elf_Scn *s; - - first_non_local = symtab->sh.sh_info; - - sym =find_symbol_by_index (elf, first_non_local); -if (!sym) { -WARN ("no non-local symbols !?" ); -return first_non_local; - } +Elf32_Word shndx = sym->sec ? sym->sec->idx :SHN_UNDEF ; +Elf_Data *symtab_data =NULL , *shndx_data =NULL ; +Elf64_Xword entsize = symtab->sh.sh_entsize; +int max_idx, idx = sym->idx; +Elf_Scn *s, *t =NULL ; s =elf_getscn (elf->elf, symtab->idx);if (!s) {
@@ -625,79 +623,124 @@ static int elf_move_global_symbol(structreturn -1 ; } - data =elf_newdata (s); -if (!data) { -WARN_ELF ("elf_newdata" ); -return -1 ; +if (symtab_shndx) { + t =elf_getscn (elf->elf, symtab_shndx->idx); +if (!t) { +WARN_ELF ("elf_getscn" ); +return -1 ; + } } - data->d_buf = &sym->sym; - data->d_size =sizeof (sym->sym); - data->d_align =1 ; - data->d_type =ELF_T_SYM ; +for (;;) { +/* get next data descriptor for the relevant sections */ + symtab_data =elf_getdata (s, symtab_data); +if (t) + shndx_data =elf_getdata (t, shndx_data); + +/* end-of-list */ +if (!symtab_data) { +void *buf; + +if (idx) { +/* we don't do holes in symbol tables */ +WARN ("index out of range" ); +return -1 ; + } - sym->idx = symtab->sh.sh_size /sizeof (sym->sym); -elf_dirty_reloc_sym (elf, sym); +/* if @idx == 0, it's the next contiguous entry, create it */ + symtab_data =elf_newdata (s); +if (t) + shndx_data =elf_newdata (t); + + buf =calloc (1 , entsize); +if (!buf) { +WARN ("malloc" ); +return -1 ; + } - symtab->sh.sh_info +=1 ; - symtab->sh.sh_size += data->d_size; - symtab->changed = true; + symtab_data->d_buf = buf; + symtab_data->d_size = entsize; + symtab_data->d_align =1 ; + symtab_data->d_type =ELF_T_SYM ; + + symtab->sh.sh_size += entsize; + symtab->changed = true; + +if (t) { + shndx_data->d_buf = &sym->sec->idx; + shndx_data->d_size =sizeof (Elf32_Word); + shndx_data->d_align =sizeof (Elf32_Word); + shndx_data->d_type =ELF_T_WORD ; -if (symtab_shndx) { - s =elf_getscn (elf->elf, symtab_shndx->idx); -if (!s) { -WARN_ELF ("elf_getscn" ); + symtab_shndx->sh.sh_size +=sizeof (Elf32_Word); + symtab_shndx->changed = true; + } + +break ; + } + +/* empty blocks should not happen */ +if (!symtab_data->d_size) { +WARN ("zero size data" );return -1 ; } - shndx_data =elf_newdata (s); +/* is this the right block? */ + max_idx = symtab_data->d_size / entsize; +if (idx < max_idx) +break ; + +/* adjust index and try again */ + idx -= max_idx; + } + +/* something went side-ways */ +if (idx <0 ) { +WARN ("negative index" ); +return -1 ; + } + +/* setup extended section index magic and write the symbol */ +if (shndx >=SHN_UNDEF && shndx <SHN_LORESERVE ) { + sym->sym.st_shndx = shndx; +if (!shndx_data) + shndx =0 ; + }else { + sym->sym.st_shndx =SHN_XINDEX ;if (!shndx_data) { -WARN_ELF ("elf_newshndx_data" ); +WARN ("no .symtab_shndx" );return -1 ; } + } - shndx_data->d_buf = &sym->sec->idx; - shndx_data->d_size =sizeof (Elf32_Word); - shndx_data->d_align =4 ; - shndx_data->d_type =ELF_T_WORD ; - - symtab_shndx->sh.sh_size +=4 ; - symtab_shndx->changed = true; +if (!gelf_update_symshndx (symtab_data, shndx_data, idx, &sym->sym, shndx)) { +WARN_ELF ("gelf_update_symshndx" ); +return -1 ; } -return first_non_local; +return 0 ; }static struct symbol *elf_create_section_symbol (struct elf *elf,struct section *sec) {struct section *symtab, *symtab_shndx; -Elf_Data *shndx_data =NULL ; -struct symbol *sym; -Elf32_Word shndx; +Elf32_Word first_non_local, new_idx; +struct symbol *sym, *old; symtab =find_section_by_name (elf,".symtab" );if (symtab) { symtab_shndx =find_section_by_name (elf,".symtab_shndx" ); -if (symtab_shndx) - shndx_data = symtab_shndx->data; }else {WARN ("no .symtab" );return NULL ; } - sym =malloc (sizeof (*sym)); + sym =calloc (1 ,sizeof (*sym));if (!sym) {perror ("malloc" );return NULL ; } -memset (sym,0 ,sizeof (*sym)); - - sym->idx =elf_move_global_symbol (elf, symtab, symtab_shndx); -if (sym->idx <0 ) { -WARN ("elf_move_global_symbol" ); -return NULL ; - } sym->name = sec->name; sym->sec = sec;
@@ -707,24 +750,41 @@ elf_create_section_symbol(struct elf *el// st_other 0 // st_value 0 // st_size 0 - shndx = sec->idx; -if (shndx >=SHN_UNDEF && shndx <SHN_LORESERVE ) { - sym->sym.st_shndx = shndx; -if (!shndx_data) - shndx =0 ; - }else { - sym->sym.st_shndx =SHN_XINDEX ; -if (!shndx_data) { -WARN ("no .symtab_shndx" ); + +/* +* Move the first global symbol, as per sh_info, into a new, higher +* symbol index. This fees up a spot for a new local symbol. +*/ + first_non_local = symtab->sh.sh_info; + new_idx = symtab->sh.sh_size / symtab->sh.sh_entsize; + old =find_symbol_by_index (elf, first_non_local); +if (old) { + old->idx = new_idx; + +hlist_del (&old->hash); +elf_hash_add (symbol, &old->hash, old->idx); + +elf_dirty_reloc_sym (elf, old); + +if (elf_update_symbol (elf, symtab, symtab_shndx, old)) { +WARN ("elf_update_symbol move" );return NULL ; } + + new_idx = first_non_local; } -if (!gelf_update_symshndx (symtab->data, shndx_data, sym->idx, &sym->sym, shndx)) { -WARN_ELF ("gelf_update_symshndx" ); + sym->idx = new_idx; +if (elf_update_symbol (elf, symtab, symtab_shndx, sym)) { +WARN ("elf_update_symbol" );return NULL ; } +/* +* Either way, we added a LOCAL symbol. +*/ + symtab->sh.sh_info +=1 ; +elf_add_symbol (elf, sym);return sym;
Greg Kroah-Hartman
maintainerPATCH 719/879 wifi: mac80211: fix use-after-free in chanctx code
In reply to Greg Kroah-HartmanFrom: Johannes Berg <[email protected]>
commit 2965c4cdf7ad9ce0796fac5e57debb9519ea721e upstream.
In ieee80211_vif_use_reserved_context(), when we have an old context and the new context's replace_state is set to IEEE80211_CHANCTX_REPLACE_NONE, we free the old context in ieee80211_vif_use_reserved_reassign(). Therefore, we cannot check the old_ctx anymore, so we should set it to NULL after this point.
However, since the new_ctx replace state is clearly not IEEE80211_CHANCTX_REPLACES_OTHER, we're not going to do anything else in this function and can just return to avoid accessing the freed old_ctx.
--- net/mac80211/chan.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
net/mac80211/chan.c +2 -5
@@ -1749,12 +1749,9 @@ int ieee80211_vif_use_reserved_context(sif (new_ctx->replace_state ==IEEE80211_CHANCTX_REPLACE_NONE ) {if (old_ctx) - err =ieee80211_vif_use_reserved_reassign (sdata); -else - err =ieee80211_vif_use_reserved_assign (sdata); +return ieee80211_vif_use_reserved_reassign (sdata); -if (err) -return err; +return ieee80211_vif_use_reserved_assign (sdata); }/*
Greg Kroah-Hartman
maintainerPATCH 720/879 iwlwifi: fw: init SAR GEO table only if data is present
In reply to Greg Kroah-HartmanFrom: Johannes Berg <[email protected]>
commit d1f6530c3e373ddd7c76b05646052a27eead14ad upstream.
When no table data was read from ACPI, then filling the data and returning success here will fill zero values, which means transmit power will be limited to 0 dBm. This is clearly not intended.
Return an error from iwl_sar_geo_init() if there's no data to fill into the command structure.
--- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/wireless/intel/iwlwifi/fw/acpi.c +3 -0
@@ -937,6 +937,9 @@ int iwl_sar_geo_init(struct iwl_fw_runti {int i, j; +if (!fwrt->geo_enabled) +return -ENODATA ; +if (!iwl_sar_geo_support (fwrt))return -EOPNOTSUPP ;
Greg Kroah-Hartman
maintainerPATCH 721/879 iwlwifi: mvm: fix assert 1F04 upon reconfig
In reply to Greg Kroah-HartmanFrom: Emmanuel Grumbach <[email protected]>
commit 9d096e3d3061dbf4ee10e2b59fc2c06e05bdb997 upstream.
When we reconfig we must not send the MAC_POWER command that relates to a MAC that was not yet added to the firmware.
Ignore those in the iterator.
--- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/wireless/intel/iwlwifi/mvm/power.c +3 -0
@@ -563,6 +563,9 @@ static void iwl_mvm_power_get_vifs_iterastruct iwl_power_vifs *power_iterator = _data;bool active = mvmvif->phy_ctxt && mvmvif->phy_ctxt->id <NUM_PHY_CTX ; +if (!mvmvif->uploaded) +return ; +switch (ieee80211_vif_type_p2p (vif)) {case NL80211_IFTYPE_P2P_DEVICE :break ;
Greg Kroah-Hartman
maintainerPATCH 722/879 iwlwifi: mei: clear the sap data header before sending
In reply to Greg Kroah-HartmanFrom: Avraham Stern <[email protected]>
commit 55cf10488d7a9fa1b1b473a5e44a80666932e094 upstream.
The SAP data header has some fields that are marked as reserved but are actually in use by CSME. Clear those fields before sending the data to avoid having random values in those fields.
--- drivers/net/wireless/intel/iwlwifi/mei/main.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/wireless/intel/iwlwifi/mei/main.c +1 -0
@@ -493,6 +493,7 @@ void iwl_mei_add_data_to_ring(struct sk_if (cb_tx) {struct iwl_sap_cb_data *cb_hdr =skb_push (skb,sizeof (*cb_hdr)); +memset (cb_hdr,0 ,sizeof (*cb_hdr)); cb_hdr->hdr.type =cpu_to_le16 (SAP_MSG_CB_DATA_PACKET ); cb_hdr->hdr.len =cpu_to_le16 (skb->len -sizeof (cb_hdr->hdr)); cb_hdr->hdr.seq_num =cpu_to_le32 (atomic_inc_return (&mei->sap_seq_no));
Greg Kroah-Hartman
maintainerPATCH 723/879 iwlwifi: mei: fix potential NULL-ptr deref
In reply to Greg Kroah-HartmanFrom: Johannes Berg <[email protected]>
commit 78488a64aea94a3336ee97f345c1496e9bc5ebdf upstream.
If SKB allocation fails, continue rather than using the NULL pointer.
Coverity CID: 1497650
--- drivers/net/wireless/intel/iwlwifi/mei/main.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/wireless/intel/iwlwifi/mei/main.c +2 -0
@@ -1020,6 +1020,8 @@ static void iwl_mei_handle_sap_data(stru/* We need enough room for the WiFi header + SNAP + IV */ skb =netdev_alloc_skb (netdev, len +QOS_HDR_IV_SNAP_LEN ); +if (!skb) +continue ;skb_reserve (skb,QOS_HDR_IV_SNAP_LEN ); ethhdr =skb_push (skb,sizeof (*ethhdr));
Greg Kroah-Hartman
maintainerPATCH 724/879 ipmi:ipmb: Fix refcount leak in ipmi_ipmb_probe
In reply to Greg Kroah-HartmanFrom: Miaoqian Lin <[email protected]>
commit a508e33956b538e034ed5df619a73ec7c15bda72 upstream.
of_parse_phandle() returns a node pointer with refcount incremented, we should use of_node_put() on it when done. Add missing of_node_put() to avoid refcount leak.
Message-Id: <[email protected]>
--- drivers/char/ipmi/ipmi_ipmb.c | 1 + 1 file changed, 1 insertion(+)
drivers/char/ipmi/ipmi_ipmb.c +1 -0
@@ -476,6 +476,7 @@ static int ipmi_ipmb_probe(struct i2c_cl slave_np =of_parse_phandle (dev->of_node,"slave-dev" ,0 );if (slave_np) { slave_adap =of_get_i2c_adapter_by_node (slave_np); +of_node_put (slave_np);if (!slave_adap) {dev_notice (&client->dev,"Could not find slave adapter\n" );
Greg Kroah-Hartman
maintainerPATCH 725/879 fs-writeback: writeback_sb_inodes:Recalculate wrote according skipped pages
In reply to Greg Kroah-HartmanFrom: Zhihao Cheng <[email protected]>
commit 68f4c6eba70df70a720188bce95c85570ddfcc87 upstream.
Commit 505a666ee3fc ("writeback: plug writeback in wb_writeback() and writeback_inodes_wb()") has us holding a plug during wb_writeback, which may cause a potential ABBA dead lock:
wb_writeback fat_file_fsyncblk_start_plug(&plug)
for (;;) {
iter i-1: some reqs have been added into plug->mq_list // LOCK A iter i:
progress = __writeback_inodes_wb(wb, work)
. writeback_sb_inodes // fat's bdev
. __writeback_single_inode
. . generic_writepages
. . __block_write_full_page
. . . . __generic_file_fsync
. . . . sync_inode_metadata
. . . . writeback_single_inode
. . . . __writeback_single_inode
. . . . fat_write_inode
. . . . __fat_write_inode
. . . . sync_dirty_buffer // fat's bdev
. . . . lock_buffer(bh) // LOCK B
. . . . submit_bh
. . . . blk_mq_get_tag // LOCK A
. . . trylock_buffer(bh) // LOCK B
. . . redirty_page_for_writepage
. . . wbc->pages_skipped++
. . --wbc->nr_to_write
. wrote += write_chunk - wbc.nr_to_write // wrote > 0
. requeue_inode
. redirty_tail_locked
if (progress) // progress > 0
continue;
iter i+1:
queue_io
// similar process with iter i, infinite for-loop !
}blk_finish_plug(&plug) // flush plug won't be called
Above process triggers a hungtask like:
[ 399.044861] INFO: task bb:2607 blocked for more than 30 seconds. [ 399.046824] Not tainted 5.18.0-rc1-00005-gefae4d9eb6a2-dirty [ 399.051539] task:bb state:D stack: 0 pid: 2607 ppid: 2426 flags:0x00004000 [ 399.051556] Call Trace: [ 399.051570] __schedule+0x480/0x1050 [ 399.051592] schedule+0x92/0x1a0 [ 399.051602] io_schedule+0x22/0x50 [ 399.051613] blk_mq_get_tag+0x1d3/0x3c0 [ 399.051640] __blk_mq_alloc_requests+0x21d/0x3f0 [ 399.051657] blk_mq_submit_bio+0x68d/0xca0 [ 399.051674] __submit_bio+0x1b5/0x2d0 [ 399.051708] submit_bio_noacct+0x34e/0x720 [ 399.051718] submit_bio+0x3b/0x150 [ 399.051725] submit_bh_wbc+0x161/0x230 [ 399.051734] __sync_dirty_buffer+0xd1/0x420 [ 399.051744] sync_dirty_buffer+0x17/0x20 [ 399.051750] __fat_write_inode+0x289/0x310 [ 399.051766] fat_write_inode+0x2a/0xa0 [ 399.051783] __writeback_single_inode+0x53c/0x6f0 [ 399.051795] writeback_single_inode+0x145/0x200 [ 399.051803] sync_inode_metadata+0x45/0x70 [ 399.051856] __generic_file_fsync+0xa3/0x150 [ 399.051880] fat_file_fsync+0x1d/0x80 [ 399.051895] vfs_fsync_range+0x40/0xb0 [ 399.051929] __x64_sys_fsync+0x18/0x30
In my test, 'need_resched()' (which is imported by 590dca3a71 "fs-writeback:
unplug before cond_resched in writeback_sb_inodes") in function 'writeback_sb_inodes()' seldom comes true, unless cond_resched() is deleted from write_cache_pages().
Fix it by correcting wrote number according number of skipped pages in writeback_sb_inodes().
Goto Link to find a reproducer.
--- fs/fs-writeback.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
fs/fs-writeback.c +8 -5
@@ -1779,11 +1779,12 @@ static long writeback_sb_inodes(struct s };unsigned long start_time = jiffies;long write_chunk; -long wrote =0 ;/* count both pages and inodes */ +long total_wrote =0 ;/* count both pages and inodes */ while (!list_empty (&wb->b_io)) {struct inode *inode =wb_inode (wb->b_io.prev);struct bdi_writeback *tmp_wb; +long wrote;if (inode->i_sb != sb) {if (work->sb) {
@@ -1859,7 +1860,9 @@ static long writeback_sb_inodes(struct swbc_detach_inode (&wbc); work->nr_pages -= write_chunk - wbc.nr_to_write; - wrote += write_chunk - wbc.nr_to_write; + wrote = write_chunk - wbc.nr_to_write - wbc.pages_skipped; + wrote = wrote <0 ?0 : wrote; + total_wrote += wrote;if (need_resched ()) {/*
@@ -1881,7 +1884,7 @@ static long writeback_sb_inodes(struct s tmp_wb =inode_to_wb_and_lock_list (inode);spin_lock (&inode->i_lock);if (!(inode->i_state &I_DIRTY_ALL )) - wrote++; + total_wrote++;requeue_inode (inode, tmp_wb, &wbc);inode_sync_complete (inode);spin_unlock (&inode->i_lock);
@@ -1895,14 +1898,14 @@ static long writeback_sb_inodes(struct s* bail out to wb_writeback() often enough to check * background threshold and other termination conditions. */ -if (wrote) { +if (total_wrote) {if (time_is_before_jiffies (start_time +HZ /10UL ))break ;if (work->nr_pages <=0 )break ; } } -return wrote; +return total_wrote; } static long __writeback_inodes_wb(struct bdi_writeback *wb,
Greg Kroah-Hartman
maintainerPATCH 726/879 efi: Do not import certificates from UEFI Secure Boot for T2 Macs
In reply to Greg Kroah-HartmanFrom: Aditya Garg <[email protected]>
commit 155ca952c7ca19aa32ecfb7373a32bbc2e1ec6eb upstream.
On Apple T2 Macs, when Linux attempts to read the db and dbx efi variables at early boot to load UEFI Secure Boot certificates, a page fault occurs in Apple firmware code and EFI runtime services are disabled with the following logs:
[Firmware Bug]: Page fault caused by firmware at PA: 0xffffb1edc0068000
WARNING: CPU: 3 PID: 104 at arch/x86/platform/efi/quirks.c:735 efi_crash_gracefully_on_page_fault+0x50/0xf0 (Removed some logs from here) Call Trace: <TASK> page_fault_oops+0x4f/0x2c0 ? search_bpf_extables+0x6b/0x80 ? search_module_extables+0x50/0x80 ? search_exception_tables+0x5b/0x60 kernelmode_fixup_or_oops+0x9e/0x110 __bad_area_nosemaphore+0x155/0x190 bad_area_nosemaphore+0x16/0x20 do_kern_addr_fault+0x8c/0xa0 exc_page_fault+0xd8/0x180 asm_exc_page_fault+0x1e/0x30 (Removed some logs from here) ? __efi_call+0x28/0x30 ? switch_mm+0x20/0x30 ? efi_call_rts+0x19a/0x8e0 ? process_one_work+0x222/0x3f0 ? worker_thread+0x4a/0x3d0 ? kthread+0x17a/0x1a0 ? process_one_work+0x3f0/0x3f0 ? set_kthread_struct+0x40/0x40 ? ret_from_fork+0x22/0x30 </TASK> ---[ end trace 1f82023595a5927f ]---
efi: Froze efi_rts_wq and disabled EFI Runtime Services
integrity: Couldn't get size: 0x8000000000000015
integrity: MODSIGN: Couldn't get UEFI db list
efi: EFI Runtime Services are disabled!
integrity: Couldn't get size: 0x8000000000000015
integrity: Couldn't get UEFI dbx list
integrity: Couldn't get size: 0x8000000000000015
integrity: Couldn't get mokx list
integrity: Couldn't get size: 0x80000000
So we avoid reading these UEFI variables and thus prevent the crash.
--- security/integrity/platform_certs/keyring_handler.h | 8 ++++ security/integrity/platform_certs/load_uefi.c | 33 ++++++++++++++++++++ 2 files changed, 41 insertions(+)
security/integrity/platform_certs/keyring_handler.h +8 -0
@@ -35,3 +35,11 @@ efi_element_handler_t get_handler_for_moefi_element_handler_t get_handler_for_dbx (const efi_guid_t *sig_type);#endif + +#ifndef UEFI_QUIRK_SKIP_CERT +#define UEFI_QUIRK_SKIP_CERT (vendor, product) \ + .matches = { \ + DMI_MATCH(DMI_BOARD_VENDOR, vendor), \ + DMI_MATCH(DMI_PRODUCT_NAME, product), \ + }, +#endif
security/integrity/platform_certs/load_uefi.c +33 -0
@@ -3,6 +3,7 @@#include <linux/kernel.h> #include <linux/sched.h> #include <linux/cred.h> +#include <linux/dmi.h> #include <linux/err.h> #include <linux/efi.h> #include <linux/slab.h>
@@ -13,6 +14,31 @@#include "keyring_handler.h" /* +* On T2 Macs reading the db and dbx efi variables to load UEFI Secure Boot +* certificates causes occurrence of a page fault in Apple's firmware and +* a crash disabling EFI runtime services. The following quirk skips reading +* these variables. +*/ +static const struct dmi_system_id uefi_skip_cert[] = { + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro15,1" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro15,2" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro15,3" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro15,4" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro16,1" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro16,2" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro16,3" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookPro16,4" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookAir8,1" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookAir8,2" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacBookAir9,1" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacMini8,1" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"MacPro7,1" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"iMac20,1" ) }, + {UEFI_QUIRK_SKIP_CERT ("Apple Inc." ,"iMac20,2" ) }, + { } +}; + +/* * Look to see if a UEFI variable called MokIgnoreDB exists and return true if * it does. *
@@ -138,6 +164,13 @@ static int __init load_uefi_certs(void)unsigned long dbsize =0 , dbxsize =0 , mokxsize =0 ;efi_status_t status;int rc =0 ; +const struct dmi_system_id *dmi_id; + + dmi_id =dmi_first_match (uefi_skip_cert); +if (dmi_id) { +pr_err ("Reading UEFI Secure Boot Certs is not supported on T2 Macs.\n" ); +return false; + }if (!efi_rt_services_supported (EFI_RT_SUPPORTED_GET_VARIABLE ))return false;
Greg Kroah-Hartman
maintainerPATCH 727/879 bfq: Avoid false marking of bic as stably merged
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 70456e5210f40ffdb8f6d905acfdcec5bd5fad9e upstream.
bfq_setup_cooperator() can mark bic as stably merged even though it decides to not merge its bfqqs (when bfq_setup_merge() returns NULL). Make sure to mark bic as stably merged only if we are really going to merge bfqqs.
--- block/bfq-iosched.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
block/bfq-iosched.c +6 -3
@@ -2899,9 +2899,12 @@ bfq_setup_cooperator(struct bfq_data *bfstruct bfq_queue *new_bfqq =bfq_setup_merge (bfqq, stable_merge_bfqq); - bic->stably_merged = true; -if (new_bfqq && new_bfqq->bic) - new_bfqq->bic->stably_merged = true; +if (new_bfqq) { + bic->stably_merged = true; +if (new_bfqq->bic) + new_bfqq->bic->stably_merged = + true; + }return new_bfqq; }else return NULL ;
Greg Kroah-Hartman
maintainerPATCH 728/879 bfq: Avoid merging queues with different parents
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit c1cee4ab36acef271be9101590756ed0c0c374d9 upstream.
It can happen that the parent of a bfqq changes between the moment we decide two queues are worth to merge (and set bic->stable_merge_bfqq) and the moment bfq_setup_merge() is called. This can happen e.g. because the process submitted IO for a different cgroup and thus bfqq got reparented. It can even happen that the bfqq we are merging with has parent cgroup that is already offline and going to be destroyed in which case the merge can lead to use-after-free issues such as:
BUG: KASAN: use-after-free in __bfq_deactivate_entity+0x9cb/0xa50 Read of size 8 at addr ffff88800693c0c0 by task runc:[2:INIT]/10544 CPU: 0 PID: 10544 Comm: runc:[2:INIT] Tainted: G E 5.15.2-0.g5fb85fd-default #1 openSUSE Tumbleweed (unreleased) f1f3b891c72369aebecd2e43e4641a6358867c70 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a-rebuilt.opensuse.org 04/01/2014 Call Trace: <IRQ> dump_stack_lvl+0x46/0x5a print_address_description.constprop.0+0x1f/0x140 ? __bfq_deactivate_entity+0x9cb/0xa50 kasan_report.cold+0x7f/0x11b ? __bfq_deactivate_entity+0x9cb/0xa50 __bfq_deactivate_entity+0x9cb/0xa50 ? update_curr+0x32f/0x5d0 bfq_deactivate_entity+0xa0/0x1d0 bfq_del_bfqq_busy+0x28a/0x420 ? resched_curr+0x116/0x1d0 ? bfq_requeue_bfqq+0x70/0x70 ? check_preempt_wakeup+0x52b/0xbc0 __bfq_bfqq_expire+0x1a2/0x270 bfq_bfqq_expire+0xd16/0x2160 ? try_to_wake_up+0x4ee/0x1260 ? bfq_end_wr_async_queues+0xe0/0xe0 ? _raw_write_unlock_bh+0x60/0x60 ? _raw_spin_lock_irq+0x81/0xe0 bfq_idle_slice_timer+0x109/0x280 ? bfq_dispatch_request+0x4870/0x4870 __hrtimer_run_queues+0x37d/0x700 ? enqueue_hrtimer+0x1b0/0x1b0 ? kvm_clock_get_cycles+0xd/0x10 ? ktime_get_update_offsets_now+0x6f/0x280 hrtimer_interrupt+0x2c8/0x740
Fix the problem by checking that the parent of the two bfqqs we are merging in bfq_setup_merge() is the same.
--- block/bfq-iosched.c | 8 ++++++++ 1 file changed, 8 insertions(+)
block/bfq-iosched.c +8 -0
@@ -2762,6 +2762,14 @@ bfq_setup_merge(struct bfq_queue *bfqq,if (process_refs ==0 || new_process_refs ==0 )return NULL ; +/* +* Make sure merged queues belong to the same parent. Parents could +* have changed since the time we decided the two queues are suitable +* for merging. +*/ +if (new_bfqq->entity.parent != bfqq->entity.parent) +return NULL ; +bfq_log_bfqq (bfqq->bfqd, bfqq,"scheduling merge with queue %d" , new_bfqq->pid);
Greg Kroah-Hartman
maintainerPATCH 729/879 bfq: Split shared queues on move between cgroups
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 3bc5e683c67d94bd839a1da2e796c15847b51b69 upstream.
When bfqq is shared by multiple processes it can happen that one of the processes gets moved to a different cgroup (or just starts submitting IO for different cgroup). In case that happens we need to split the merged bfqq as otherwise we will have IO for multiple cgroups in one bfqq and we will just account IO time to wrong entities etc.
Similarly if the bfqq is scheduled to merge with another bfqq but the merge didn't happen yet, cancel the merge as it need not be valid anymore.
--- block/bfq-cgroup.c | 36 +++++++++++++++++++++++++++++++++--- block/bfq-iosched.c | 2 +- block/bfq-iosched.h | 1 + 3 files changed, 35 insertions(+), 4 deletions(-)
block/bfq-cgroup.c +33 -3
@@ -743,9 +743,39 @@ static struct bfq_group *__bfq_bic_chang }if (sync_bfqq) { - entity = &sync_bfqq->entity; -if (entity->sched_data != &bfqg->sched_data) -bfq_bfqq_move (bfqd, sync_bfqq, bfqg); +if (!sync_bfqq->new_bfqq && !bfq_bfqq_coop (sync_bfqq)) { +/* We are the only user of this bfqq, just move it */ +if (sync_bfqq->entity.sched_data != &bfqg->sched_data) +bfq_bfqq_move (bfqd, sync_bfqq, bfqg); + }else { +struct bfq_queue *bfqq; + +/* +* The queue was merged to a different queue. Check +* that the merge chain still belongs to the same +* cgroup. +*/ +for (bfqq = sync_bfqq; bfqq; bfqq = bfqq->new_bfqq) +if (bfqq->entity.sched_data != + &bfqg->sched_data) +break ; +if (bfqq) { +/* +* Some queue changed cgroup so the merge is +* not valid anymore. We cannot easily just +* cancel the merge (by clearing new_bfqq) as +* there may be other processes using this +* queue and holding refs to all queues below +* sync_bfqq->new_bfqq. Similarly if the merge +* already happened, we need to detach from +* bfqq now so that we cannot merge bio to a +* request from the old cgroup. +*/ +bfq_put_cooperator (sync_bfqq); +bfq_release_process_ref (bfqd, sync_bfqq); +bic_set_bfqq (bic,NULL ,1 ); + } + } }return bfqg;
block/bfq-iosched.c +1 -1
@@ -5319,7 +5319,7 @@ static void bfq_put_stable_ref(struct bfbfq_put_queue (bfqq); } -static void bfq_put_cooperator (struct bfq_queue *bfqq) +void bfq_put_cooperator (struct bfq_queue *bfqq) {struct bfq_queue *__bfqq, *next;
block/bfq-iosched.h +1 -0
@@ -980,6 +980,7 @@ void bfq_weights_tree_remove(struct bfq_void bfq_bfqq_expire (struct bfq_data *bfqd,struct bfq_queue *bfqq,bool compensate,enum bfqq_expiration reason);void bfq_put_queue (struct bfq_queue *bfqq); +void bfq_put_cooperator (struct bfq_queue *bfqq);void bfq_end_wr_async_queues (struct bfq_data *bfqd,struct bfq_group *bfqg);void bfq_release_process_ref (struct bfq_data *bfqd,struct bfq_queue *bfqq);void bfq_schedule_dispatch (struct bfq_data *bfqd);
Greg Kroah-Hartman
maintainerPATCH 730/879 bfq: Update cgroup information before merging bio
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit ea591cd4eb270393810e7be01feb8fde6a34fbbe upstream.
When the process is migrated to a different cgroup (or in case of writeback just starts submitting bios associated with a different cgroup) bfq_merge_bio() can operate with stale cgroup information in bic. Thus the bio can be merged to a request from a different cgroup or it can result in merging of bfqqs for different cgroups or bfqqs of already dead cgroups and causing possible use-after-free issues. Fix the problem by updating cgroup information in bfq_merge_bio().
--- block/bfq-iosched.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
block/bfq-iosched.c +9 -2
@@ -2461,10 +2461,17 @@ static bool bfq_bio_merge(struct requestspin_lock_irq (&bfqd->lock); -if (bic) +if (bic) { +/* +* Make sure cgroup info is uptodate for current process before +* considering the merge. +*/ +bfq_bic_update_cgroup (bic, bio); + bfqd->bio_bfqq =bic_to_bfqq (bic,op_is_sync (bio->bi_opf)); -else + }else { bfqd->bio_bfqq =NULL ; + } bfqd->bio_bic = bic; ret =blk_mq_sched_try_merge (q, bio, nr_segs, &free);
Greg Kroah-Hartman
maintainerPATCH 731/879 bfq: Drop pointless unlock-lock pair
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit fc84e1f941b91221092da5b3102ec82da24c5673 upstream.
In bfq_insert_request() we unlock bfqd->lock only to call trace_block_rq_insert() and then lock bfqd->lock again. This is really pointless since tracing is disabled if we really care about performance and even if the tracepoint is enabled, it is a quick call.
--- block/bfq-iosched.c | 3 --- 1 file changed, 3 deletions(-)
block/bfq-iosched.c +0 -3
@@ -6154,11 +6154,8 @@ static void bfq_insert_request(struct blreturn ; } -spin_unlock_irq (&bfqd->lock); -trace_block_rq_insert (rq); -spin_lock_irq (&bfqd->lock); bfqq =bfq_init_rq (rq);if (!bfqq || at_head) {if (at_head)
Greg Kroah-Hartman
maintainerPATCH 732/879 bfq: Remove pointless bfq_init_rq() calls
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 5f550ede5edf846ecc0067be1ba80514e6fe7f8e upstream.
We call bfq_init_rq() from request merging functions where requests we get should have already gone through bfq_init_rq() during insert and anyway we want to do anything only if the request is already tracked by BFQ. So replace calls to bfq_init_rq() with RQ_BFQQ() instead to simply skip requests untracked by BFQ. We move bfq_init_rq() call in bfq_insert_request() a bit earlier to cover request merging and thus can transfer FIFO position in case of a merge.
--- block/bfq-iosched.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
block/bfq-iosched.c +6 -6
@@ -2501,8 +2501,6 @@ static int bfq_request_merge(struct requreturn ELEVATOR_NO_MERGE ; } -static struct bfq_queue *bfq_init_rq (struct request *rq); -static void bfq_request_merged (struct request_queue *q,struct request *req,enum elv_merge type) {
@@ -2511,7 +2509,7 @@ static void bfq_request_merged(struct re blk_rq_pos(req) < blk_rq_pos(container_of(rb_prev(&req->rb_node), struct request, rb_node))) { -struct bfq_queue *bfqq =bfq_init_rq (req); +struct bfq_queue *bfqq =RQ_BFQQ (req);struct bfq_data *bfqd;struct request *prev, *next_rq;
@@ -2563,8 +2561,8 @@ static void bfq_request_merged(struct restatic void bfq_requests_merged (struct request_queue *q,struct request *rq,struct request *next) { -struct bfq_queue *bfqq =bfq_init_rq (rq), - *next_bfqq =bfq_init_rq (next); +struct bfq_queue *bfqq =RQ_BFQQ (rq), + *next_bfqq =RQ_BFQQ (next);if (!bfqq) goto remove;
@@ -6133,6 +6131,8 @@ static inline void bfq_update_insert_sta unsigned int cmd_flags) {}#endif /* CONFIG_BFQ_CGROUP_DEBUG */ +static struct bfq_queue *bfq_init_rq (struct request *rq); +static void bfq_insert_request (struct blk_mq_hw_ctx *hctx,struct request *rq,bool at_head) {
@@ -6148,6 +6148,7 @@ static void bfq_insert_request(struct blbfqg_stats_update_legacy_io (q, rq);#endif spin_lock_irq (&bfqd->lock); + bfqq =bfq_init_rq (rq);if (blk_mq_sched_try_insert_merge (q, rq, &free)) {spin_unlock_irq (&bfqd->lock);blk_mq_free_requests (&free);
@@ -6156,7 +6157,6 @@ static void bfq_insert_request(struct bltrace_block_rq_insert (rq); - bfqq =bfq_init_rq (rq);if (!bfqq || at_head) {if (at_head)list_add (&rq->queuelist, &bfqd->dispatch);
Greg Kroah-Hartman
maintainerPATCH 733/879 bfq: Track whether bfq_group is still online
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 09f871868080c33992cd6a9b72a5ca49582578fa upstream.
Track whether bfq_group is still online. We cannot rely on blkcg_gq->online because that gets cleared only after all policies are offlined and we need something that gets updated already under bfqd->lock when we are cleaning up our bfq_group to be able to guarantee that when we see online bfq_group, it will stay online while we are holding bfqd->lock lock.
--- block/bfq-cgroup.c | 3 ++- block/bfq-iosched.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-)
block/bfq-cgroup.c +2 -1
@@ -557,6 +557,7 @@ static void bfq_pd_init(struct blkg_poli*/ bfqg->bfqd = bfqd; bfqg->active_entities =0 ; + bfqg->online = true; bfqg->rq_pos_tree =RB_ROOT ; }
@@ -603,7 +604,6 @@ struct bfq_group *bfq_find_set_group(strstruct bfq_entity *entity; bfqg =bfq_lookup_bfqg (bfqd, blkcg); -if (unlikely (!bfqg))return NULL ;
@@ -979,6 +979,7 @@ static void bfq_pd_offline(struct blkg_p put_async_queues:bfq_put_async_queues (bfqd, bfqg); + bfqg->online = false;spin_unlock_irqrestore (&bfqd->lock, flags);/*
block/bfq-iosched.h +2 -0
@@ -929,6 +929,8 @@ struct bfq_group {/* reference counter (see comments in bfq_bic_update_cgroup) */ int ref; +/* Is bfq_group still online? */ +bool online;struct bfq_entity entity;struct bfq_sched_data sched_data;
Greg Kroah-Hartman
maintainerPATCH 734/879 bfq: Get rid of __bio_blkcg() usage
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 4e54a2493e582361adc3bfbf06c7d50d19d18837 upstream.
BFQ usage of __bio_blkcg() is a relict from the past. Furthermore if bio would not be associated with any blkcg, the usage of __bio_blkcg() in BFQ is prone to races with the task being migrated between cgroups as __bio_blkcg() calls at different places could return different blkcgs.
Convert BFQ to the new situation where bio->bi_blkg is initialized in bio_set_dev() and thus practically always valid. This allows us to save blkcg_gq lookup and noticeably simplify the code.
--- block/bfq-cgroup.c | 63 ++++++++++++++++++---------------------------------- block/bfq-iosched.c | 11 --------- block/bfq-iosched.h | 3 -- 3 files changed, 25 insertions(+), 52 deletions(-)
block/bfq-cgroup.c +23 -40
@@ -586,27 +586,11 @@ static void bfq_group_set_parent(struct entity->sched_data = &parent->sched_data; } -static struct bfq_group *bfq_lookup_bfqg (struct bfq_data *bfqd, -struct blkcg *blkcg) +static void bfq_link_bfqg (struct bfq_data *bfqd,struct bfq_group *bfqg) { -struct blkcg_gq *blkg; - - blkg =blkg_lookup (blkcg, bfqd->queue); -if (likely (blkg)) -return blkg_to_bfqg (blkg); -return NULL ; -} - -struct bfq_group *bfq_find_set_group (struct bfq_data *bfqd, -struct blkcg *blkcg) -{ -struct bfq_group *bfqg, *parent; +struct bfq_group *parent;struct bfq_entity *entity; - bfqg =bfq_lookup_bfqg (bfqd, blkcg); -if (unlikely (!bfqg)) -return NULL ; -/* * Update chain of bfq_groups as we might be handling a leaf group * which, along with some of its relatives, has not been hooked yet
@@ -623,8 +607,15 @@ struct bfq_group *bfq_find_set_group(strbfq_group_set_parent (curr_bfqg, parent); } } +} -return bfqg; +struct bfq_group *bfq_bio_bfqg (struct bfq_data *bfqd,struct bio *bio) +{ +struct blkcg_gq *blkg = bio->bi_blkg; + +if (!blkg) +return bfqd->root_group; +return blkg_to_bfqg (blkg); }/**
@@ -714,25 +705,15 @@ void bfq_bfqq_move(struct bfq_data *bfqd* Move bic to blkcg, assuming that bfqd->lock is held; which makes * sure that the reference to cgroup is valid across the call (see * comments in bfq_bic_update_cgroup on this issue) -* -* NOTE: an alternative approach might have been to store the current -* cgroup in bfqq and getting a reference to it, reducing the lookup -* time here, at the price of slightly more complex code. */ -static struct bfq_group *__bfq_bic_change_cgroup (struct bfq_data *bfqd, -struct bfq_io_cq *bic, -struct blkcg *blkcg) +static void *__bfq_bic_change_cgroup (struct bfq_data *bfqd, +struct bfq_io_cq *bic, +struct bfq_group *bfqg) {struct bfq_queue *async_bfqq =bic_to_bfqq (bic,0 );struct bfq_queue *sync_bfqq =bic_to_bfqq (bic,1 ); -struct bfq_group *bfqg;struct bfq_entity *entity; - bfqg =bfq_find_set_group (bfqd, blkcg); - -if (unlikely (!bfqg)) - bfqg = bfqd->root_group; -if (async_bfqq) { entity = &async_bfqq->entity;
@@ -784,20 +765,24 @@ static struct bfq_group *__bfq_bic_changvoid bfq_bic_update_cgroup (struct bfq_io_cq *bic,struct bio *bio) {struct bfq_data *bfqd =bic_to_bfqd (bic); -struct bfq_group *bfqg =NULL ; +struct bfq_group *bfqg =bfq_bio_bfqg (bfqd, bio);uint64_t serial_nr; -rcu_read_lock (); - serial_nr =__bio_blkcg (bio)->css.serial_nr; + serial_nr =bfqg_to_blkg (bfqg)->blkcg->css.serial_nr;/* * Check whether blkcg has changed. The condition may trigger * spuriously on a newly created cic but there's no harm. */ if (unlikely (!bfqd) ||likely (bic->blkcg_serial_nr == serial_nr)) - goto out; +return ; - bfqg =__bfq_bic_change_cgroup (bfqd, bic,__bio_blkcg (bio)); +/* +* New cgroup for this process. Make sure it is linked to bfq internal +* cgroup hierarchy. +*/ +bfq_link_bfqg (bfqd, bfqg); +__bfq_bic_change_cgroup (bfqd, bic, bfqg);/* * Update blkg_path for bfq_log_* functions. We cache this * path, and update it here, for the following
@@ -850,8 +835,6 @@ void bfq_bic_update_cgroup(struct bfq_io*/ blkg_path (bfqg_to_blkg (bfqg), bfqg->blkg_path,sizeof (bfqg->blkg_path)); bic->blkcg_serial_nr = serial_nr; -out: -rcu_read_unlock (); }/**
@@ -1469,7 +1452,7 @@ void bfq_end_wr_async(struct bfq_data *bbfq_end_wr_async_queues (bfqd, bfqd->root_group); } -struct bfq_group *bfq_find_set_group (struct bfq_data *bfqd,struct blkcg *blkcg) +struct bfq_group *bfq_bio_bfqg (struct bfq_data *bfqd,struct bio *bio) {return bfqd->root_group; }
block/bfq-iosched.c +1 -10
@@ -5730,14 +5730,7 @@ static struct bfq_queue *bfq_get_queue(sstruct bfq_queue *bfqq;struct bfq_group *bfqg; -rcu_read_lock (); - - bfqg =bfq_find_set_group (bfqd,__bio_blkcg (bio)); -if (!bfqg) { - bfqq = &bfqd->oom_bfqq; - goto out; - } - + bfqg =bfq_bio_bfqg (bfqd, bio);if (!is_sync) { async_bfqq =bfq_async_queue_prio (bfqd, bfqg, ioprio_class, ioprio);
@@ -5783,8 +5776,6 @@ out:if (bfqq != &bfqd->oom_bfqq && is_sync && !respawn) bfqq =bfq_do_or_sched_stable_merge (bfqd, bfqq, bic); - -rcu_read_unlock ();return bfqq; }
block/bfq-iosched.h +1 -2
@@ -1010,8 +1010,7 @@ void bfq_bfqq_move(struct bfq_data *bfqdvoid bfq_init_entity (struct bfq_entity *entity,struct bfq_group *bfqg);void bfq_bic_update_cgroup (struct bfq_io_cq *bic,struct bio *bio);void bfq_end_wr_async (struct bfq_data *bfqd); -struct bfq_group *bfq_find_set_group (struct bfq_data *bfqd, -struct blkcg *blkcg); +struct bfq_group *bfq_bio_bfqg (struct bfq_data *bfqd,struct bio *bio);struct blkcg_gq *bfqg_to_blkg (struct bfq_group *bfqg);struct bfq_group *bfqq_group (struct bfq_queue *bfqq);struct bfq_group *bfq_create_group_hierarchy (struct bfq_data *bfqd,int node);
Greg Kroah-Hartman
maintainerPATCH 735/879 bfq: Make sure bfqg for which we are queueing requests is online
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 075a53b78b815301f8d3dd1ee2cd99554e34f0dd upstream.
Bios queued into BFQ IO scheduler can be associated with a cgroup that was already offlined. This may then cause insertion of this bfq_group into a service tree. But this bfq_group will get freed as soon as last bio associated with it is completed leading to use after free issues for service tree users. Fix the problem by making sure we always operate on online bfq_group. If the bfq_group associated with the bio is not online, we pick the first online parent.
--- block/bfq-cgroup.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
block/bfq-cgroup.c +12 -3
@@ -612,10 +612,19 @@ static void bfq_link_bfqg(struct bfq_datstruct bfq_group *bfq_bio_bfqg (struct bfq_data *bfqd,struct bio *bio) {struct blkcg_gq *blkg = bio->bi_blkg; +struct bfq_group *bfqg; -if (!blkg) -return bfqd->root_group; -return blkg_to_bfqg (blkg); +while (blkg) { + bfqg =blkg_to_bfqg (blkg); +if (bfqg->online) { +bio_associate_blkg_from_css (bio, &blkg->blkcg->css); +return bfqg; + } + blkg = blkg->parent; + } +bio_associate_blkg_from_css (bio, + &bfqg_to_blkg (bfqd->root_group)->blkcg->css); +return bfqd->root_group; }/**
Greg Kroah-Hartman
maintainerPATCH 736/879 ext4: mark group as trimmed only if it was fully scanned
In reply to Greg Kroah-HartmanFrom: Dmitry Monakhov <[email protected]>
commit d63c00ea435a5352f486c259665a4ced60399421 upstream.
Otherwise nonaligned fstrim calls will works inconveniently for iterative scanners, for example:
// trim [0,16MB] for group-1, but mark full group as trimmed
fstrim -o $((1024*1024*128)) -l $((1024*1024*16)) ./m
// handle [16MB,16MB] for group-1, do nothing because group already has the flag. fstrim -o $((1024*1024*144)) -l $((1024*1024*16)) ./m
[ Update function documentation for ext4_trim_all_free -- TYT ]
--- fs/ext4/mballoc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
fs/ext4/mballoc.c +12 -6
@@ -6398,6 +6398,7 @@ __releases(ext4_group_lock_ptr(sb, e4b->* @start: first group block to examine * @max: last group block to examine * @minblocks: minimum extent block count +* @set_trimmed: set the trimmed flag if at least one block is trimmed * * ext4_trim_all_free walks through group's block bitmap searching for free * extents. When the free extent is found, mark it as used in group buddy
@@ -6407,7 +6408,7 @@ __releases(ext4_group_lock_ptr(sb, e4b->static ext4_grpblk_t ext4_trim_all_free (struct super_block *sb,ext4_group_t group,ext4_grpblk_t start,ext4_grpblk_t max, -ext4_grpblk_t minblocks) +ext4_grpblk_t minblocks,bool set_trimmed) {struct ext4_buddy e4b;int ret;
@@ -6426,7 +6427,7 @@ ext4_trim_all_free(struct super_block *sif (!EXT4_MB_GRP_WAS_TRIMMED (e4b.bd_info) || minblocks <EXT4_SB (sb)->s_last_trim_minblks) { ret =ext4_try_to_trim_range (sb, &e4b, start, max, minblocks); -if (ret >=0 ) +if (ret >=0 && set_trimmed)EXT4_MB_GRP_SET_TRIMMED (e4b.bd_info); }else { ret =0 ;
@@ -6463,6 +6464,7 @@ int ext4_trim_fs(struct super_block *sb,ext4_fsblk_t first_data_blk =le32_to_cpu (EXT4_SB (sb)->s_es->s_first_data_block);ext4_fsblk_t max_blks =ext4_blocks_count (EXT4_SB (sb)->s_es); +bool whole_group, eof = false;int ret =0 ; start = range->start >> sb->s_blocksize_bits;
@@ -6481,8 +6483,10 @@ int ext4_trim_fs(struct super_block *sb,if (minlen >EXT4_CLUSTERS_PER_GROUP (sb)) goto out; } -if (end >= max_blks) +if (end >= max_blks -1 ) { end = max_blks -1 ; + eof = true; + }if (end <= first_data_blk) goto out;if (start < first_data_blk)
@@ -6496,6 +6500,7 @@ int ext4_trim_fs(struct super_block *sb,/* end now represents the last cluster to discard in this group */ end =EXT4_CLUSTERS_PER_GROUP (sb) -1 ; + whole_group = true;for (group = first_group; group <= last_group; group++) { grp =ext4_get_group_info (sb, group);
@@ -6512,12 +6517,13 @@ int ext4_trim_fs(struct super_block *sb,* change it for the last group, note that last_cluster is * already computed earlier by ext4_get_group_no_and_offset() */ -if (group == last_group) +if (group == last_group) { end = last_cluster; - + whole_group = eof ? true : end ==EXT4_CLUSTERS_PER_GROUP (sb) -1 ; + }if (grp->bb_free >= minlen) { cnt =ext4_trim_all_free (sb, group, first_cluster, - end, minlen); + end, minlen, whole_group);if (cnt <0 ) { ret = cnt;break ;
Greg Kroah-Hartman
maintainerPATCH 737/879 ext4: fix use-after-free in ext4_rename_dir_prepare
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit 0be698ecbe4471fcad80e81ec6a05001421041b3 upstream.
We got issue as follows:
EXT4-fs (loop0): mounted filesystem without journal. Opts: ,errors=continueext4_get_first_dir_block: bh->b_data=0xffff88810bee6000 len=34478ext4_get_first_dir_block: *parent_de=0xffff88810beee6ae bh->b_data=0xffff88810bee6000ext4_rename_dir_prepare: [1] parent_de=0xffff88810beee6ae
==================================================================
BUG: KASAN: use-after-free in ext4_rename_dir_prepare+0x152/0x220
Read of size 4 at addr ffff88810beee6ae by task rep/1895
CPU: 13 PID: 1895 Comm: rep Not tainted 5.10.0+ #241
Call Trace:
dump_stack+0xbe/0xf9
print_address_description.constprop.0+0x1e/0x220
kasan_report.cold+0x37/0x7f
ext4_rename_dir_prepare+0x152/0x220
ext4_rename+0xf44/0x1ad0
ext4_rename2+0x11c/0x170
vfs_rename+0xa84/0x1440
do_renameat2+0x683/0x8f0
__x64_sys_renameat+0x53/0x60
do_syscall_64+0x33/0x40
entry_SYSCALL_64_after_hwframe+0x44/0xa9
RIP: 0033:0x7f45a6fc41c9
RSP: 002b:00007ffc5a470218 EFLAGS: 00000246 ORIG_RAX: 0000000000000108
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f45a6fc41c9
RDX: 0000000000000005 RSI: 0000000020000180 RDI: 0000000000000005
RBP: 00007ffc5a470240 R08: 00007ffc5a470160 R09: 0000000020000080
R10: 00000000200001c0 R11: 0000000000000246 R12: 0000000000400bb0
R13: 00007ffc5a470320 R14: 0000000000000000 R15: 0000000000000000
The buggy address belongs to the page:
page:00000000440015ce refcount:0 mapcount:0 mapping:0000000000000000 index:0x1 pfn:0x10beee
flags: 0x200000000000000()
raw: 0200000000000000 ffffea00043ff4c8 ffffea0004325608 0000000000000000
raw: 0000000000000001 0000000000000000 00000000ffffffff 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff88810beee580: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff88810beee600: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
>ffff88810beee680: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
^
ffff88810beee700: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ffff88810beee780: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
==================================================================Disabling lock debugging due to kernel taintext4_rename_dir_prepare: [2] parent_de->inode=3537895424ext4_rename_dir_prepare: [3] dir=0xffff888124170140ext4_rename_dir_prepare: [4] ino=2ext4_rename_dir_prepare: ent->dir->i_ino=2 parent=-757071872
Reason is first directory entry which 'rec_len' is 34478, then will get illegal parent entry. Now, we do not check directory entry after read directory block in 'ext4_get_first_dir_block'.
To solve this issue, check directory entry in 'ext4_get_first_dir_block'.
[ Trigger an ext4_error() instead of just warning if the directory is
missing a '.' or '..' entry. Also make sure we return an error code
if the file system is corrupted. -TYT ]
--- fs/ext4/namei.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-)
fs/ext4/namei.c +27 -3
@@ -3455,6 +3455,9 @@ static struct buffer_head *ext4_get_firsstruct buffer_head *bh;if (!ext4_has_inline_data (inode)) { +struct ext4_dir_entry_2 *de; +unsigned int offset; +/* The first directory block must not be a hole, so * treat it as DIRENT_HTREE */
@@ -3463,9 +3466,30 @@ static struct buffer_head *ext4_get_firs *retval =PTR_ERR (bh);return NULL ; } - *parent_de =ext4_next_entry ( - (struct ext4_dir_entry_2 *)bh->b_data, - inode->i_sb->s_blocksize); + + de = (struct ext4_dir_entry_2 *) bh->b_data; +if (ext4_check_dir_entry (inode,NULL , de, bh, bh->b_data, + bh->b_size,0 ) || +le32_to_cpu (de->inode) != inode->i_ino || +strcmp ("." , de->name)) { +EXT4_ERROR_INODE (inode,"directory missing '.'" ); +brelse (bh); + *retval = -EFSCORRUPTED ; +return NULL ; + } + offset =ext4_rec_len_from_disk (de->rec_len, + inode->i_sb->s_blocksize); + de =ext4_next_entry (de, inode->i_sb->s_blocksize); +if (ext4_check_dir_entry (inode,NULL , de, bh, bh->b_data, + bh->b_size, offset) || +le32_to_cpu (de->inode) ==0 ||strcmp (".." , de->name)) { +EXT4_ERROR_INODE (inode,"directory missing '..'" ); +brelse (bh); + *retval = -EFSCORRUPTED ; +return NULL ; + } + *parent_de = de; +return bh; }
Greg Kroah-Hartman
maintainerPATCH 738/879 ext4: fix journal_ioprio mount option handling
In reply to Greg Kroah-HartmanFrom: Ojaswin Mujoo <[email protected]>
commit e4e58e5df309d695799c494958962100a4c25039 upstream.
In __ext4_super() we always overwrote the user specified journal_ioprio value with a default value, expecting parse_apply_sb_mount_options() to later correctly set ctx->journal_ioprio to the user specified value. However, if parse_apply_sb_mount_options() returned early because of empty sbi->es_s->s_mount_opts, the correct journal_ioprio value was never set.
This patch fixes __ext4_super() to only use the default value if the user has not specified any value for journal_ioprio.
Similarly, the remount behavior was to either use journal_ioprio value specified during initial mount, or use the default value irrespective of the journal_ioprio value specified during remount. This patch modifies this to first check if a new value for ioprio has been passed during remount and apply it. If no new value is passed, use the value specified during initial mount.
--- fs/ext4/super.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
fs/ext4/super.c +10 -5
@@ -4410,7 +4410,8 @@ static int __ext4_fill_super(struct fs_cint silent = fc->sb_flags &SB_SILENT ;/* Set defaults for the variables that will be set during parsing */ - ctx->journal_ioprio =DEFAULT_JOURNAL_IOPRIO ; +if (!(ctx->spec &EXT4_SPEC_JOURNAL_IOPRIO )) + ctx->journal_ioprio =DEFAULT_JOURNAL_IOPRIO ; sbi->s_inode_readahead_blks =EXT4_DEF_INODE_READAHEAD_BLKS ; sbi->s_sectors_written_start =
@@ -6277,7 +6278,6 @@ static int __ext4_remount(struct fs_contchar *to_free[EXT4_MAXQUOTAS ];#endif - ctx->journal_ioprio =DEFAULT_JOURNAL_IOPRIO ;/* Store the original options */ old_sb_flags = sb->s_flags;
@@ -6303,9 +6303,14 @@ static int __ext4_remount(struct fs_cont } else old_opts.s_qf_names[i] =NULL ;#endif -if (sbi->s_journal && sbi->s_journal->j_task->io_context) - ctx->journal_ioprio = - sbi->s_journal->j_task->io_context->ioprio; +if (!(ctx->spec &EXT4_SPEC_JOURNAL_IOPRIO )) { +if (sbi->s_journal && sbi->s_journal->j_task->io_context) + ctx->journal_ioprio = + sbi->s_journal->j_task->io_context->ioprio; +else + ctx->journal_ioprio =DEFAULT_JOURNAL_IOPRIO ; + + }ext4_apply_options (fc, sb);
Greg Kroah-Hartman
maintainerPATCH 739/879 ext4: fix race condition between ext4_write and ext4_convert_inline_data
In reply to Greg Kroah-HartmanFrom: Baokun Li <[email protected]>
commit f87c7a4b084afc13190cbb263538e444cb2b392a upstream.
Hulk Robot reported a BUG_ON:
==================================================================
EXT4-fs error (device loop3): ext4_mb_generate_buddy:805: group 0, block bitmap and bg descriptor inconsistent: 25 vs 31513 free clusters kernel BUG at fs/ext4/ext4_jbd2.c:53!
invalid opcode: 0000 [#1] SMP KASAN PTI
CPU: 0 PID: 25371 Comm: syz-executor.3 Not tainted 5.10.0+ #1 RIP: 0010:ext4_put_nojournal fs/ext4/ext4_jbd2.c:53 [inline] RIP: 0010:__ext4_journal_stop+0x10e/0x110 fs/ext4/ext4_jbd2.c:116 [...] Call Trace: ext4_write_inline_data_end+0x59a/0x730 fs/ext4/inline.c:795 generic_perform_write+0x279/0x3c0 mm/filemap.c:3344 ext4_buffered_write_iter+0x2e3/0x3d0 fs/ext4/file.c:270 ext4_file_write_iter+0x30a/0x11c0 fs/ext4/file.c:520 do_iter_readv_writev+0x339/0x3c0 fs/read_write.c:732 do_iter_write+0x107/0x430 fs/read_write.c:861 vfs_writev fs/read_write.c:934 [inline] do_pwritev+0x1e5/0x380 fs/read_write.c:1031 [...] ==================================================================
Above issue may happen as follows:
cpu1 cpu2
__________________________|__________________________ do_pwritev
vfs_writev
do_iter_write
ext4_file_write_iter
ext4_buffered_write_iter
generic_perform_write
ext4_da_write_begin
vfs_fallocate
ext4_fallocate
ext4_convert_inline_data
ext4_convert_inline_data_nolock
ext4_destroy_inline_data_nolock
clear EXT4_STATE_MAY_INLINE_DATA
ext4_map_blocks
ext4_ext_map_blocks
ext4_mb_new_blocks
ext4_mb_regular_allocator
ext4_mb_good_group_nolock
ext4_mb_init_group
ext4_mb_init_cache
ext4_mb_generate_buddy --> error
ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)
ext4_restore_inline_data
set EXT4_STATE_MAY_INLINE_DATA
ext4_block_write_begin
ext4_da_write_end
ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)
ext4_write_inline_data_end
handle=NULL
ext4_journal_stop(handle)
__ext4_journal_stop
ext4_put_nojournal(handle)
ref_cnt = (unsigned long)handle
BUG_ON(ref_cnt == 0) ---> BUG_ONThe lock held by ext4_convert_inline_data is xattr_sem, but the lock held by generic_perform_write is i_rwsem. Therefore, the two locks can be concurrent.
To solve above issue, we add inode_lock() for ext4_convert_inline_data(). At the same time, move ext4_convert_inline_data() in front of ext4_punch_hole(), remove similar handling from ext4_punch_hole().
--- fs/ext4/extents.c | 10 ++++++---- fs/ext4/inode.c | 9 --------- 2 files changed, 6 insertions(+), 13 deletions(-)
fs/ext4/extents.c +6 -4
@@ -4693,15 +4693,17 @@ long ext4_fallocate(struct file *file, i FALLOC_FL_INSERT_RANGE))return -EOPNOTSUPP ; +inode_lock (inode); + ret =ext4_convert_inline_data (inode); +inode_unlock (inode); +if (ret) + goto exit; +if (mode &FALLOC_FL_PUNCH_HOLE ) { ret =ext4_punch_hole (file, offset, len); goto exit; } - ret =ext4_convert_inline_data (inode); -if (ret) - goto exit; -if (mode &FALLOC_FL_COLLAPSE_RANGE ) { ret =ext4_collapse_range (file, offset, len); goto exit;
fs/ext4/inode.c +0 -9
@@ -3967,15 +3967,6 @@ int ext4_punch_hole(struct file *file, ltrace_ext4_punch_hole (inode, offset, length,0 ); -ext4_clear_inode_state (inode,EXT4_STATE_MAY_INLINE_DATA ); -if (ext4_has_inline_data (inode)) { -filemap_invalidate_lock (mapping); - ret =ext4_convert_inline_data (inode); -filemap_invalidate_unlock (mapping); -if (ret) -return ret; - } -/* * Write out all dirty pages to avoid race conditions * Then release them.
Greg Kroah-Hartman
maintainerPATCH 740/879 ext4: fix warning in ext4_handle_inode_extension
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit f4534c9fc94d22383f187b9409abb3f9df2e3db3 upstream.
We got issue as follows:
EXT4-fs error (device loop0) in ext4_reserve_inode_write:5741: Out of memory
EXT4-fs error (device loop0): ext4_setattr:5462: inode #13: comm syz-executor.0: mark_inode_dirty error
EXT4-fs error (device loop0) in ext4_setattr:5519: Out of memory
EXT4-fs error (device loop0): ext4_ind_map_blocks:595: inode #13: comm syz-executor.0: Can't allocate blocks for non-extent mapped inodes with bigalloc
------------[ cut here ]------------ WARNING: CPU: 1 PID: 4361 at fs/ext4/file.c:301 ext4_file_write_iter+0x11c9/0x1220 Modules linked in: CPU: 1 PID: 4361 Comm: syz-executor.0 Not tainted 5.10.0+ #1 RIP: 0010:ext4_file_write_iter+0x11c9/0x1220 RSP: 0018:ffff924d80b27c00 EFLAGS: 00010282 RAX: ffffffff815a3379 RBX: 0000000000000000 RCX: 000000003b000000 RDX: ffff924d81601000 RSI: 00000000000009cc RDI: 00000000000009cd RBP: 000000000000000d R08: ffffffffbc5a2c6b R09: 0000902e0e52a96f R10: ffff902e2b7c1b40 R11: ffff902e2b7c1b40 R12: 000000000000000a R13: 0000000000000001 R14: ffff902e0e52aa10 R15: ffffffffffffff8b FS: 00007f81a7f65700(0000) GS:ffff902e3bc80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffffffff600400 CR3: 000000012db88001 CR4: 00000000003706e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: do_iter_readv_writev+0x2e5/0x360 do_iter_write+0x112/0x4c0 do_pwritev+0x1e5/0x390 __x64_sys_pwritev2+0x7e/0xa0 do_syscall_64+0x37/0x50 entry_SYSCALL_64_after_hwframe+0x44/0xa9
Above issue may happen as follows:
Assume
inode.i_size=4096
EXT4_I(inode)->i_disksize=4096
step 1: set inode->i_isize = 8192ext4_setattr
if (attr->ia_size != inode->i_size)
EXT4_I(inode)->i_disksize = attr->ia_size;
rc = ext4_mark_inode_dirty
ext4_reserve_inode_write
ext4_get_inode_loc
__ext4_get_inode_loc
sb_getblk --> return -ENOMEM
...
if (!error) ->will not update i_size
i_size_write(inode, attr->ia_size);Now:
inode.i_size=4096
EXT4_I(inode)->i_disksize=8192
step 2: Direct write 4096 bytesext4_file_write_iter
ext4_dio_write_iter
iomap_dio_rw ->return error
if (extend)
ext4_handle_inode_extension
WARN_ON_ONCE(i_size_read(inode) < EXT4_I(inode)->i_disksize);
->Then trigger warning.
To solve above issue, if mark inode dirty failed in ext4_setattr just set 'EXT4_I(inode)->i_disksize' with old value.
--- fs/ext4/inode.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/ext4/inode.c +4 -0
@@ -5389,6 +5389,7 @@ int ext4_setattr(struct user_namespace *if (attr->ia_valid &ATTR_SIZE ) {handle_t *handle;loff_t oldsize = inode->i_size; +loff_t old_disksize;int shrink = (attr->ia_size < inode->i_size);if (!(ext4_test_inode_flag (inode,EXT4_INODE_EXTENTS ))) {
@@ -5460,6 +5461,7 @@ int ext4_setattr(struct user_namespace * inode->i_sb->s_blocksize_bits);down_write (&EXT4_I (inode)->i_data_sem); + old_disksize =EXT4_I (inode)->i_disksize;EXT4_I (inode)->i_disksize = attr->ia_size; rc =ext4_mark_inode_dirty (handle, inode);if (!error)
@@ -5471,6 +5473,8 @@ int ext4_setattr(struct user_namespace **/ if (!error)i_size_write (inode, attr->ia_size); +else +EXT4_I (inode)->i_disksize = old_disksize;up_write (&EXT4_I (inode)->i_data_sem);ext4_journal_stop (handle);if (error)
Greg Kroah-Hartman
maintainerPATCH 741/879 ext4: fix memory leak in parse_apply_sb_mount_options()
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
commit c069db76ed7b681c69159f44be96d2137e9ca989 upstream.
If processing the on-disk mount options fails after any memory was allocated in the ext4_fs_context, e.g. s_qf_names, then this memory is leaked. Fix this by calling ext4_fc_free() instead of kfree() directly.
Reproducer:
mkfs.ext4 -F /dev/vdc
tune2fs /dev/vdc -E mount_opts=usrjquota=file
echo clear > /sys/kernel/debug/kmemleak
mount /dev/vdc /vdc
echo scan > /sys/kernel/debug/kmemleak
sleep 5
echo scan > /sys/kernel/debug/kmemleak
cat /sys/kernel/debug/kmemleak
--- fs/ext4/super.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
fs/ext4/super.c +4 -2
@@ -2626,8 +2626,10 @@ parse_failed: ret =ext4_apply_options (fc, sb); out_free: -kfree (s_ctx); -kfree (fc); +if (fc) { +ext4_fc_free (fc); +kfree (fc); + }kfree (s_mount_opts);return ret; }
Greg Kroah-Hartman
maintainerPATCH 742/879 ext4: fix bug_on in ext4_writepages
In reply to Greg Kroah-HartmanFrom: Ye Bin <[email protected]>
commit ef09ed5d37b84d18562b30cf7253e57062d0db05 upstream.
we got issue as follows:
EXT4-fs error (device loop0): ext4_mb_generate_buddy:1141: group 0, block bitmap and bg descriptor inconsistent: 25 vs 31513 free cls
------------[ cut here ]------------ kernel BUG at fs/ext4/inode.c:2708! invalid opcode: 0000 [#1] PREEMPT SMP KASAN PTI CPU: 2 PID: 2147 Comm: rep Not tainted 5.18.0-rc2-next-20220413+ #155 RIP: 0010:ext4_writepages+0x1977/0x1c10 RSP: 0018:ffff88811d3e7880 EFLAGS: 00010246 RAX: 0000000000000000 RBX: 0000000000000001 RCX: ffff88811c098000 RDX: 0000000000000000 RSI: ffff88811c098000 RDI: 0000000000000002 RBP: ffff888128140f50 R08: ffffffffb1ff6387 R09: 0000000000000000 R10: 0000000000000007 R11: ffffed10250281ea R12: 0000000000000001 R13: 00000000000000a4 R14: ffff88811d3e7bb8 R15: ffff888128141028 FS: 00007f443aed9740(0000) GS:ffff8883aef00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000020007200 CR3: 000000011c2a4000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: <TASK> do_writepages+0x130/0x3a0 filemap_fdatawrite_wbc+0x83/0xa0 filemap_flush+0xab/0xe0 ext4_alloc_da_blocks+0x51/0x120 __ext4_ioctl+0x1534/0x3210 __x64_sys_ioctl+0x12c/0x170 do_syscall_64+0x3b/0x90
It may happen as follows:
1. write inline_data inodevfs_write
new_sync_write
ext4_file_write_iter
ext4_buffered_write_iter
generic_perform_write
ext4_da_write_begin
ext4_da_write_inline_data_begin -> If inline data size too
small will allocate block to write, then mapping will has
dirty page
ext4_da_convert_inline_data_to_extent ->clear EXT4_STATE_MAY_INLINE_DATA
2. fallocate
do_vfs_ioctl
ioctl_preallocate
vfs_fallocate
ext4_fallocate
ext4_convert_inline_data
ext4_convert_inline_data_nolock
ext4_map_blocks -> fail will goto restore data
ext4_restore_inline_data
ext4_create_inline_data
ext4_write_inline_data
ext4_set_inode_state -> set inode EXT4_STATE_MAY_INLINE_DATA3. writepages__ext4_ioctl
ext4_alloc_da_blocks
filemap_flush
filemap_fdatawrite_wbc
do_writepages
ext4_writepages
if (ext4_has_inline_data(inode))
BUG_ON(ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA))
The root cause of this issue is we destory inline data until call ext4_writepages under delay allocation mode. But there maybe already convert from inline to extent. To solve this issue, we call filemap_flush first..
--- fs/ext4/inline.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
fs/ext4/inline.c +12 -0
@@ -2005,6 +2005,18 @@ int ext4_convert_inline_data(struct inodif (!ext4_has_inline_data (inode)) {ext4_clear_inode_state (inode,EXT4_STATE_MAY_INLINE_DATA );return 0 ; + }else if (!ext4_test_inode_state (inode,EXT4_STATE_MAY_INLINE_DATA )) { +/* +* Inode has inline data but EXT4_STATE_MAY_INLINE_DATA is +* cleared. This means we are in the middle of moving of +* inline data to delay allocated block. Just force writeout +* here to finish conversion. +*/ + error =filemap_flush (inode->i_mapping); +if (error) +return error; +if (!ext4_has_inline_data (inode)) +return 0 ; } needed_blocks =ext4_writepage_trans_blocks (inode);
Greg Kroah-Hartman
maintainerPATCH 743/879 ext4: filter out EXT4_FC_REPLAY from on-disk superblock field s_state
In reply to Greg Kroah-HartmanFrom: Theodore Ts'o <[email protected]>
commit c878bea3c9d724ddfa05a813f30de3d25a0ba83f upstream.
The EXT4_FC_REPLAY bit in sbi->s_mount_state is used to indicate that we are in the middle of replay the fast commit journal. This was actually a mistake, since the sbi->s_mount_info is initialized from es->s_state. Arguably s_mount_state is misleadingly named, but the name is historical --- s_mount_state and s_state dates back to ext2.
What should have been used is the ext4_{set,clear,test}_mount_flag() inline functions, which sets EXT4_MF_* bits in sbi->s_mount_flags.
The problem with using EXT4_FC_REPLAY is that a maliciously corrupted superblock could result in EXT4_FC_REPLAY getting set in s_mount_state. This bypasses some sanity checks, and this can trigger a BUG() in ext4_es_cache_extent(). As a easy-to-backport-fix, filter out the EXT4_FC_REPLAY bit for now. We should eventually transition away from EXT4_FC_REPLAY to something like EXT4_MF_REPLAY.
--- fs/ext4/super.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/ext4/super.c +3 -2
@@ -4890,7 +4890,7 @@ static int __ext4_fill_super(struct fs_c sbi->s_inodes_per_block; sbi->s_desc_per_block = blocksize /EXT4_DESC_SIZE (sb); sbi->s_sbh = bh; - sbi->s_mount_state =le16_to_cpu (es->s_state); + sbi->s_mount_state =le16_to_cpu (es->s_state) & ~EXT4_FC_REPLAY ; sbi->s_addr_per_block_bits =ilog2 (EXT4_ADDR_PER_BLOCK (sb)); sbi->s_desc_per_block_bits =ilog2 (EXT4_DESC_PER_BLOCK (sb));
@@ -6453,7 +6453,8 @@ static int __ext4_remount(struct fs_contif (err) goto restore_opts; } - sbi->s_mount_state =le16_to_cpu (es->s_state); + sbi->s_mount_state = (le16_to_cpu (es->s_state) & + ~EXT4_FC_REPLAY ); err =ext4_setup_super (sb, es,0 );if (err)
Greg Kroah-Hartman
maintainerPATCH 744/879 ext4: fix bug_on in __es_tree_search
In reply to Greg Kroah-HartmanFrom: Baokun Li <[email protected]>
commit d36f6ed761b53933b0b4126486c10d3da7751e7f upstream.
Hulk Robot reported a BUG_ON:
==================================================================
kernel BUG at fs/ext4/extents_status.c:199!
[...]
RIP: 0010:ext4_es_end fs/ext4/extents_status.c:199 [inline] RIP: 0010:__es_tree_search+0x1e0/0x260 fs/ext4/extents_status.c:217 [...] Call Trace: ext4_es_cache_extent+0x109/0x340 fs/ext4/extents_status.c:766 ext4_cache_extents+0x239/0x2e0 fs/ext4/extents.c:561 ext4_find_extent+0x6b7/0xa20 fs/ext4/extents.c:964 ext4_ext_map_blocks+0x16b/0x4b70 fs/ext4/extents.c:4384 ext4_map_blocks+0xe26/0x19f0 fs/ext4/inode.c:567 ext4_getblk+0x320/0x4c0 fs/ext4/inode.c:980 ext4_bread+0x2d/0x170 fs/ext4/inode.c:1031 ext4_quota_read+0x248/0x320 fs/ext4/super.c:6257 v2_read_header+0x78/0x110 fs/quota/quota_v2.c:63 v2_check_quota_file+0x76/0x230 fs/quota/quota_v2.c:82 vfs_load_quota_inode+0x5d1/0x1530 fs/quota/dquot.c:2368 dquot_enable+0x28a/0x330 fs/quota/dquot.c:2490 ext4_quota_enable fs/ext4/super.c:6137 [inline] ext4_enable_quotas+0x5d7/0x960 fs/ext4/super.c:6163 ext4_fill_super+0xa7c9/0xdc00 fs/ext4/super.c:4754 mount_bdev+0x2e9/0x3b0 fs/super.c:1158 mount_fs+0x4b/0x1e4 fs/super.c:1261
[...]
==================================================================
Above issue may happen as follows:
-------------------------------------ext4_fill_super
ext4_enable_quotas
ext4_quota_enable
ext4_iget
__ext4_iget
ext4_ext_check_inode
ext4_ext_check
__ext4_ext_check
ext4_valid_extent_entries
Check for overlapping extents does't take effect
dquot_enable
vfs_load_quota_inode
v2_check_quota_file
v2_read_header
ext4_quota_read
ext4_bread
ext4_getblk
ext4_map_blocks
ext4_ext_map_blocks
ext4_find_extent
ext4_cache_extents
ext4_es_cache_extent
ext4_es_cache_extent
__es_tree_search
ext4_es_end
BUG_ON(es->es_lblk + es->es_len < es->es_lblk)The error ext4 extents is as follows:
0af3 0300 0400 0000 00000000 extent_header 00000000 0100 0000 12000000 extent1 00000000 0100 0000 18000000 extent2 02000000 0400 0000 14000000 extent3
In the ext4_valid_extent_entries function,
if prev is 0, no error is returned even if lblock<=prev. This was intended to skip the check on the first extent, but in the error image above, prev=0+1-1=0 when checking the second extent, so even though lblock<=prev, the function does not return an error. As a result, bug_ON occurs in __es_tree_search and the system panics.
To solve this problem, we only need to check that:
1. The lblock of the first extent is not less than 0.
2. The lblock of the next extent is not less than the next block of the previous extent.
The same applies to extent_idx.
--- fs/ext4/extents.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
fs/ext4/extents.c +5 -5
@@ -372,7 +372,7 @@ static int ext4_valid_extent_entries(str {unsigned short entries;ext4_lblk_t lblock =0 ; -ext4_lblk_t prev =0 ; +ext4_lblk_t cur =0 ;if (eh->eh_entries ==0 )return 1 ;
@@ -396,11 +396,11 @@ static int ext4_valid_extent_entries(str/* Check for overlapping extents */ lblock =le32_to_cpu (ext->ee_block); -if ((lblock <= prev) && prev) { +if (lblock < cur) { *pblk =ext4_ext_pblock (ext);return 0 ; } - prev = lblock +ext4_ext_get_actual_len (ext) -1 ; + cur = lblock +ext4_ext_get_actual_len (ext); ext++; entries--; }
@@ -420,13 +420,13 @@ static int ext4_valid_extent_entries(str/* Check for overlapping index extents */ lblock =le32_to_cpu (ext_idx->ei_block); -if ((lblock <= prev) && prev) { +if (lblock < cur) { *pblk =ext4_idx_pblock (ext_idx);return 0 ; } ext_idx++; entries--; - prev = lblock; + cur = lblock +1 ; } }return 1 ;
Greg Kroah-Hartman
maintainerPATCH 745/879 ext4: verify dir block before splitting it
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 46c116b920ebec58031f0a78c5ea9599b0d2a371 upstream.
Before splitting a directory block verify its directory entries are sane so that the splitting code does not access memory it should not.
--- fs/ext4/namei.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-)
fs/ext4/namei.c +21 -11
@@ -277,9 +277,9 @@ static struct dx_frame *dx_probe(structstruct dx_hash_info *hinfo, struct dx_frame *frame);static void dx_release (struct dx_frame *frames); -static int dx_make_map (struct inode *dir,struct ext4_dir_entry_2 *de, -unsigned blocksize,struct dx_hash_info *hinfo, -struct dx_map_entry map[]); +static int dx_make_map (struct inode *dir,struct buffer_head *bh, +struct dx_hash_info *hinfo, +struct dx_map_entry *map_tail);static void dx_sort_map (struct dx_map_entry *map,unsigned count); static struct ext4_dir_entry_2 *dx_move_dirents(struct inode *dir, char *from, char *to, struct dx_map_entry *offsets,
@@ -1249,15 +1249,23 @@ static inline int search_dirblock(struct* Create map of hash values, offsets, and sizes, stored at end of block. * Returns number of entries mapped. */ -static int dx_make_map (struct inode *dir,struct ext4_dir_entry_2 *de, -unsigned blocksize,struct dx_hash_info *hinfo, +static int dx_make_map (struct inode *dir,struct buffer_head *bh, +struct dx_hash_info *hinfo,struct dx_map_entry *map_tail) {int count =0 ; -char *base = (char *) de; +struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *)bh->b_data; +unsigned int buflen = bh->b_size; +char *base = bh->b_data;struct dx_hash_info h = *hinfo; -while ((char *) de < base + blocksize) { +if (ext4_has_metadata_csum (dir->i_sb)) + buflen -=sizeof (struct ext4_dir_entry_tail ); + +while ((char *) de < base + buflen) { +if (ext4_check_dir_entry (dir,NULL , de, bh, base, buflen, + ((char *)de) - base)) +return -EFSCORRUPTED ;if (de->name_len && de->inode) {if (ext4_hash_in_dirent (dir)) h.hash =EXT4_DIRENT_HASH (de);
@@ -1270,8 +1278,7 @@ static int dx_make_map(struct inode *dir count++;cond_resched (); } -/* XXX: do we need to check rec_len == 0 case? -Chris */ - de =ext4_next_entry (de, blocksize); + de =ext4_next_entry (de, dir->i_sb->s_blocksize); }return count; }
@@ -1943,8 +1950,11 @@ static struct ext4_dir_entry_2 *do_split/* create map in the end of data2 block */ map = (struct dx_map_entry *) (data2 + blocksize); - count =dx_make_map (dir, (struct ext4_dir_entry_2 *) data1, - blocksize, hinfo, map); + count =dx_make_map (dir, *bh, hinfo, map); +if (count <0 ) { + err = count; + goto journal_error; + } map -= count;dx_sort_map (map, count);/* Ensure that neither split block is over half full */
Greg Kroah-Hartman
maintainerPATCH 746/879 ext4: avoid cycles in directory h-tree
In reply to Greg Kroah-HartmanFrom: Jan Kara <[email protected]>
commit 3ba733f879c2a88910744647e41edeefbc0d92b2 upstream.
A maliciously corrupted filesystem can contain cycles in the h-tree stored inside a directory. That can easily lead to the kernel corrupting tree nodes that were already verified under its hands while doing a node split and consequently accessing unallocated memory. Fix the problem by verifying traversed block numbers are unique.
--- fs/ext4/namei.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-)
fs/ext4/namei.c +19 -3
@@ -777,12 +777,14 @@ static struct dx_frame * dx_probe(struct ext4_filename *fname, struct inode *dir, struct dx_hash_info *hinfo, struct dx_frame *frame_in) { - unsigned count, indirect; + unsigned count, indirect, level, i;struct dx_entry *at, *entries, *p, *q, *m;struct dx_root *root;struct dx_frame *frame = frame_in;struct dx_frame *ret_err =ERR_PTR (ERR_BAD_DX_DIR );u32 hash; +ext4_lblk_t block; +ext4_lblk_t blocks[EXT4_HTREE_LEVEL ];memset (frame_in,0 ,EXT4_HTREE_LEVEL *sizeof (frame_in[0 ])); frame->bh =ext4_read_dirblock (dir,0 ,INDEX );
@@ -854,6 +856,8 @@ dx_probe(struct ext4_filename *fname, st }dxtrace (printk ("Look up %x" , hash)); + level =0 ; + blocks[0 ] =0 ;while (1 ) { count =dx_get_count (entries);if (!count || count >dx_get_limit (entries)) {
@@ -882,15 +886,27 @@ dx_probe(struct ext4_filename *fname, st dx_get_block(at))); frame->entries = entries; frame->at = at; -if (!indirect--) + + block =dx_get_block (at); +for (i =0 ; i <= level; i++) { +if (blocks[i] == block) { +ext4_warning_inode (dir, +"dx entry: tree cycle block %u points back to block %u" , + blocks[level], block); + goto fail; + } + } +if (++level > indirect)return frame; + blocks[level] = block; frame++; - frame->bh =ext4_read_dirblock (dir,dx_get_block (at),INDEX ); + frame->bh =ext4_read_dirblock (dir, block,INDEX );if (IS_ERR (frame->bh)) { ret_err = (struct dx_frame *) frame->bh; frame->bh =NULL ; goto fail; } + entries = ((struct dx_node *) frame->bh->b_data)->entries;if (dx_get_limit (entries) !=dx_node_limit (dir)) {
Greg Kroah-Hartman
maintainerPATCH 747/879 ACPI: property: Release subnode properties with data nodes
In reply to Greg Kroah-HartmanFrom: Sakari Ailus <[email protected]>
commit 3bd561e1572ee02a50cd1a5be339abf1a5b78d56 upstream.
struct acpi_device_properties describes one source of properties present on either struct acpi_device or struct acpi_data_node. When properties are parsed, both are populated but when released, only those properties that are associated with the device node are freed.
Fix this by also releasing memory of the data node properties.
--- drivers/acpi/property.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
drivers/acpi/property.c +12 -6
@@ -433,6 +433,16 @@ void acpi_init_properties(struct acpi_deacpi_extract_apple_properties (adev); } +static void acpi_free_device_properties (struct list_head *list) +{ +struct acpi_device_properties *props, *tmp; + +list_for_each_entry_safe (props, tmp, list, list) { +list_del (&props->list); +kfree (props); + } +} +static void acpi_destroy_nondev_subnodes (struct list_head *list) {struct acpi_data_node *dn, *next;
@@ -445,22 +455,18 @@ static void acpi_destroy_nondev_subnodeswait_for_completion (&dn->kobj_done);list_del (&dn->sibling);ACPI_FREE ((void *)dn->data.pointer); +acpi_free_device_properties (&dn->data.properties);kfree (dn); } }void acpi_free_properties (struct acpi_device *adev) { -struct acpi_device_properties *props, *tmp; -acpi_destroy_nondev_subnodes (&adev->data.subnodes);ACPI_FREE ((void *)adev->data.pointer); adev->data.of_compatible =NULL ; adev->data.pointer =NULL ; -list_for_each_entry_safe (props, tmp, &adev->data.properties, list) { -list_del (&props->list); -kfree (props); - } +acpi_free_device_properties (&adev->data.properties); }/**
Greg Kroah-Hartman
maintainerPATCH 748/879 tty: goldfish: Introduce gf_ioread32()/gf_iowrite32()
In reply to Greg Kroah-HartmanFrom: Laurent Vivier <[email protected]>
commit 2e2ac4a3327479f7e2744cdd88a5c823f2057bad upstream.
The goldfish TTY device was clearly defined as having little-endian registers, but the switch to __raw_{read,write}l(() broke its driver when running on big-endian kernels (if anyone ever tried this).
The m68k qemu implementation got this wrong, and assumed native-endian registers. While this is a bug in qemu, it is probably impossible to fix that since there is no way of knowing which other operating systems have started relying on that bug over the years.
Hence revert commit da31de35cd2f ("tty: goldfish: use __raw_writel()/__raw_readl()", and define gf_ioread32()/gf_iowrite32() to be able to use accessors defined by the architecture.
--- drivers/tty/goldfish.c | 20 ++++++++++---------- include/linux/goldfish.h | 15 +++++++++++---- 2 files changed, 21 insertions(+), 14 deletions(-)
drivers/tty/goldfish.c +10 -10
@@ -61,13 +61,13 @@ static void do_rw_io(struct goldfish_ttyspin_lock_irqsave (&qtty->lock, irq_flags);gf_write_ptr ((void *)address, base +GOLDFISH_TTY_REG_DATA_PTR , base +GOLDFISH_TTY_REG_DATA_PTR_HIGH ); -__raw_writel (count, base +GOLDFISH_TTY_REG_DATA_LEN ); +gf_iowrite32 (count, base +GOLDFISH_TTY_REG_DATA_LEN );if (is_write) -__raw_writel (GOLDFISH_TTY_CMD_WRITE_BUFFER , +gf_iowrite32 (GOLDFISH_TTY_CMD_WRITE_BUFFER , base +GOLDFISH_TTY_REG_CMD );else -__raw_writel (GOLDFISH_TTY_CMD_READ_BUFFER , +gf_iowrite32 (GOLDFISH_TTY_CMD_READ_BUFFER , base +GOLDFISH_TTY_REG_CMD );spin_unlock_irqrestore (&qtty->lock, irq_flags);
@@ -142,7 +142,7 @@ static irqreturn_t goldfish_tty_interrupunsigned char *buf;u32 count; - count =__raw_readl (base +GOLDFISH_TTY_REG_BYTES_READY ); + count =gf_ioread32 (base +GOLDFISH_TTY_REG_BYTES_READY );if (count ==0 )return IRQ_NONE ;
@@ -159,7 +159,7 @@ static int goldfish_tty_activate(struct { struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port); -__raw_writel (GOLDFISH_TTY_CMD_INT_ENABLE , qtty->base +GOLDFISH_TTY_REG_CMD ); +gf_iowrite32 (GOLDFISH_TTY_CMD_INT_ENABLE , qtty->base +GOLDFISH_TTY_REG_CMD );return 0 ; }
@@ -167,7 +167,7 @@ static void goldfish_tty_shutdown(struct { struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port); -__raw_writel (GOLDFISH_TTY_CMD_INT_DISABLE , qtty->base +GOLDFISH_TTY_REG_CMD ); +gf_iowrite32 (GOLDFISH_TTY_CMD_INT_DISABLE , qtty->base +GOLDFISH_TTY_REG_CMD ); }static int goldfish_tty_open (struct tty_struct *tty,struct file *filp)
@@ -202,7 +202,7 @@ static unsigned int goldfish_tty_chars_i {struct goldfish_tty *qtty = &goldfish_ttys[tty->index];void __iomem *base = qtty->base; -return __raw_readl (base +GOLDFISH_TTY_REG_BYTES_READY ); +return gf_ioread32 (base +GOLDFISH_TTY_REG_BYTES_READY ); } static void goldfish_tty_console_write(struct console *co, const char *b,
@@ -355,7 +355,7 @@ static int goldfish_tty_probe(struct pla* on Ranchu emulator (qemu2) returns 1 here and * driver will use physical addresses. */ - qtty->version =__raw_readl (base +GOLDFISH_TTY_REG_VERSION ); + qtty->version =gf_ioread32 (base +GOLDFISH_TTY_REG_VERSION );/* * Goldfish TTY device on Ranchu emulator (qemu2)
@@ -374,7 +374,7 @@ static int goldfish_tty_probe(struct pla } } -__raw_writel (GOLDFISH_TTY_CMD_INT_DISABLE , base +GOLDFISH_TTY_REG_CMD ); +gf_iowrite32 (GOLDFISH_TTY_CMD_INT_DISABLE , base +GOLDFISH_TTY_REG_CMD ); ret =request_irq (irq, goldfish_tty_interrupt,IRQF_SHARED ,"goldfish_tty" , qtty);
@@ -436,7 +436,7 @@ static int goldfish_tty_remove(struct pl#ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE static void gf_early_console_putchar (struct uart_port *port,unsigned char ch) { -__raw_writel (ch, port->membase); +gf_iowrite32 (ch, port->membase); }static void gf_early_write (struct console *con,const char *s,unsigned int n)
include/linux/goldfish.h +11 -4
@@ -8,14 +8,21 @@/* Helpers for Goldfish virtual platform */ +#ifndef gf_ioread32 +#define gf_ioread32 ioread32 +#endif +#ifndef gf_iowrite32 +#define gf_iowrite32 iowrite32 +#endif +static inline void gf_write_ptr (const void *ptr,void __iomem *portl,void __iomem *porth) {const unsigned long addr = (unsigned long )ptr; -__raw_writel (lower_32_bits (addr), portl); +gf_iowrite32 (lower_32_bits (addr), portl);#ifdef CONFIG_64BIT -__raw_writel (upper_32_bits (addr), porth); +gf_iowrite32 (upper_32_bits (addr), porth);#endif }
@@ -23,9 +30,9 @@ static inline void gf_write_dma_addr(convoid __iomem *portl, void __iomem *porth) { -__raw_writel (lower_32_bits (addr ),portl ); +gf_iowrite32 (lower_32_bits (addr ),portl );#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -__raw_writel (upper_32_bits (addr), porth); +gf_iowrite32 (upper_32_bits (addr), porth);#endif }
Greg Kroah-Hartman
maintainerPATCH 749/879 tracing: Have event format check not flag %p* on __get_dynamic_array()
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (Google) <[email protected]>
commit 499f12168aebd6da8fa32c9b7d6203ca9b5eb88d upstream.
The print fmt check against trace events to make sure that the format does not use pointers that may be freed from the time of the trace to the time the event is read, gives a false positive on %pISpc when reading data that was saved in __get_dynamic_array() when it is perfectly fine to do so, as the data being read is on the ring buffer.
--- kernel/trace/trace_events.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
kernel/trace/trace_events.c +7 -6
@@ -392,12 +392,6 @@ static void test_event_printk(struct traif (!(dereference_flags & (1ULL << arg))) goto next_arg; -/* Check for __get_sockaddr */ ; -if (str_has_prefix (fmt + i,"__get_sockaddr(" )) { - dereference_flags &= ~(1ULL << arg); - goto next_arg; - } -/* Find the REC-> in the argument */ c =strchr (fmt + i,',' ); r =strstr (fmt + i,"REC->" );
@@ -413,7 +407,14 @@ static void test_event_printk(struct tra a =strchr (fmt + i,'&' );if ((a && (a < r)) ||test_field (r, call)) dereference_flags &= ~(1ULL << arg); + }else if ((r =strstr (fmt + i,"__get_dynamic_array(" )) && + (!c || r < c)) { + dereference_flags &= ~(1ULL << arg); + }else if ((r =strstr (fmt + i,"__get_sockaddr(" )) && + (!c || r < c)) { + dereference_flags &= ~(1ULL << arg); } + next_arg: i--; arg++;
Greg Kroah-Hartman
maintainerPATCH 750/879 tracing: Fix potential double free in create_var_ref()
In reply to Greg Kroah-HartmanFrom: Keita Suzuki <[email protected]>
commit 99696a2592bca641eb88cc9a80c90e591afebd0f upstream.
In create_var_ref(), init_var_ref() is called to initialize the fields of variable ref_field, which is allocated in the previous function call to create_hist_field(). Function init_var_ref() allocates the corresponding fields such as ref_field->system, but frees these fields when the function encounters an error. The caller later calls destroy_hist_field() to conduct error handling, which frees the fields and the variable itself. This results in double free of the fields which are already freed in the previous function.
Fix this by storing NULL to the corresponding fields when they are freed in init_var_ref().
--- kernel/trace/trace_events_hist.c | 3 +++ 1 file changed, 3 insertions(+)
kernel/trace/trace_events_hist.c +3 -0
@@ -2093,8 +2093,11 @@ static int init_var_ref(struct hist_fielreturn err; free:kfree (ref_field->system); + ref_field->system =NULL ;kfree (ref_field->event_name); + ref_field->event_name =NULL ;kfree (ref_field->name); + ref_field->name =NULL ; goto out; }
Greg Kroah-Hartman
maintainerPATCH 751/879 tracing: Fix return value of trace_pid_write()
In reply to Greg Kroah-HartmanFrom: Wonhyuk Yang <[email protected]>
commit b27f266f74fbda4ee36c2b2b04d15992860cf23b upstream.
Setting set_event_pid with trailing whitespace lead to endless write system calls like below.
$ strace echo "123 " > /sys/kernel/debug/tracing/set_event_pid
execve("/usr/bin/echo", ["echo", "123 "], ...) = 0
...
write(1, "123 \n", 5) = 4
write(1, "\n", 1) = 0
write(1, "\n", 1) = 0
write(1, "\n", 1) = 0
write(1, "\n", 1) = 0
write(1, "\n", 1) = 0
....This is because, the result of trace_get_user's are not returned when it read at least one pid. To fix it, update read variable even if parser->idx == 0.
The result of applied patch is below.
$ strace echo "123 " > /sys/kernel/debug/tracing/set_event_pid
execve("/usr/bin/echo", ["echo", "123 "], ...) = 0
...
write(1, "123 \n", 5) = 5
close(1) = 0--- kernel/trace/trace.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
kernel/trace/trace.c +4 -2
@@ -721,13 +721,16 @@ int trace_pid_write(struct trace_pid_lis pos =0 ; ret =trace_get_user (&parser, ubuf, cnt, &pos); -if (ret <0 || !trace_parser_loaded (&parser)) +if (ret <0 )break ; read += ret; ubuf += ret; cnt -= ret; +if (!trace_parser_loaded (&parser)) +break ; + ret = -EINVAL ;if (kstrtoul (parser.buffer,0 , &val))break ;
@@ -753,7 +756,6 @@ int trace_pid_write(struct trace_pid_lisif (!nr_pids) {/* Cleared the list of pids */ trace_pid_list_free (pid_list); - read = ret; pid_list =NULL ; }
Greg Kroah-Hartman
maintainerPATCH 752/879 tracing: Initialize integer variable to prevent garbage return value
In reply to Greg Kroah-HartmanFrom: Gautam Menghani <[email protected]>
commit 154827f8e53d8c492b3fb0cb757fbcadb5d516b5 upstream.
Initialize the integer variable to 0 to fix the clang scan warning:
Undefined or garbage value returned to caller [core.uninitialized.UndefReturn]
return ret;
--- kernel/trace/trace_boot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_boot.c +1 -1
@@ -300,7 +300,7 @@ trace_boot_hist_add_handlers(struct xbc_ {struct xbc_node *node;const char *p, *handler; -int ret; +int ret =0 ; handler =xbc_node_get_data (hnode);
Greg Kroah-Hartman
maintainerPATCH 753/879 drm/amdgpu: add beige goby PCI ID
In reply to Greg Kroah-HartmanFrom: Alex Deucher <[email protected]>
commit 62e9bd20035b53ff6c679499c08546d96c6c60a7 upstream.
Add a beige goby PCI ID.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +1 -0
@@ -1931,6 +1931,7 @@ static const struct pci_device_id pciidl {0x1002, 0x7421, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BEIGE_GOBY}, {0x1002, 0x7422, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BEIGE_GOBY}, {0x1002, 0x7423, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BEIGE_GOBY}, + {0x1002, 0x7424, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BEIGE_GOBY}, {0x1002, 0x743F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BEIGE_GOBY}, { PCI_DEVICE(0x1002, PCI_ANY_ID),
Greg Kroah-Hartman
maintainerPATCH 754/879 PCI/PM: Fix bridge_d3_blacklist[] Elo i2 overwrite of Gigabyte X299
In reply to Greg Kroah-HartmanFrom: Bjorn Helgaas <[email protected]>
commit 12068bb346db5776d0ec9bb4cd073f8427a1ac92 upstream.
92597f97a40b ("PCI/PM: Avoid putting Elo i2 PCIe Ports in D3cold") omitted braces around the new Elo i2 entry, so it overwrote the existing Gigabyte X299 entry. Add the appropriate braces.
Found by:
$ make W=1 drivers/pci/pci.o
CC drivers/pci/pci.o
drivers/pci/pci.c:2974:12: error: initialized field overwritten [-Werror=override-init]
2974 | .ident = "Elo i2",
| ^~~~~~~~--- drivers/pci/pci.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/pci/pci.c +2 -0
@@ -2920,6 +2920,8 @@ static const struct dmi_system_id bridgeDMI_MATCH (DMI_BOARD_VENDOR ,"Gigabyte Technology Co., Ltd." ), DMI_MATCH(DMI_BOARD_NAME, "X299 DESIGNARE EX-CF"), }, + }, + {/* * Downstream device is not accessible after putting a root port * into D3cold and back into D0 on Elo i2.
Greg Kroah-Hartman
maintainerPATCH 755/879 PCI: qcom: Fix pipe clock imbalance
In reply to Greg Kroah-HartmanFrom: Johan Hovold <[email protected]>
commit fdf6a2f533115ec5d4d9629178f8196331f1ac50 upstream.
Fix a clock imbalance introduced by ed8cc3b1fc84 ("PCI: qcom: Add support for SDM845 PCIe controller"), which enables the pipe clock both in init() and in post_init() but only disables in post_deinit().
Note that the pipe clock was also never disabled in the init() error paths and that enabling the clock before powering up the PHY looks questionable.
--- drivers/pci/controller/dwc/pcie-qcom.c | 6 ------ 1 file changed, 6 deletions(-)
drivers/pci/controller/dwc/pcie-qcom.c +0 -6
@@ -1238,12 +1238,6 @@ static int qcom_pcie_init_2_7_0(struct q goto err_disable_clocks; } - ret =clk_prepare_enable (res->pipe_clk); -if (ret) { -dev_err (dev,"cannot prepare/enable pipe clock\n" ); - goto err_disable_clocks; - } -/* Wait for reset to complete, required on SM8450 */ usleep_range (1000 ,1500 );
Greg Kroah-Hartman
maintainerPATCH 756/879 PCI: qcom: Fix runtime PM imbalance on probe errors
In reply to Greg Kroah-HartmanFrom: Johan Hovold <[email protected]>
commit 87d83b96c8d6c6c2d2096bd0bdba73bcf42b8ef0 upstream.
Drop the leftover pm_runtime_disable() calls from the late probe error paths that would, for example, prevent runtime PM from being reenabled after a probe deferral.
--- drivers/pci/controller/dwc/pcie-qcom.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
drivers/pci/controller/dwc/pcie-qcom.c +1 -4
@@ -1621,17 +1621,14 @@ static int qcom_pcie_probe(struct platfo pp->ops = &qcom_pcie_dw_ops; ret =phy_init (pcie->phy); -if (ret) { -pm_runtime_disable (&pdev->dev); +if (ret) goto err_pm_runtime_put; - }platform_set_drvdata (pdev, pcie); ret =dw_pcie_host_init (pp);if (ret) {dev_err (dev,"cannot initialize host\n" ); -pm_runtime_disable (&pdev->dev); goto err_pm_runtime_put; }
Greg Kroah-Hartman
maintainerPATCH 757/879 PCI: qcom: Fix unbalanced PHY init on probe errors
In reply to Greg Kroah-HartmanFrom: Johan Hovold <[email protected]>
commit 83013631f0f9961416abd812e228c8efbc2f6069 upstream.
Undo the PHY initialisation (e.g. balance runtime PM) if host initialisation fails during probe.
--- drivers/pci/controller/dwc/pcie-qcom.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/pci/controller/dwc/pcie-qcom.c +3 -1
@@ -1629,11 +1629,13 @@ static int qcom_pcie_probe(struct platfo ret =dw_pcie_host_init (pp);if (ret) {dev_err (dev,"cannot initialize host\n" ); - goto err_pm_runtime_put; + goto err_phy_exit; }return 0 ; +err_phy_exit: +phy_exit (pcie->phy); err_pm_runtime_put:pm_runtime_put (dev);pm_runtime_disable (dev);
Greg Kroah-Hartman
maintainerPATCH 758/879 staging: r8188eu: prevent ->Ssid overflow in rtw_wx_set_scan()
In reply to Greg Kroah-HartmanFrom: Denis Efremov <[email protected]>
commit bc10916e890948d8927a5c8c40fb5dc44be5e1b8 upstream.
This code has a check to prevent read overflow but it needs another check to prevent writing beyond the end of the ->Ssid[] array.
--- drivers/staging/r8188eu/os_dep/ioctl_linux.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/staging/r8188eu/os_dep/ioctl_linux.c +4 -2
@@ -1131,9 +1131,11 @@ static int rtw_wx_set_scan(struct net_debreak ; } sec_len = *(pos++); len -=1 ; -if (sec_len >0 && sec_len <= len) { +if (sec_len >0 && + sec_len <= len && + sec_len <=32 ) { ssid[ssid_index].SsidLength = sec_len; -memcpy (ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength); +memcpy (ssid[ssid_index].Ssid, pos, sec_len); ssid_index++; } pos += sec_len;
Greg Kroah-Hartman
maintainerPATCH 759/879 block: Fix potential deadlock in blk_ia_range_sysfs_show()
In reply to Greg Kroah-HartmanFrom: Damien Le Moal <[email protected]>
commit 41e46b3c2aa24f755b2ae9ec4ce931ba5f0d8532 upstream.
When being read, a sysfs attribute is already protected against removal with the kobject node active reference counter. As a result, in blk_ia_range_sysfs_show(), there is no need to take the queue sysfs lock when reading the value of a range attribute. Using the queue sysfs lock in this function creates a potential deadlock situation with the disk removal, something that a lockdep signals with a splat when the device is removed:
[ 760.703551] Possible unsafe locking scenario: [ 760.703551] [ 760.703554] CPU0 CPU1 [ 760.703556] ---- ---- [ 760.703558] lock(&q->sysfs_lock); [ 760.703565] lock(kn->active#385); [ 760.703573] lock(&q->sysfs_lock); [ 760.703579] lock(kn->active#385); [ 760.703587] [ 760.703587] *** DEADLOCK ***
Solve this by removing the mutex_lock()/mutex_unlock() calls from blk_ia_range_sysfs_show().
--- block/blk-ia-ranges.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
block/blk-ia-ranges.c +1 -6
@@ -54,13 +54,8 @@ static ssize_t blk_ia_range_sysfs_show(s container_of(attr, struct blk_ia_range_sysfs_entry, attr);struct blk_independent_access_range *iar = container_of(kobj, struct blk_independent_access_range, kobj); -ssize_t ret; -mutex_lock (&iar->queue->sysfs_lock); - ret = entry->show (iar, buf); -mutex_unlock (&iar->queue->sysfs_lock); - -return ret; +return entry->show (iar, buf); }static const struct sysfs_ops blk_ia_range_sysfs_ops = {
Greg Kroah-Hartman
maintainerPATCH 760/879 mm, compaction: fast_find_migrateblock() should return pfn in the target zone
In reply to Greg Kroah-HartmanFrom: Rei Yamamoto <[email protected]>
commit bbe832b9db2e1ad21522f8f0bf02775fff8a0e0e upstream.
At present, pages not in the target zone are added to cc->migratepages list in isolate_migratepages_block(). As a result, pages may migrate between nodes unintentionally.
This would be a serious problem for older kernels without commit a984226f457f849e ("mm: memcontrol: remove the pgdata parameter of mem_cgroup_page_lruvec"), because it can corrupt the lru list by handling pages in list without holding proper lru_lock.
Avoid returning a pfn outside the target zone in the case that it is not aligned with a pageblock boundary. Otherwise isolate_migratepages_block() will handle pages not in the target zone.
--- mm/compaction.c | 2 ++ 1 file changed, 2 insertions(+)
mm/compaction.c +2 -0
@@ -1858,6 +1858,8 @@ static unsigned long fast_find_migrateblupdate_fast_start_pfn (cc, free_pfn); pfn =pageblock_start_pfn (free_pfn); +if (pfn < cc->zone->zone_start_pfn) + pfn = cc->zone->zone_start_pfn; cc->fast_search_fail =0 ; found_block = true;set_pageblock_skip (freepage);
Greg Kroah-Hartman
maintainerPATCH 761/879 s390/perf: obtain sie_block from the right address
In reply to Greg Kroah-HartmanFrom: Nico Boehr <[email protected]>
commit c9bfb460c3e4da2462e16b0f0b200990b36b1dd2 upstream.
Since commit 1179f170b6f0 ("s390: fix fpu restore in entry.S"), the sie_block pointer is located at empty1[1], but in sie_block() it was taken from empty1[0].
This leads to a random pointer being dereferenced, possibly causing system crash.
This problem can be observed when running a simple guest with an endless loop and recording the cpu-clock event:
sudo perf kvm --guestvmlinux=<guestkernel> --guest top -e cpu-clock
With this fix, the correct guest address is shown.
--- arch/s390/kernel/perf_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/s390/kernel/perf_event.c +1 -1
@@ -30,7 +30,7 @@ static struct kvm_s390_sie_block *sie_blif (!stack)return NULL ; -return (struct kvm_s390_sie_block *) stack->empty1[0 ]; +return (struct kvm_s390_sie_block *)stack->empty1[1 ]; }static bool is_in_guest (struct pt_regs *regs)
Greg Kroah-Hartman
maintainerPATCH 762/879 s390/stp: clock_delta should be signed
In reply to Greg Kroah-HartmanFrom: Sven Schnelle <[email protected]>
commit 5ace65ebb5ce9fe1cc8fdbdd97079fb566ef0ea4 upstream.
clock_delta is declared as unsigned long in various places. However, the clock sync delta can be negative. This would add a huge positive offset in clock_sync_global where clock_delta is added to clk.eitod which is a 72 bit integer. Declare it as signed long to fix this.
--- arch/s390/include/asm/cio.h | 2 +- arch/s390/kernel/time.c | 8 ++++---- drivers/s390/cio/chsc.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-)
arch/s390/include/asm/cio.h +1 -1
@@ -369,7 +369,7 @@ void cio_gp_dma_destroy(struct gen_poolstruct gen_pool *cio_gp_dma_create (struct device *dma_dev,int nr_pages);/* Function from drivers/s390/cio/chsc.c */ -int chsc_sstpc (void *page,unsigned int op,u16 ctrl,u64 *clock_delta); +int chsc_sstpc (void *page,unsigned int op,u16 ctrl,long *clock_delta);int chsc_sstpi (void *page,void *result,size_t size);int chsc_stzi (void *page,void *result,size_t size);int chsc_sgib (u32 origin);
arch/s390/kernel/time.c +4 -4
@@ -364,7 +364,7 @@ static inline int check_sync_clock(void)* Apply clock delta to the global data structures. * This is called once on the CPU that performed the clock sync. */ -static void clock_sync_global (unsigned long delta) +static void clock_sync_global (long delta) {unsigned long now, adj;struct ptff_qto qto;
@@ -400,7 +400,7 @@ static void clock_sync_global(unsigned l* Apply clock delta to the per-CPU data structures of this CPU. * This is called for each online CPU after the call to clock_sync_global. */ -static void clock_sync_local (unsigned long delta) +static void clock_sync_local (long delta) {/* Add the delta to the clock comparator. */ if (S390_lowcore.clock_comparator != clock_comparator_max) {
@@ -424,7 +424,7 @@ static void __init time_init_wq(void)struct clock_sync_data {atomic_t cpus;int in_sync; -unsigned long clock_delta; +long clock_delta; };/*
@@ -544,7 +544,7 @@ static int stpinfo_valid(void)static int stp_sync_clock (void *data) {struct clock_sync_data *sync = data; -u64 clock_delta, flags; +long clock_delta, flags;static int first;int rc;
drivers/s390/cio/chsc.c +2 -2
@@ -1255,7 +1255,7 @@ exit:EXPORT_SYMBOL_GPL (css_general_characteristics);EXPORT_SYMBOL_GPL (css_chsc_characteristics); -int chsc_sstpc (void *page,unsigned int op,u16 ctrl,u64 *clock_delta) +int chsc_sstpc (void *page,unsigned int op,u16 ctrl,long *clock_delta) {struct {struct chsc_header request;
@@ -1266,7 +1266,7 @@ int chsc_sstpc(void *page, unsigned intunsigned int rsvd2[5 ];struct chsc_header response;unsigned int rsvd3[3 ]; -u64 clock_delta; +s64 clock_delta;unsigned int rsvd4[2 ]; } *rr;int rc;
Greg Kroah-Hartman
maintainerPATCH 763/879 dlm: fix plock invalid read
In reply to Greg Kroah-HartmanFrom: Alexander Aring <[email protected]>
commit 42252d0d2aa9b94d168241710a761588b3959019 upstream.
This patch fixes an invalid read showed by KASAN. A unlock will allocate a "struct plock_op" and a followed send_op() will append it to a global send_list data structure. In some cases a followed dev_read() moves it to recv_list and dev_write() will cast it to "struct plock_xop" and access fields which are only available in those structures. At this point an invalid read happens by accessing those fields.
To fix this issue the "callback" field is moved to "struct plock_op" to indicate that a cast to "plock_xop" is allowed and does the additional "plock_xop" handling if set.
Example of the KASAN output which showed the invalid read:
[ 2064.296453] ================================================================== [ 2064.304852] BUG: KASAN: slab-out-of-bounds in dev_write+0x52b/0x5a0 [dlm] [ 2064.306491] Read of size 8 at addr ffff88800ef227d8 by task dlm_controld/7484 [ 2064.308168] [ 2064.308575] CPU: 0 PID: 7484 Comm: dlm_controld Kdump: loaded Not tainted 5.14.0+ #9 [ 2064.310292] Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 [ 2064.311618] Call Trace: [ 2064.312218] dump_stack_lvl+0x56/0x7b [ 2064.313150] print_address_description.constprop.8+0x21/0x150 [ 2064.314578] ? dev_write+0x52b/0x5a0 [dlm] [ 2064.315610] ? dev_write+0x52b/0x5a0 [dlm] [ 2064.316595] kasan_report.cold.14+0x7f/0x11b [ 2064.317674] ? dev_write+0x52b/0x5a0 [dlm] [ 2064.318687] dev_write+0x52b/0x5a0 [dlm] [ 2064.319629] ? dev_read+0x4a0/0x4a0 [dlm] [ 2064.320713] ? bpf_lsm_kernfs_init_security+0x10/0x10 [ 2064.321926] vfs_write+0x17e/0x930 [ 2064.322769] ? __fget_light+0x1aa/0x220 [ 2064.323753] ksys_write+0xf1/0x1c0 [ 2064.324548] ? __ia32_sys_read+0xb0/0xb0 [ 2064.325464] do_syscall_64+0x3a/0x80 [ 2064.326387] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 2064.327606] RIP: 0033:0x7f807e4ba96f [ 2064.328470] Code: 89 54 24 18 48 89 74 24 10 89 7c 24 08 e8 39 87 f8 ff 48 8b 54 24 18 48 8b 74 24 10 41 89 c0 8b 7c 24 08 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 31 44 89 c7 48 89 44 24 08 e8 7c 87 f8 ff 48 [ 2064.332902] RSP: 002b:00007ffd50cfe6e0 EFLAGS: 00000293 ORIG_RAX: 0000000000000001 [ 2064.334658] RAX: ffffffffffffffda RBX: 000055cc3886eb30 RCX: 00007f807e4ba96f [ 2064.336275] RDX: 0000000000000040 RSI: 00007ffd50cfe7e0 RDI: 0000000000000010 [ 2064.337980] RBP: 00007ffd50cfe7e0 R08: 0000000000000000 R09: 0000000000000001 [ 2064.339560] R10: 000055cc3886eb30 R11: 0000000000000293 R12: 000055cc3886eb80 [ 2064.341237] R13: 000055cc3886eb00 R14: 000055cc3886f590 R15: 0000000000000001 [ 2064.342857] [ 2064.343226] Allocated by task 12438: [ 2064.344057] kasan_save_stack+0x1c/0x40 [ 2064.345079] __kasan_kmalloc+0x84/0xa0 [ 2064.345933] kmem_cache_alloc_trace+0x13b/0x220 [ 2064.346953] dlm_posix_unlock+0xec/0x720 [dlm] [ 2064.348811] do_lock_file_wait.part.32+0xca/0x1d0 [ 2064.351070] fcntl_setlk+0x281/0xbc0 [ 2064.352879] do_fcntl+0x5e4/0xfe0 [ 2064.354657] __x64_sys_fcntl+0x11f/0x170 [ 2064.356550] do_syscall_64+0x3a/0x80 [ 2064.358259] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 2064.360745] [ 2064.361511] Last potentially related work creation: [ 2064.363957] kasan_save_stack+0x1c/0x40 [ 2064.365811] __kasan_record_aux_stack+0xaf/0xc0 [ 2064.368100] call_rcu+0x11b/0xf70 [ 2064.369785] dlm_process_incoming_buffer+0x47d/0xfd0 [dlm] [ 2064.372404] receive_from_sock+0x290/0x770 [dlm] [ 2064.374607] process_recv_sockets+0x32/0x40 [dlm] [ 2064.377290] process_one_work+0x9a8/0x16e0 [ 2064.379357] worker_thread+0x87/0xbf0 [ 2064.381188] kthread+0x3ac/0x490 [ 2064.383460] ret_from_fork+0x22/0x30 [ 2064.385588] [ 2064.386518] Second to last potentially related work creation: [ 2064.389219] kasan_save_stack+0x1c/0x40 [ 2064.391043] __kasan_record_aux_stack+0xaf/0xc0 [ 2064.393303] call_rcu+0x11b/0xf70 [ 2064.394885] dlm_process_incoming_buffer+0x47d/0xfd0 [dlm] [ 2064.397694] receive_from_sock+0x290/0x770 [dlm] [ 2064.399932] process_recv_sockets+0x32/0x40 [dlm] [ 2064.402180] process_one_work+0x9a8/0x16e0 [ 2064.404388] worker_thread+0x87/0xbf0 [ 2064.406124] kthread+0x3ac/0x490 [ 2064.408021] ret_from_fork+0x22/0x30 [ 2064.409834] [ 2064.410599] The buggy address belongs to the object at ffff88800ef22780 [ 2064.410599] which belongs to the cache kmalloc-96 of size 96 [ 2064.416495] The buggy address is located 88 bytes inside of [ 2064.416495] 96-byte region [ffff88800ef22780, ffff88800ef227e0) [ 2064.422045] The buggy address belongs to the page: [ 2064.424635] page:00000000b6bef8bc refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0xef22 [ 2064.428970] flags: 0xfffffc0000200(slab|node=0|zone=1|lastcpupid=0x1fffff) [ 2064.432515] raw: 000fffffc0000200 ffffea0000d68b80 0000001400000014 ffff888001041780 [ 2064.436110] raw: 0000000000000000 0000000080200020 00000001ffffffff 0000000000000000 [ 2064.439813] page dumped because: kasan: bad access detected [ 2064.442548] [ 2064.443310] Memory state around the buggy address: [ 2064.445988] ffff88800ef22680: 00 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc [ 2064.449444] ffff88800ef22700: 00 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc [ 2064.452941] >ffff88800ef22780: 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc fc [ 2064.456383] ^ [ 2064.459386] ffff88800ef22800: 00 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc [ 2064.462788] ffff88800ef22880: 00 00 00 00 00 00 00 00 00 00 00 00 fc fc fc fc [ 2064.466239] ==================================================================
reproducer in python:
import argparse
import struct
import fcntl
import os
parser = argparse.ArgumentParser()
parser.add_argument('-f', '--file',
help='file to use fcntl, must be on dlm lock filesystem e.g. gfs2')
args = parser.parse_args()
f = open(args.file, 'wb+')
lockdata = struct.pack('hhllhh', fcntl.F_WRLCK,0,0,0,0,0) fcntl.fcntl(f, fcntl.F_SETLK, lockdata)
lockdata = struct.pack('hhllhh', fcntl.F_UNLCK,0,0,0,0,0) fcntl.fcntl(f, fcntl.F_SETLK, lockdata)
--- fs/dlm/plock.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
fs/dlm/plock.c +5 -7
@@ -23,11 +23,11 @@ struct plock_op {struct list_head list;int done;struct dlm_plock_info info; +int (*callback)(struct file_lock *fl,int result); };struct plock_xop {struct plock_op xop; -int (*callback)(struct file_lock *fl,int result);void *fl;void *file;struct file_lock flc;
@@ -129,19 +129,18 @@ int dlm_posix_lock(dlm_lockspace_t *lock/* fl_owner is lockd which doesn't distinguish processes on the nfs client */ op->info.owner = (__u64 ) fl->fl_pid; - xop->callback = fl->fl_lmops->lm_grant; + op->callback = fl->fl_lmops->lm_grant;locks_init_lock (&xop->flc);locks_copy_lock (&xop->flc, fl); xop->fl = fl; xop->file = file; }else { op->info.owner = (__u64 )(long ) fl->fl_owner; - xop->callback =NULL ; }send_op (op); -if (xop->callback ==NULL ) { +if (!op->callback) { rv =wait_event_interruptible (recv_wq, (op->done !=0 ));if (rv == -ERESTARTSYS ) { log_debug(ls, "dlm_posix_lock: wait killed %llx",
@@ -203,7 +202,7 @@ static int dlm_plock_callback(struct plo file = xop->file; flc = &xop->flc; fl = xop->fl; - notify = xop->callback; + notify = op->callback;if (op->info.rv) {notify (fl, op->info.rv);
@@ -436,10 +435,9 @@ static ssize_t dev_write(struct file *fiif (op->info.fsid == info.fsid && op->info.number == info.number && op->info.owner == info.owner) { -struct plock_xop *xop = (struct plock_xop *)op;list_del_init (&op->list);memcpy (&op->info, &info,sizeof (info)); -if (xop->callback) +if (op->callback) do_callback =1 ;else op->done =1 ;
Greg Kroah-Hartman
maintainerPATCH 764/879 dlm: uninitialized variable on error in dlm_listen_for_all()
In reply to Greg Kroah-HartmanFrom: Dan Carpenter <[email protected]>
commit 1f4f10845e14690b02410de50d9ea9684625a4ae upstream.
The "sock" variable is not initialized on this error path.
--- fs/dlm/lowcomms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/dlm/lowcomms.c +1 -1
@@ -1789,7 +1789,7 @@ static int dlm_listen_for_all(void) SOCK_STREAM, dlm_proto_ops->proto, &sock);if (result <0 ) {log_print ("Can't create comms socket: %d" , result); - goto out; +return result; }sock_set_mark (sock->sk, dlm_config.ci_mark);
Greg Kroah-Hartman
maintainerPATCH 765/879 dlm: fix wake_up() calls for pending remove
In reply to Greg Kroah-HartmanFrom: Alexander Aring <[email protected]>
commit f6f7418357457ed58cbb020fc97e74d4e0e7b47f upstream.
This patch move the wake_up() call at the point when a remove message completed. Before it was only when a remove message was going to be sent. The possible waiter in wait_pending_remove() waits until a remove is done if the resource name matches with the per ls variable ls->ls_remove_name. If this is the case we must wait until a pending remove is done which is indicated if DLM_WAIT_PENDING_COND() returns false which will always be the case when ls_remove_len and ls_remove_name are unset to indicate that a remove is not going on anymore.
--- fs/dlm/lock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/dlm/lock.c +2 -2
@@ -1795,7 +1795,6 @@ static void shrink_bucket(struct dlm_lsmemcpy (ls->ls_remove_name, name,DLM_RESNAME_MAXLEN );spin_unlock (&ls->ls_remove_spin);spin_unlock (&ls->ls_rsbtbl[b].lock); -wake_up (&ls->ls_remove_wait);send_remove (r);
@@ -1804,6 +1803,7 @@ static void shrink_bucket(struct dlm_ls ls->ls_remove_len =0 ;memset (ls->ls_remove_name,0 ,DLM_RESNAME_MAXLEN );spin_unlock (&ls->ls_remove_spin); +wake_up (&ls->ls_remove_wait);dlm_free_rsb (r); }
@@ -4079,7 +4079,6 @@ static void send_repeat_remove(struct dlmemcpy (ls->ls_remove_name, name,DLM_RESNAME_MAXLEN );spin_unlock (&ls->ls_remove_spin);spin_unlock (&ls->ls_rsbtbl[b].lock); -wake_up (&ls->ls_remove_wait); rv =_create_message (ls,sizeof (struct dlm_message ) + len, dir_nodeid,DLM_MSG_REMOVE , &ms, &mh);
@@ -4095,6 +4094,7 @@ static void send_repeat_remove(struct dl ls->ls_remove_len =0 ;memset (ls->ls_remove_name,0 ,DLM_RESNAME_MAXLEN );spin_unlock (&ls->ls_remove_spin); +wake_up (&ls->ls_remove_wait); }static int receive_request (struct dlm_ls *ls,struct dlm_message *ms)
Greg Kroah-Hartman
maintainerPATCH 766/879 dlm: fix missing lkb refcount handling
In reply to Greg Kroah-HartmanFrom: Alexander Aring <[email protected]>
commit 1689c169134f4b5a39156122d799b7dca76d8ddb upstream.
We always call hold_lkb(lkb) if we increment lkb->lkb_wait_count. So, we always need to call unhold_lkb(lkb) if we decrement lkb->lkb_wait_count. This patch will add missing unhold_lkb(lkb) if we decrement lkb->lkb_wait_count. In case of setting lkb->lkb_wait_count to zero we need to countdown until reaching zero and call unhold_lkb(lkb). The waiters list unhold_lkb(lkb) can be removed because it's done for the last lkb_wait_count decrement iteration as it's done in _remove_from_waiters().
This issue was discovered by a dlm gfs2 test case which use excessively dlm_unlock(LKF_CANCEL) feature. Probably the lkb->lkb_wait_count value never reached above 1 if this feature isn't used and so it was not discovered before.
The testcase ended in a rsb on the rsb keep data structure with a refcount of 1 but no lkb was associated with it, which is itself an invalid behaviour. A side effect of that was a condition in which the dlm was sending remove messages in a looping behaviour. With this patch that has not been reproduced.
--- fs/dlm/lock.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
fs/dlm/lock.c +9 -2
@@ -1559,6 +1559,7 @@ static int _remove_from_waiters(struct d lkb->lkb_wait_type =0 ; lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL ; lkb->lkb_wait_count--; +unhold_lkb (lkb); goto out_del; }
@@ -1585,6 +1586,7 @@ static int _remove_from_waiters(struct dlog_error (ls,"remwait error %x reply %d wait_type %d overlap" , lkb->lkb_id, mstype, lkb->lkb_wait_type); lkb->lkb_wait_count--; +unhold_lkb (lkb); lkb->lkb_wait_type =0 ; }
@@ -5331,11 +5333,16 @@ int dlm_recover_waiters_post(struct dlm_ lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK ; lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL ; lkb->lkb_wait_type =0 ; - lkb->lkb_wait_count =0 ; +/* drop all wait_count references we still +* hold a reference for this iteration. +*/ +while (lkb->lkb_wait_count) { + lkb->lkb_wait_count--; +unhold_lkb (lkb); + }mutex_lock (&ls->ls_waiters_mutex);list_del_init (&lkb->lkb_wait_reply);mutex_unlock (&ls->ls_waiters_mutex); -unhold_lkb (lkb);/* for waiters list */ if (oc || ou) {/* do an unlock or cancel instead of resending */
Greg Kroah-Hartman
maintainerPATCH 767/879 ocfs2: dlmfs: fix error handling of user_dlm_destroy_lock
In reply to Greg Kroah-HartmanFrom: Junxiao Bi via Ocfs2-devel <[email protected]>
commit 863e0d81b6683c4cbc588ad831f560c90e494bef upstream.
When user_dlm_destroy_lock failed, it didn't clean up the flags it set before exit. For USER_LOCK_IN_TEARDOWN, if this function fails because of lock is still in used, next time when unlink invokes this function, it will return succeed, and then unlink will remove inode and dentry if lock is not in used(file closed), but the dlm lock is still linked in dlm lock resource, then when bast come in, it will trigger a panic due to user-after-free. See the following panic call trace. To fix this, USER_LOCK_IN_TEARDOWN should be reverted if fail. And also error should be returned if USER_LOCK_IN_TEARDOWN is set to let user know that unlink fail.
For the case of ocfs2_dlm_unlock failure, besides USER_LOCK_IN_TEARDOWN, USER_LOCK_BUSY is also required to be cleared. Even though spin lock is released in between, but USER_LOCK_IN_TEARDOWN is still set, for USER_LOCK_BUSY, if before every place that waits on this flag, USER_LOCK_IN_TEARDOWN is checked to bail out, that will make sure no flow waits on the busy flag set by user_dlm_destroy_lock(), then we can simplely revert USER_LOCK_BUSY when ocfs2_dlm_unlock fails. Fix user_dlm_cluster_lock() which is the only function not following this.
[ 941.336392] (python,26174,16):dlmfs_unlink:562 ERROR: unlink 004fb0000060000b5a90b8c847b72e1, error -16 from destroy [ 989.757536] ------------[ cut here ]------------ [ 989.757709] kernel BUG at fs/ocfs2/dlmfs/userdlm.c:173! [ 989.757876] invalid opcode: 0000 [#1] SMP [ 989.758027] Modules linked in: ksplice_2zhuk2jr_ib_ipoib_new(O)
ksplice_2zhuk2jr(O) mptctl mptbase xen_netback xen_blkback xen_gntalloc xen_gntdev xen_evtchn cdc_ether usbnet mii ocfs2 jbd2 rpcsec_gss_krb5 auth_rpcgss nfsv4 nfsv3 nfs_acl nfs fscache lockd grace ocfs2_dlmfs ocfs2_stack_o2cb ocfs2_dlm ocfs2_nodemanager ocfs2_stackglue configfs bnx2fc fcoe libfcoe libfc scsi_transport_fc sunrpc ipmi_devintf bridge stp llc rds_rdma rds bonding ib_sdp ib_ipoib rdma_ucm ib_ucm ib_uverbs ib_umad rdma_cm ib_cm iw_cm falcon_lsm_serviceable(PE) falcon_nf_netcontain(PE) mlx4_vnic falcon_kal(E) falcon_lsm_pinned_13402(E) mlx4_ib ib_sa ib_mad ib_core ib_addr xenfs xen_privcmd dm_multipath iTCO_wdt iTCO_vendor_support pcspkr sb_edac edac_core i2c_i801 lpc_ich mfd_core ipmi_ssif i2c_core ipmi_si ipmi_msghandler
[ 989.760686] ioatdma sg ext3 jbd mbcache sd_mod ahci libahci ixgbe dca ptp
pps_core vxlan udp_tunnel ip6_udp_tunnel megaraid_sas mlx4_core crc32c_intel be2iscsi bnx2i cnic uio cxgb4i cxgb4 cxgb3i libcxgbi ipv6 cxgb3 mdio libiscsi_tcp qla4xxx iscsi_boot_sysfs libiscsi scsi_transport_iscsi wmi dm_mirror dm_region_hash dm_log dm_mod [last unloaded:ksplice_2zhuk2jr_ib_ipoib_old]
[ 989.761987] CPU: 10 PID: 19102 Comm: dlm_thread Tainted: P OE 4.1.12-124.57.1.el6uek.x86_64 #2 [ 989.762290] Hardware name: Oracle Corporation ORACLE SERVER X5-2/ASM,MOTHERBOARD,1U, BIOS 30350100 06/17/2021 [ 989.762599] task: ffff880178af6200 ti: ffff88017f7c8000 task.ti: ffff88017f7c8000 [ 989.762848] RIP: e030:[<ffffffffc07d4316>] [<ffffffffc07d4316>] __user_dlm_queue_lockres.part.4+0x76/0x80 [ocfs2_dlmfs] [ 989.763185] RSP: e02b:ffff88017f7cbcb8 EFLAGS: 00010246 [ 989.763353] RAX: 0000000000000000 RBX: ffff880174d48008 RCX: 0000000000000003 [ 989.763565] RDX: 0000000000120012 RSI: 0000000000000003 RDI: ffff880174d48170 [ 989.763778] RBP: ffff88017f7cbcc8 R08: ffff88021f4293b0 R09: 0000000000000000 [ 989.763991] R10: ffff880179c8c000 R11: 0000000000000003 R12: ffff880174d48008 [ 989.764204] R13: 0000000000000003 R14: ffff880179c8c000 R15: ffff88021db7a000 [ 989.764422] FS: 0000000000000000(0000) GS:ffff880247480000(0000) knlGS:ffff880247480000 [ 989.764685] CS: e033 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 989.764865] CR2: ffff8000007f6800 CR3: 0000000001ae0000 CR4: 0000000000042660 [ 989.765081] Stack: [ 989.765167] 0000000000000003 ffff880174d48040 ffff88017f7cbd18 ffffffffc07d455f [ 989.765442] ffff88017f7cbd88 ffffffff816fb639 ffff88017f7cbd38 ffff8800361b5600 [ 989.765717] ffff88021db7a000 ffff88021f429380 0000000000000003 ffffffffc0453020 [ 989.765991] Call Trace: [ 989.766093] [<ffffffffc07d455f>] user_bast+0x5f/0xf0 [ocfs2_dlmfs] [ 989.766287] [<ffffffff816fb639>] ? schedule_timeout+0x169/0x2d0 [ 989.766475] [<ffffffffc0453020>] ? o2dlm_lock_ast_wrapper+0x20/0x20 [ocfs2_stack_o2cb] [ 989.766738] [<ffffffffc045303a>] o2dlm_blocking_ast_wrapper+0x1a/0x20 [ocfs2_stack_o2cb] [ 989.767010] [<ffffffffc0864ec6>] dlm_do_local_bast+0x46/0xe0 [ocfs2_dlm] [ 989.767217] [<ffffffffc084f5cc>] ? dlm_lockres_calc_usage+0x4c/0x60 [ocfs2_dlm] [ 989.767466] [<ffffffffc08501f1>] dlm_thread+0xa31/0x1140 [ocfs2_dlm] [ 989.767662] [<ffffffff816f78da>] ? __schedule+0x24a/0x810 [ 989.767834] [<ffffffff816f78ce>] ? __schedule+0x23e/0x810 [ 989.768006] [<ffffffff816f78da>] ? __schedule+0x24a/0x810 [ 989.768178] [<ffffffff816f78ce>] ? __schedule+0x23e/0x810 [ 989.768349] [<ffffffff816f78da>] ? __schedule+0x24a/0x810 [ 989.768521] [<ffffffff816f78ce>] ? __schedule+0x23e/0x810 [ 989.768693] [<ffffffff816f78da>] ? __schedule+0x24a/0x810 [ 989.768893] [<ffffffff816f78ce>] ? __schedule+0x23e/0x810 [ 989.769067] [<ffffffff816f78da>] ? __schedule+0x24a/0x810 [ 989.769241] [<ffffffff810ce4d0>] ? wait_woken+0x90/0x90 [ 989.769411] [<ffffffffc084f7c0>] ? dlm_kick_thread+0x80/0x80 [ocfs2_dlm] [ 989.769617] [<ffffffff810a8bbb>] kthread+0xcb/0xf0 [ 989.769774] [<ffffffff816f78da>] ? __schedule+0x24a/0x810 [ 989.769945] [<ffffffff816f78da>] ? __schedule+0x24a/0x810 [ 989.770117] [<ffffffff810a8af0>] ? kthread_create_on_node+0x180/0x180 [ 989.770321] [<ffffffff816fdaa1>] ret_from_fork+0x61/0x90 [ 989.770492] [<ffffffff810a8af0>] ? kthread_create_on_node+0x180/0x180 [ 989.770689] Code: d0 00 00 00 f0 45 7d c0 bf 00 20 00 00 48 89 83 c0 00 00 00 48 89 83 c8 00 00 00 e8 55 c1 8c c0 83 4b 04 10 48 83 c4 08 5b 5d c3 <0f> 0b 0f 1f 84 00 00 00 00 00 55 48 89 e5 41 55 41 54 53 48 83 [ 989.771892] RIP [<ffffffffc07d4316>] __user_dlm_queue_lockres.part.4+0x76/0x80 [ocfs2_dlmfs] [ 989.772174] RSP <ffff88017f7cbcb8> [ 989.772704] ---[ end trace ebd1e38cebcc93a8 ]--- [ 989.772907] Kernel panic - not syncing: Fatal exception [ 989.773173] Kernel Offset: disabled
--- fs/ocfs2/dlmfs/userdlm.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
fs/ocfs2/dlmfs/userdlm.c +15 -1
@@ -433,6 +433,11 @@ again: }spin_lock (&lockres->l_lock); +if (lockres->l_flags &USER_LOCK_IN_TEARDOWN ) { +spin_unlock (&lockres->l_lock); + status = -EAGAIN ; + goto bail; + }/* We only compare against the currently granted level * here. If the lock is blocked waiting on a downconvert,
@@ -595,7 +600,7 @@ int user_dlm_destroy_lock(struct user_lospin_lock (&lockres->l_lock);if (lockres->l_flags &USER_LOCK_IN_TEARDOWN ) {spin_unlock (&lockres->l_lock); -return 0 ; + goto bail; } lockres->l_flags |=USER_LOCK_IN_TEARDOWN ;
@@ -609,12 +614,17 @@ int user_dlm_destroy_lock(struct user_lo }if (lockres->l_ro_holders || lockres->l_ex_holders) { + lockres->l_flags &= ~USER_LOCK_IN_TEARDOWN ;spin_unlock (&lockres->l_lock); goto bail; } status =0 ;if (!(lockres->l_flags &USER_LOCK_ATTACHED )) { +/* +* lock is never requested, leave USER_LOCK_IN_TEARDOWN set +* to avoid new lock request coming in. +*/ spin_unlock (&lockres->l_lock); goto bail; }
@@ -625,6 +635,10 @@ int user_dlm_destroy_lock(struct user_lo status =ocfs2_dlm_unlock (conn, &lockres->l_lksb,DLM_LKF_VALBLK );if (status) { +spin_lock (&lockres->l_lock); + lockres->l_flags &= ~USER_LOCK_IN_TEARDOWN ; + lockres->l_flags &= ~USER_LOCK_BUSY ; +spin_unlock (&lockres->l_lock);user_log_dlm_error ("ocfs2_dlm_unlock" , status, lockres); goto bail; }
Greg Kroah-Hartman
maintainerPATCH 768/879 scsi: dc395x: Fix a missing check on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 036a45aa587a10fa2abbd50fbd0f6c4cfc44f69f upstream.
The bug is here:
p->target_id, p->target_lun);
The list iterator 'p' will point to a bogus position containing HEAD if the list is empty or no element is found. This case must be checked before any use of the iterator, otherwise it will lead to an invalid memory access.
To fix this bug, add a check. Use a new variable 'iter' as the list iterator, and use the original variable 'p' as a dedicated pointer to point to the found element.
--- drivers/scsi/dc395x.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/scsi/dc395x.c +12 -3
@@ -3585,10 +3585,19 @@ static struct DeviceCtlBlk *device_alloc#endif if (dcb->target_lun !=0 ) {/* Copy settings */ -struct DeviceCtlBlk *p; -list_for_each_entry (p, &acb->dcb_list, list) -if (p->target_id == dcb->target_id) +struct DeviceCtlBlk *p =NULL , *iter; + +list_for_each_entry (iter, &acb->dcb_list, list) +if (iter->target_id == dcb->target_id) { + p = iter;break ; + } + +if (!p) { +kfree (dcb); +return NULL ; + } + dprintkdbg(DBG_1, "device_alloc: <%02i-%i> copy from <%02i-%i>\n", dcb->target_id, dcb->target_lun,
Greg Kroah-Hartman
maintainerPATCH 769/879 scsi: ufs: qcom: Add a readl() to make sure ref_clk gets enabled
In reply to Greg Kroah-HartmanFrom: Manivannan Sadhasivam <[email protected]>
commit 8eecddfca30e1651dc1c74531ed5eef21dcce7e3 upstream.
In ufs_qcom_dev_ref_clk_ctrl(), it was noted that the ref_clk needs to be stable for at least 1us. Even though there is wmb() to make sure the write gets "completed", there is no guarantee that the write actually reached the UFS device. There is a good chance that the write could be stored in a Write Buffer (WB). In that case, even though the CPU waits for 1us, the ref_clk might not be stable for that period.
So lets do a readl() to make sure that the previous write has reached the UFS device before udelay().
Also, the wmb() after writel_relaxed() is not really needed. Both writel() and readl() are ordered on all architectures and the CPU won't speculate instructions after readl() due to the in-built control dependency with read value on weakly ordered architectures. So it can be safely removed.
--- drivers/scsi/ufs/ufs-qcom.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/scsi/ufs/ufs-qcom.c +5 -2
@@ -682,8 +682,11 @@ static void ufs_qcom_dev_ref_clk_ctrl(stwritel_relaxed (temp, host->dev_ref_clk_ctrl_mmio); -/* ensure that ref_clk is enabled/disabled before we return */ -wmb (); +/* +* Make sure the write to ref_clk reaches the destination and +* not stored in a Write Buffer (WB). +*/ +readl (host->dev_ref_clk_ctrl_mmio);/* * If we call hibern8 exit after this, we need to make sure that
Greg Kroah-Hartman
maintainerPATCH 770/879 landlock: Add clang-format exceptions
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 6cc2df8e3a3967e7c13a424f87f6efb1d4a62d80 upstream.
In preparation to a following commit, add clang-format on and clang-format off stanzas around constant definitions. This enables to keep aligned values, which is much more readable than packed definitions.
--- include/uapi/linux/landlock.h | 4 ++++ security/landlock/fs.c | 2 ++ security/landlock/limits.h | 4 ++++ 3 files changed, 10 insertions(+)
include/uapi/linux/landlock.h +4 -0
@@ -33,7 +33,9 @@ struct landlock_ruleset_attr {* - %LANDLOCK_CREATE_RULESET_VERSION: Get the highest supported Landlock ABI * version. */ +/* clang-format off */ #define LANDLOCK_CREATE_RULESET_VERSION (1U << 0) +/* clang-format on */ /** * enum landlock_rule_type - Landlock rule type
@@ -120,6 +122,7 @@ struct landlock_path_beneath_attr {* :manpage:`access(2)`. * Future Landlock evolutions will enable to restrict them. */ +/* clang-format off */ #define LANDLOCK_ACCESS_FS_EXECUTE (1ULL << 0)#define LANDLOCK_ACCESS_FS_WRITE_FILE (1ULL << 1)#define LANDLOCK_ACCESS_FS_READ_FILE (1ULL << 2)
@@ -133,5 +136,6 @@ struct landlock_path_beneath_attr {#define LANDLOCK_ACCESS_FS_MAKE_FIFO (1ULL << 10)#define LANDLOCK_ACCESS_FS_MAKE_BLOCK (1ULL << 11)#define LANDLOCK_ACCESS_FS_MAKE_SYM (1ULL << 12) +/* clang-format on */ #endif /* _UAPI_LINUX_LANDLOCK_H */
security/landlock/fs.c +2 -0
@@ -141,10 +141,12 @@ retry: }/* All access rights that can be tied to files. */ +/* clang-format off */ #define ACCESS_FILE ( \ LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_WRITE_FILE | \ LANDLOCK_ACCESS_FS_READ_FILE) +/* clang-format on */ /* * @path: Should have been checked by get_path_from_fd().
security/landlock/limits.h +4 -0
@@ -12,10 +12,14 @@#include <linux/limits.h> #include <uapi/linux/landlock.h> +/* clang-format off */ +#define LANDLOCK_MAX_NUM_LAYERS 64#define LANDLOCK_MAX_NUM_RULES U32_MAX#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_MAKE_SYM#define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1) +/* clang-format on */ +#endif /* _SECURITY_LANDLOCK_LIMITS_H */
Greg Kroah-Hartman
maintainerPATCH 771/879 landlock: Format with clang-format
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 06a1c40a09a8dded4bf0e7e3ccbda6bddcccd7c8 upstream.
Let's follow a consistent and documented coding style. Everything may not be to our liking but it is better than tacit knowledge. Moreover, this will help maintain style consistency between different developers.
This contains only whitespace changes.
Automatically formatted with:
clang-format-14 -i security/landlock/*.[ch] include/uapi/linux/landlock.h
--- security/landlock/cred.c | 4 +- security/landlock/cred.h | 8 ++-- security/landlock/fs.c | 78 +++++++++++++++++++++-------------------- security/landlock/fs.h | 11 +++-- security/landlock/object.c | 6 +-- security/landlock/object.h | 6 +-- security/landlock/ptrace.c | 10 ++--- security/landlock/ruleset.c | 80 +++++++++++++++++++++---------------------- security/landlock/ruleset.h | 15 ++++---- security/landlock/syscalls.c | 60 ++++++++++++++++---------------- 10 files changed, 142 insertions(+), 136 deletions(-)
security/landlock/cred.c +2 -2
@@ -15,7 +15,7 @@#include "setup.h" static int hook_cred_prepare (struct cred *const new, -const struct cred *const old,const gfp_t gfp) +const struct cred *const old,const gfp_t gfp) {struct landlock_ruleset *const old_dom =landlock_cred (old)->domain;
@@ -42,5 +42,5 @@ static struct security_hook_list landloc__init void landlock_add_cred_hooks (void ) {security_add_hooks (landlock_hooks,ARRAY_SIZE (landlock_hooks), -LANDLOCK_NAME ); +LANDLOCK_NAME ); }
security/landlock/cred.h +4 -4
@@ -20,8 +20,8 @@ struct landlock_cred_security {struct landlock_ruleset *domain; }; -static inline struct landlock_cred_security *landlock_cred ( -const struct cred *cred) +static inline struct landlock_cred_security * +landlock_cred (const struct cred *cred) {return cred->security + landlock_blob_sizes.lbs_cred; }
@@ -34,8 +34,8 @@ static inline const struct landlock_rule/* * The call needs to come from an RCU read-side critical section. */ -static inline const struct landlock_ruleset *landlock_get_task_domain ( -const struct task_struct *const task) +static inline const struct landlock_ruleset * +landlock_get_task_domain (const struct task_struct *const task) {return landlock_cred (__task_cred (task))->domain; }
security/landlock/fs.c +40 -38
205 lines not on this page · raw message
security/landlock/fs.h +6 -5
@@ -50,14 +50,14 @@ struct landlock_superblock_security {atomic_long_t inode_refs; }; -static inline struct landlock_inode_security *landlock_inode ( -const struct inode *const inode) +static inline struct landlock_inode_security * +landlock_inode (const struct inode *const inode) {return inode->i_security + landlock_blob_sizes.lbs_inode; } -static inline struct landlock_superblock_security *landlock_superblock ( -const struct super_block *const superblock) +static inline struct landlock_superblock_security * +landlock_superblock (const struct super_block *const superblock) {return superblock->s_security + landlock_blob_sizes.lbs_superblock; }
@@ -65,6 +65,7 @@ static inline struct landlock_superblock__init void landlock_add_fs_hooks (void );int landlock_append_fs_rule (struct landlock_ruleset *const ruleset, -const struct path *const path,u32 access_hierarchy); +const struct path *const path, +u32 access_hierarchy);#endif /* _SECURITY_LANDLOCK_FS_H */
security/landlock/object.c +3 -3
@@ -17,9 +17,9 @@#include "object.h" -struct landlock_object *landlock_create_object ( -const struct landlock_object_underops *const underops, -void *const underobj) +struct landlock_object * +landlock_create_object (const struct landlock_object_underops *const underops, +void *const underobj) {struct landlock_object *new_object;
security/landlock/object.h +3 -3
@@ -76,9 +76,9 @@ struct landlock_object { }; }; -struct landlock_object *landlock_create_object ( -const struct landlock_object_underops *const underops, -void *const underobj); +struct landlock_object * +landlock_create_object (const struct landlock_object_underops *const underops, +void *const underobj);void landlock_put_object (struct landlock_object *const object);
security/landlock/ptrace.c +5 -5
@@ -30,7 +30,7 @@* means a subset of) the @child domain. */ static bool domain_scope_le (const struct landlock_ruleset *const parent, -const struct landlock_ruleset *const child) +const struct landlock_ruleset *const child) {const struct landlock_hierarchy *walker;
@@ -48,7 +48,7 @@ static bool domain_scope_le(const struct }static bool task_is_scoped (const struct task_struct *const parent, -const struct task_struct *const child) +const struct task_struct *const child) {bool is_scoped;const struct landlock_ruleset *dom_parent, *dom_child;
@@ -62,7 +62,7 @@ static bool task_is_scoped(const struct }static int task_ptrace (const struct task_struct *const parent, -const struct task_struct *const child) +const struct task_struct *const child) {/* Quick return for non-landlocked tasks. */ if (!landlocked (parent))
@@ -86,7 +86,7 @@ static int task_ptrace(const struct task* granted, -errno if denied. */ static int hook_ptrace_access_check (struct task_struct *const child, -const unsigned int mode) +const unsigned int mode) {return task_ptrace (current, child); }
@@ -116,5 +116,5 @@ static struct security_hook_list landloc__init void landlock_add_ptrace_hooks (void ) {security_add_hooks (landlock_hooks,ARRAY_SIZE (landlock_hooks), -LANDLOCK_NAME ); +LANDLOCK_NAME ); }
security/landlock/ruleset.c +40 -40
200 lines not on this page · raw message
security/landlock/ruleset.h +8 -7
@@ -146,15 +146,16 @@ void landlock_put_ruleset(struct landlocvoid landlock_put_ruleset_deferred (struct landlock_ruleset *const ruleset);int landlock_insert_rule (struct landlock_ruleset *const ruleset, -struct landlock_object *const object,const u32 access); +struct landlock_object *const object, +const u32 access); -struct landlock_ruleset *landlock_merge_ruleset ( -struct landlock_ruleset *const parent, -struct landlock_ruleset *const ruleset); +struct landlock_ruleset * +landlock_merge_ruleset (struct landlock_ruleset *const parent, +struct landlock_ruleset *const ruleset); -const struct landlock_rule *landlock_find_rule ( -const struct landlock_ruleset *const ruleset, -const struct landlock_object *const object); +const struct landlock_rule * +landlock_find_rule (const struct landlock_ruleset *const ruleset, +const struct landlock_object *const object);static inline void landlock_get_ruleset (struct landlock_ruleset *const ruleset) {
security/landlock/syscalls.c +31 -29
167 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 772/879 selftests/landlock: Add clang-format exceptions
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 4598d9abf4215e1e371a35683350d50122793c80 upstream.
In preparation to a following commit, add clang-format on and clang-format off stanzas around constant definitions and the TEST_F_FORK macro. This enables to keep aligned values, which is much more readable than packed definitions.
Add other clang-format exceptions for FIXTURE() and FIXTURE_VARIANT_ADD() declarations to force space before open brace, which is reported by checkpatch.pl .
--- tools/testing/selftests/landlock/common.h | 2 ++ tools/testing/selftests/landlock/fs_test.c | 23 +++++++++++++++++------ tools/testing/selftests/landlock/ptrace_test.c | 20 +++++++++++++++++++- 3 files changed, 38 insertions(+), 7 deletions(-)
tools/testing/selftests/landlock/common.h +2 -0
@@ -25,6 +25,7 @@* this to be possible, we must not call abort() but instead exit smoothly * (hence the step print). */ +/* clang-format off */ #define TEST_F_FORK (fixture_name, test_name) \ static void fixture_name##_##test_name##_child( \ struct __test_metadata *_metadata, \
@@ -71,6 +72,7 @@FIXTURE_DATA (fixture_name) __attribute__((unused)) *self, \ const FIXTURE_VARIANT(fixture_name) \ __attribute__((unused)) *variant) +/* clang-format on */ #ifndef landlock_create_ruleset static inline int landlock_create_ruleset(
tools/testing/selftests/landlock/fs_test.c +17 -6
@@ -221,8 +221,9 @@ static void remove_layout1(struct __testEXPECT_EQ (0 ,remove_path (dir_s3d2)); } -FIXTURE (layout1) { -}; +/* clang-format off */ +FIXTURE (layout1) {}; +/* clang-format on */ FIXTURE_SETUP (layout1) {
@@ -376,6 +377,8 @@ TEST_F_FORK(layout1, inval)ASSERT_EQ (0 ,close (ruleset_fd)); } +/* clang-format off */ +#define ACCESS_FILE ( \ LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_WRITE_FILE | \
@@ -396,6 +399,8 @@ TEST_F_FORK(layout1, inval) LANDLOCK_ACCESS_FS_MAKE_BLOCK | \ ACCESS_LAST) +/* clang-format on */ + TEST_F_FORK(layout1, file_access_rights) {__u64 access;
@@ -452,6 +457,8 @@ struct rule {__u64 access; }; +/* clang-format off */ +#define ACCESS_RO ( \ LANDLOCK_ACCESS_FS_READ_FILE | \ LANDLOCK_ACCESS_FS_READ_DIR)
@@ -460,6 +467,8 @@ struct rule { ACCESS_RO | \ LANDLOCK_ACCESS_FS_WRITE_FILE) +/* clang-format on */ +static int create_ruleset (struct __test_metadata *const _metadata,const __u64 handled_access_fs,const struct rule rules[]) {
@@ -2070,8 +2079,9 @@ TEST_F_FORK(layout1, proc_pipe)ASSERT_EQ (0 ,close (pipe_fds[1 ])); } -FIXTURE (layout1_bind) { -}; +/* clang-format off */ +FIXTURE (layout1_bind) {}; +/* clang-format on */ FIXTURE_SETUP (layout1_bind) {
@@ -2411,8 +2421,9 @@ static const char (*merge_sub_files[])[]* └── work */ -FIXTURE (layout2_overlay) { -}; +/* clang-format off */ +FIXTURE (layout2_overlay) {}; +/* clang-format on */ FIXTURE_SETUP (layout2_overlay) {
tools/testing/selftests/landlock/ptrace_test.c +19 -1
@@ -59,7 +59,9 @@ static int test_ptrace_read(const pid_treturn 0 ; } -FIXTURE (hierarchy) { }; +/* clang-format off */ +FIXTURE (hierarchy) {}; +/* clang-format on */ FIXTURE_VARIANT (hierarchy) {const bool domain_both;
@@ -83,7 +85,9 @@ FIXTURE_VARIANT(hierarchy) {* \ P2 -> P1 : allow * 'P2 */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, allow_without_domain) { +/* clang-format on */ .domain_both = false, .domain_parent = false, .domain_child = false,
@@ -98,7 +102,9 @@ FIXTURE_VARIANT_ADD(hierarchy, allow_wit* | P2 | * '------' */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, allow_with_one_domain) { +/* clang-format on */ .domain_both = false, .domain_parent = false, .domain_child = true,
@@ -112,7 +118,9 @@ FIXTURE_VARIANT_ADD(hierarchy, allow_wit* ' * P2 */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, deny_with_parent_domain) { +/* clang-format on */ .domain_both = false, .domain_parent = true, .domain_child = false,
@@ -127,7 +135,9 @@ FIXTURE_VARIANT_ADD(hierarchy, deny_with* | P2 | * '------' */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, deny_with_sibling_domain) { +/* clang-format on */ .domain_both = false, .domain_parent = true, .domain_child = true,
@@ -142,7 +152,9 @@ FIXTURE_VARIANT_ADD(hierarchy, deny_with* | P2 | * '-------------' */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, allow_sibling_domain) { +/* clang-format on */ .domain_both = true, .domain_parent = false, .domain_child = false,
@@ -158,7 +170,9 @@ FIXTURE_VARIANT_ADD(hierarchy, allow_sib* | '------' | * '-----------------' */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, allow_with_nested_domain) { +/* clang-format on */ .domain_both = true, .domain_parent = false, .domain_child = true,
@@ -174,7 +188,9 @@ FIXTURE_VARIANT_ADD(hierarchy, allow_wit* | P2 | * '-----------------' */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, deny_with_nested_and_parent_domain) { +/* clang-format on */ .domain_both = true, .domain_parent = true, .domain_child = false,
@@ -192,7 +208,9 @@ FIXTURE_VARIANT_ADD(hierarchy, deny_with* | '------' | * '-----------------' */ +/* clang-format off */ FIXTURE_VARIANT_ADD(hierarchy, deny_with_forked_domain) { +/* clang-format on */ .domain_both = true, .domain_parent = true, .domain_child = true,
Greg Kroah-Hartman
maintainerPATCH 773/879 selftests/landlock: Normalize array assignment
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 135464f9d29c5b306d7201220f1d00dab30fea89 upstream.
Add a comma after each array value to make clang-format keep the current array formatting. See the following commit.
Automatically modified with:
sed -i 's/\t\({}\|NULL\)$/\0,/' tools/testing/selftests/landlock/fs_test.c
--- tools/testing/selftests/landlock/fs_test.c | 112 ++++++++++++++--------------- 1 file changed, 56 insertions(+), 56 deletions(-)
tools/testing/selftests/landlock/fs_test.c +56 -56
@@ -514,7 +514,7 @@ TEST_F_FORK(layout1, proc_nsfs) .access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };struct landlock_path_beneath_attr path_beneath; const int ruleset_fd = create_ruleset(_metadata, rules[0].access |
@@ -560,7 +560,7 @@ TEST_F_FORK(layout1, unpriv) { .path = dir_s1d2, .access = ACCESS_RO, }, - {} + {}, };int ruleset_fd;
@@ -588,7 +588,7 @@ TEST_F_FORK(layout1, effective_access) .access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);char buf;
@@ -635,7 +635,7 @@ TEST_F_FORK(layout1, unhandled_access) .path = dir_s1d2, .access = ACCESS_RO, }, - {} + {}, };/* Here, we only handle read accesses, not write accesses. */ const int ruleset_fd =create_ruleset (_metadata,ACCESS_RO , rules);
@@ -669,7 +669,7 @@ TEST_F_FORK(layout1, ruleset_overlap) .access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -703,14 +703,14 @@ TEST_F_FORK(layout1, non_overlapping_acc .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_MAKE_REG, }, - {} + {}, };const struct rule layer2[] = { { .path = dir_s1d3, .access =LANDLOCK_ACCESS_FS_REMOVE_FILE , }, - {} + {}, };int ruleset_fd;
@@ -767,7 +767,7 @@ TEST_F_FORK(layout1, interleaved_masked_ .path = file1_s1d3, .access = LANDLOCK_ACCESS_FS_READ_FILE, }, - {} + {}, };/* First rule with write restrictions. */ const struct rule layer2_read_write[] = {
@@ -782,7 +782,7 @@ TEST_F_FORK(layout1, interleaved_masked_ .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };const struct rule layer3_read[] = { /* Allows read access via its great-grandparent directory. */
@@ -790,7 +790,7 @@ TEST_F_FORK(layout1, interleaved_masked_ .path = dir_s1d1, .access = LANDLOCK_ACCESS_FS_READ_FILE, }, - {} + {}, };const struct rule layer4_read_write[] = {/*
@@ -801,7 +801,7 @@ TEST_F_FORK(layout1, interleaved_masked_ .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_READ_FILE, }, - {} + {}, };const struct rule layer5_read[] = {/*
@@ -812,7 +812,7 @@ TEST_F_FORK(layout1, interleaved_masked_ .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_READ_FILE, }, - {} + {}, };const struct rule layer6_execute[] = {/*
@@ -823,7 +823,7 @@ TEST_F_FORK(layout1, interleaved_masked_ .path = dir_s2d1, .access = LANDLOCK_ACCESS_FS_EXECUTE, }, - {} + {}, };const struct rule layer7_read_write[] = {/*
@@ -834,7 +834,7 @@ TEST_F_FORK(layout1, interleaved_masked_ .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };int ruleset_fd;
@@ -932,7 +932,7 @@ TEST_F_FORK(layout1, inherit_subset) .access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1048,7 +1048,7 @@ TEST_F_FORK(layout1, inherit_superset) .path = dir_s1d3, .access = ACCESS_RO, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1084,7 +1084,7 @@ TEST_F_FORK(layout1, max_layers) .path = dir_s1d2, .access = ACCESS_RO, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1146,7 +1146,7 @@ TEST_F_FORK(layout1, rule_on_mountpoint) .path = dir_s3d2, .access = ACCESS_RO, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1175,7 +1175,7 @@ TEST_F_FORK(layout1, rule_over_mountpoin .path = dir_s3d1, .access = ACCESS_RO, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1203,7 +1203,7 @@ TEST_F_FORK(layout1, rule_over_root_allo .path = "/", .access = ACCESS_RO, }, - {} + {}, };int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1233,7 +1233,7 @@ TEST_F_FORK(layout1, rule_over_root_deny .path = "/", .access = LANDLOCK_ACCESS_FS_READ_FILE, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1253,7 +1253,7 @@ TEST_F_FORK(layout1, rule_inside_mount_n .path = "s3d3", .access = ACCESS_RO, }, - {} + {}, };int ruleset_fd;
@@ -1280,7 +1280,7 @@ TEST_F_FORK(layout1, mount_and_pivot) .path = dir_s3d2, .access = ACCESS_RO, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1303,7 +1303,7 @@ TEST_F_FORK(layout1, move_mount) .path = dir_s3d2, .access = ACCESS_RO, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1344,7 +1344,7 @@ TEST_F_FORK(layout1, release_inodes) .path = dir_s3d3, .access = ACCESS_RO, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);
@@ -1382,7 +1382,7 @@ static void test_relative_path(struct __ .path = TMP_DIR, .access = ACCESS_RO, }, - {} + {}, };const struct rule layer2_subs[] = { {
@@ -1393,7 +1393,7 @@ static void test_relative_path(struct __ .path = dir_s2d2, .access = ACCESS_RO, }, - {} + {}, };int dirfd, ruleset_fd;
@@ -1558,7 +1558,7 @@ TEST_F_FORK(layout1, execute) .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_EXECUTE, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1591,7 +1591,7 @@ TEST_F_FORK(layout1, link) .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_MAKE_REG, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1628,7 +1628,7 @@ TEST_F_FORK(layout1, rename_file) .path = dir_s2d2, .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1705,7 +1705,7 @@ TEST_F_FORK(layout1, rename_dir) .path = dir_s2d1, .access = LANDLOCK_ACCESS_FS_REMOVE_DIR, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1759,7 +1759,7 @@ TEST_F_FORK(layout1, remove_dir) .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_REMOVE_DIR, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1796,7 +1796,7 @@ TEST_F_FORK(layout1, remove_file) .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_REMOVE_FILE, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1821,7 +1821,7 @@ static void test_make_file(struct __test .path = dir_s1d2, .access = access, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, access, rules);
@@ -1907,7 +1907,7 @@ TEST_F_FORK(layout1, make_sym) .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_MAKE_SYM, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1952,7 +1952,7 @@ TEST_F_FORK(layout1, make_dir) .path = dir_s1d2, .access = LANDLOCK_ACCESS_FS_MAKE_DIR, }, - {} + {}, };const int ruleset_fd =create_ruleset (_metadata, rules[0 ].access, rules);
@@ -1992,7 +1992,7 @@ TEST_F_FORK(layout1, proc_unlinked_file) .path = file1_s1d2, .access = LANDLOCK_ACCESS_FS_READ_FILE, }, - {} + {}, };int reg_fd, proc_fd; const int ruleset_fd = create_ruleset(_metadata,
@@ -2034,7 +2034,7 @@ TEST_F_FORK(layout1, proc_pipe) .access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };/* Limits read and write access to files tied to the filesystem. */ const int ruleset_fd = create_ruleset(_metadata, rules[0].access,
@@ -2171,7 +2171,7 @@ TEST_F_FORK(layout1_bind, same_content_s .path = dir_s2d1, .access = ACCESS_RW, }, - {} + {}, };/* * Sets access rights on the same bind-mounted directories. The result
@@ -2187,7 +2187,7 @@ TEST_F_FORK(layout1_bind, same_content_s .path = dir_s2d2, .access = ACCESS_RW, }, - {} + {}, };/* Only allow read-access to the s1d3 hierarchies. */ const struct rule layer3_source[] = {
@@ -2195,7 +2195,7 @@ TEST_F_FORK(layout1_bind, same_content_s .path = dir_s1d3, .access = LANDLOCK_ACCESS_FS_READ_FILE, }, - {} + {}, };/* Removes all access rights. */ const struct rule layer4_destination[] = {
@@ -2203,7 +2203,7 @@ TEST_F_FORK(layout1_bind, same_content_s .path = bind_file1_s1d3, .access = LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };int ruleset_fd;
@@ -2305,18 +2305,18 @@ static const char lower_do1_fl3[] = LOWEstatic const char (*lower_base_files[])[] = { &lower_fl1, &lower_fo1, -NULL +NULL , };static const char (*lower_base_directories[])[] = { &lower_dl1, &lower_do1, -NULL +NULL , };static const char (*lower_sub_files[])[] = { &lower_dl1_fl2, &lower_do1_fo2, &lower_do1_fl3, -NULL +NULL , };#define UPPER_BASE TMP_DIR "/upper"
@@ -2333,18 +2333,18 @@ static const char upper_do1_fu3[] = UPPEstatic const char (*upper_base_files[])[] = { &upper_fu1, &upper_fo1, -NULL +NULL , };static const char (*upper_base_directories[])[] = { &upper_du1, &upper_do1, -NULL +NULL , };static const char (*upper_sub_files[])[] = { &upper_du1_fu2, &upper_do1_fo2, &upper_do1_fu3, -NULL +NULL , };#define MERGE_BASE TMP_DIR "/merge"
@@ -2365,13 +2365,13 @@ static const char (*merge_base_files[])[ &merge_fl1, &merge_fu1, &merge_fo1, -NULL + NULL, };static const char (*merge_base_directories[])[] = { &merge_dl1, &merge_du1, &merge_do1, -NULL +NULL , };static const char (*merge_sub_files[])[] = { &merge_dl1_fl2,
@@ -2379,7 +2379,7 @@ static const char (*merge_sub_files[])[] &merge_do1_fo2, &merge_do1_fl3, &merge_do1_fu3, - NULL + NULL, };/*
@@ -2544,7 +2544,7 @@ TEST_F_FORK(layout2_overlay, same_conten .path = MERGE_BASE, .access = ACCESS_RW, }, - {} + {}, };const struct rule layer2_data[] = { {
@@ -2559,7 +2559,7 @@ TEST_F_FORK(layout2_overlay, same_conten .path = MERGE_DATA, .access = ACCESS_RW, }, - {} + {}, };/* Sets access right on directories inside both layers. */ const struct rule layer3_subdirs[] = {
@@ -2591,7 +2591,7 @@ TEST_F_FORK(layout2_overlay, same_conten .path = merge_do1, .access = ACCESS_RW, }, - {} + {}, };/* Tighten access rights to the files. */ const struct rule layer4_files[] = {
@@ -2644,7 +2644,7 @@ TEST_F_FORK(layout2_overlay, same_conten .access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };const struct rule layer5_merge_only[] = { {
@@ -2652,7 +2652,7 @@ TEST_F_FORK(layout2_overlay, same_conten .access = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, }, - {} + {}, };int ruleset_fd;size_t i;
Greg Kroah-Hartman
maintainerPATCH 774/879 selftests/landlock: Format with clang-format
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 371183fa578a4cf56b3ae12e54b7f01a4249add1 upstream.
Let's follow a consistent and documented coding style. Everything may not be to our liking but it is better than tacit knowledge. Moreover, this will help maintain style consistency between different developers.
This contains only whitespace changes.
Automatically formatted with:
clang-format-14 -i tools/testing/selftests/landlock/*.[ch]
[mic: Update style according to
https://lore.kernel.org/r/[email protected]]
--- tools/testing/selftests/landlock/base_test.c | 80 ++--- tools/testing/selftests/landlock/common.h | 64 ++-- tools/testing/selftests/landlock/fs_test.c | 399 +++++++++++++------------ tools/testing/selftests/landlock/ptrace_test.c | 20 - 4 files changed, 312 insertions(+), 251 deletions(-)
tools/testing/selftests/landlock/base_test.c +46 -34
@@ -18,10 +18,11 @@#include "common.h" #ifndef O_PATH -#define O_PATH 010000000 +#define O_PATH 010000000#endif -TEST (inconsistent_attr) { +TEST (inconsistent_attr) +{const long page_size =sysconf (_SC_PAGESIZE);char *const buf =malloc (page_size +1 );struct landlock_ruleset_attr *const ruleset_attr = (void *)buf;
@@ -39,15 +40,16 @@ TEST(inconsistent_attr) {/* The size if less than sizeof(struct landlock_attr_enforce). */ ASSERT_EQ (EFAULT , errno); -ASSERT_EQ (-1 ,landlock_create_ruleset (NULL , -sizeof (struct landlock_ruleset_attr ),0 )); +ASSERT_EQ (-1 ,landlock_create_ruleset ( +NULL ,sizeof (struct landlock_ruleset_attr ),0 ));ASSERT_EQ (EFAULT , errno);ASSERT_EQ (-1 ,landlock_create_ruleset (ruleset_attr, page_size +1 ,0 ));ASSERT_EQ (E2BIG , errno); -ASSERT_EQ (-1 ,landlock_create_ruleset (ruleset_attr, -sizeof (struct landlock_ruleset_attr ),0 )); +ASSERT_EQ (-1 ,landlock_create_ruleset ( + ruleset_attr, +sizeof (struct landlock_ruleset_attr ),0 ));ASSERT_EQ (ENOMSG , errno);ASSERT_EQ (-1 ,landlock_create_ruleset (ruleset_attr, page_size,0 ));ASSERT_EQ (ENOMSG , errno);
@@ -63,32 +65,35 @@ TEST(inconsistent_attr) {free (buf); } -TEST (abi_version) { +TEST (abi_version) +{const struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs =LANDLOCK_ACCESS_FS_READ_FILE , };ASSERT_EQ (1 ,landlock_create_ruleset (NULL ,0 , -LANDLOCK_CREATE_RULESET_VERSION )); +LANDLOCK_CREATE_RULESET_VERSION ));ASSERT_EQ (-1 ,landlock_create_ruleset (&ruleset_attr,0 , -LANDLOCK_CREATE_RULESET_VERSION )); +LANDLOCK_CREATE_RULESET_VERSION ));ASSERT_EQ (EINVAL , errno);ASSERT_EQ (-1 ,landlock_create_ruleset (NULL ,sizeof (ruleset_attr), -LANDLOCK_CREATE_RULESET_VERSION )); +LANDLOCK_CREATE_RULESET_VERSION ));ASSERT_EQ (EINVAL , errno); -ASSERT_EQ (-1 ,landlock_create_ruleset (&ruleset_attr, -sizeof (ruleset_attr), -LANDLOCK_CREATE_RULESET_VERSION )); +ASSERT_EQ (-1 , +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr), +LANDLOCK_CREATE_RULESET_VERSION ));ASSERT_EQ (EINVAL , errno);ASSERT_EQ (-1 ,landlock_create_ruleset (NULL ,0 , -LANDLOCK_CREATE_RULESET_VERSION |1 <<31 )); +LANDLOCK_CREATE_RULESET_VERSION | +1 <<31 ));ASSERT_EQ (EINVAL , errno); } -TEST (inval_create_ruleset_flags) { +TEST (inval_create_ruleset_flags) +{const int last_flag =LANDLOCK_CREATE_RULESET_VERSION ;const int invalid_flag = last_flag <<1 ;const struct landlock_ruleset_attr ruleset_attr = {
@@ -102,38 +107,42 @@ TEST(inval_create_ruleset_flags) {ASSERT_EQ (EINVAL , errno);ASSERT_EQ (-1 ,landlock_create_ruleset (NULL ,sizeof (ruleset_attr), - invalid_flag)); + invalid_flag));ASSERT_EQ (EINVAL , errno); -ASSERT_EQ (-1 ,landlock_create_ruleset (&ruleset_attr, -sizeof (ruleset_attr), invalid_flag)); +ASSERT_EQ (-1 , +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr), + invalid_flag));ASSERT_EQ (EINVAL , errno); } -TEST (empty_path_beneath_attr) { +TEST (empty_path_beneath_attr) +{const struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs =LANDLOCK_ACCESS_FS_EXECUTE , }; -const int ruleset_fd =landlock_create_ruleset (&ruleset_attr, -sizeof (ruleset_attr),0 ); +const int ruleset_fd = +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 );ASSERT_LE (0 , ruleset_fd);/* Similar to struct landlock_path_beneath_attr.parent_fd = 0 */ ASSERT_EQ (-1 ,landlock_add_rule (ruleset_fd,LANDLOCK_RULE_PATH_BENEATH , -NULL ,0 )); +NULL ,0 ));ASSERT_EQ (EFAULT , errno);ASSERT_EQ (0 ,close (ruleset_fd)); } -TEST (inval_fd_enforce) { +TEST (inval_fd_enforce) +{ASSERT_EQ (0 ,prctl (PR_SET_NO_NEW_PRIVS ,1 ,0 ,0 ,0 ));ASSERT_EQ (-1 ,landlock_restrict_self (-1 ,0 ));ASSERT_EQ (EBADF , errno); } -TEST (unpriv_enforce_without_no_new_privs) { +TEST (unpriv_enforce_without_no_new_privs) +{int err;drop_caps (_metadata);
@@ -151,8 +160,8 @@ TEST(ruleset_fd_io)char buf;drop_caps (_metadata); - ruleset_fd =landlock_create_ruleset (&ruleset_attr, -sizeof (ruleset_attr),0 ); + ruleset_fd = +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 );ASSERT_LE (0 , ruleset_fd);ASSERT_EQ (-1 ,write (ruleset_fd,"." ,1 ));
@@ -197,14 +206,15 @@ TEST(ruleset_fd_transfer)drop_caps (_metadata);/* Creates a test ruleset with a simple rule. */ - ruleset_fd_tx =landlock_create_ruleset (&ruleset_attr, -sizeof (ruleset_attr),0 ); + ruleset_fd_tx = +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 );ASSERT_LE (0 , ruleset_fd_tx); - path_beneath_attr.parent_fd =open ("/tmp" ,O_PATH |O_NOFOLLOW | -O_DIRECTORY |O_CLOEXEC ); + path_beneath_attr.parent_fd = +open ("/tmp" ,O_PATH |O_NOFOLLOW |O_DIRECTORY |O_CLOEXEC );ASSERT_LE (0 , path_beneath_attr.parent_fd); -ASSERT_EQ (0 ,landlock_add_rule (ruleset_fd_tx,LANDLOCK_RULE_PATH_BENEATH , - &path_beneath_attr,0 )); +ASSERT_EQ (0 , +landlock_add_rule (ruleset_fd_tx,LANDLOCK_RULE_PATH_BENEATH , + &path_beneath_attr,0 ));ASSERT_EQ (0 ,close (path_beneath_attr.parent_fd)); cmsg =CMSG_FIRSTHDR (&msg);
@@ -215,7 +225,8 @@ TEST(ruleset_fd_transfer)memcpy (CMSG_DATA (cmsg), &ruleset_fd_tx,sizeof (ruleset_fd_tx));/* Sends the ruleset FD over a socketpair and then close it. */ -ASSERT_EQ (0 ,socketpair (AF_UNIX ,SOCK_STREAM |SOCK_CLOEXEC ,0 , socket_fds)); +ASSERT_EQ (0 ,socketpair (AF_UNIX ,SOCK_STREAM |SOCK_CLOEXEC ,0 , + socket_fds));ASSERT_EQ (sizeof (data_tx),sendmsg (socket_fds[0 ], &msg,0 ));ASSERT_EQ (0 ,close (socket_fds[0 ]));ASSERT_EQ (0 ,close (ruleset_fd_tx));
@@ -226,7 +237,8 @@ TEST(ruleset_fd_transfer)int ruleset_fd_rx; *(char *)msg.msg_iov->iov_base ='\0' ; -ASSERT_EQ (sizeof (data_tx),recvmsg (socket_fds[1 ], &msg,MSG_CMSG_CLOEXEC )); +ASSERT_EQ (sizeof (data_tx), +recvmsg (socket_fds[1 ], &msg,MSG_CMSG_CLOEXEC ));ASSERT_EQ ('.' , *(char *)msg.msg_iov->iov_base);ASSERT_EQ (0 ,close (socket_fds[1 ])); cmsg =CMSG_FIRSTHDR (&msg);
tools/testing/selftests/landlock/common.h +36 -28
131 lines not on this page · raw message
tools/testing/selftests/landlock/fs_test.c +218 -181
1,021 lines not on this page · raw message
tools/testing/selftests/landlock/ptrace_test.c +12 -8
@@ -26,9 +26,10 @@ static void create_domain(struct __test_ .handled_access_fs = LANDLOCK_ACCESS_FS_MAKE_BLOCK, }; - ruleset_fd =landlock_create_ruleset (&ruleset_attr, -sizeof (ruleset_attr),0 ); - EXPECT_LE(0, ruleset_fd) { + ruleset_fd = +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 ); + EXPECT_LE(0, ruleset_fd) + {TH_LOG ("Failed to create a ruleset: %s" ,strerror (errno)); }EXPECT_EQ (0 ,prctl (PR_SET_NO_NEW_PRIVS ,1 ,0 ,0 ,0 ));
@@ -43,7 +44,7 @@ static int test_ptrace_read(const pid_tint procenv_path_size, fd; procenv_path_size =snprintf (procenv_path,sizeof (procenv_path), - path_template, pid); + path_template, pid);if (procenv_path_size >=sizeof (procenv_path))return E2BIG ;
@@ -63,7 +64,8 @@ static int test_ptrace_read(const pid_tFIXTURE (hierarchy) {};/* clang-format on */ -FIXTURE_VARIANT (hierarchy) { +FIXTURE_VARIANT (hierarchy) +{const bool domain_both;const bool domain_parent;const bool domain_child;
@@ -217,10 +219,12 @@ FIXTURE_VARIANT_ADD(hierarchy, deny_with };FIXTURE_SETUP (hierarchy) -{ } +{ +}FIXTURE_TEARDOWN (hierarchy) -{ } +{ +}/* Test PTRACE_TRACEME and PTRACE_ATTACH for parent and child. */ TEST_F (hierarchy, trace)
@@ -348,7 +352,7 @@ TEST_F(hierarchy, trace)ASSERT_EQ (1 ,write (pipe_parent[1 ],"." ,1 ));ASSERT_EQ (child,waitpid (child, &status,0 ));if (WIFSIGNALED (status) || !WIFEXITED (status) || -WEXITSTATUS (status) !=EXIT_SUCCESS ) +WEXITSTATUS (status) !=EXIT_SUCCESS ) _metadata->passed =0 ; }
Greg Kroah-Hartman
maintainerPATCH 775/879 samples/landlock: Add clang-format exceptions
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 9805a722db071e1772b80e6e0ff33f35355639ac upstream.
In preparation to a following commit, add clang-format on and clang-format off stanzas around constant definitions. This enables to keep aligned values, which is much more readable than packed definitions.
--- samples/landlock/sandboxer.c | 8 ++++++++ 1 file changed, 8 insertions(+)
samples/landlock/sandboxer.c +8 -0
@@ -70,11 +70,15 @@ static int parse_path(char *env_path, coreturn num_paths; } +/* clang-format off */ +#define ACCESS_FILE ( \ LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_WRITE_FILE | \ LANDLOCK_ACCESS_FS_READ_FILE) +/* clang-format on */ +static int populate_ruleset (const char *const env_var,const int ruleset_fd,const __u64 allowed_access)
@@ -139,6 +143,8 @@ out_free_name:return ret; } +/* clang-format off */ +#define ACCESS_FS_ROUGHLY_READ ( \ LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_READ_FILE | \
@@ -156,6 +162,8 @@ out_free_name: LANDLOCK_ACCESS_FS_MAKE_BLOCK | \ LANDLOCK_ACCESS_FS_MAKE_SYM) +/* clang-format on */ +int main (const int argc,char *const argv[],char *const *const envp) {const char *cmd_path;
Greg Kroah-Hartman
maintainerPATCH 776/879 samples/landlock: Format with clang-format
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 81709f3dccacf4104a4bc2daa80bdd767a9c4c54 upstream.
Let's follow a consistent and documented coding style. Everything may not be to our liking but it is better than tacit knowledge. Moreover, this will help maintain style consistency between different developers.
This contains only whitespace changes.
Automatically formatted with:
clang-format-14 -i samples/landlock/*.[ch]
--- samples/landlock/sandboxer.c | 96 +++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 44 deletions(-)
samples/landlock/sandboxer.c +52 -44
@@ -22,9 +22,9 @@#include <unistd.h> #ifndef landlock_create_ruleset -static inline int landlock_create_ruleset ( -const struct landlock_ruleset_attr *const attr, -const size_t size,const __u32 flags) +static inline int +landlock_create_ruleset (const struct landlock_ruleset_attr *const attr, +const size_t size,const __u32 flags) {return syscall (__NR_landlock_create_ruleset, attr, size, flags); }
@@ -32,17 +32,18 @@ static inline int landlock_create_rulese#ifndef landlock_add_rulestatic inline int landlock_add_rule (const int ruleset_fd, -const enum landlock_rule_type rule_type, -const void *const rule_attr,const __u32 flags) +const enum landlock_rule_type rule_type, +const void *const rule_attr, +const __u32 flags) { -return syscall (__NR_landlock_add_rule, ruleset_fd, rule_type, - rule_attr, flags); +return syscall (__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr, + flags); }#endif #ifndef landlock_restrict_selfstatic inline int landlock_restrict_self (const int ruleset_fd, -const __u32 flags) +const __u32 flags) {return syscall (__NR_landlock_restrict_self, ruleset_fd, flags); }
@@ -79,9 +80,8 @@ static int parse_path(char *env_path, co/* clang-format on */ -static int populate_ruleset ( -const char *const env_var,const int ruleset_fd, -const __u64 allowed_access) +static int populate_ruleset (const char *const env_var,const int ruleset_fd, +const __u64 allowed_access) {int num_paths, i, ret =1 ;char *env_path_name;
@@ -111,12 +111,10 @@ static int populate_ruleset(for (i =0 ; i < num_paths; i++) {struct stat statbuf; - path_beneath.parent_fd =open (path_list[i],O_PATH | -O_CLOEXEC ); + path_beneath.parent_fd =open (path_list[i],O_PATH |O_CLOEXEC );if (path_beneath.parent_fd <0 ) {fprintf (stderr,"Failed to open \"%s\": %s\n" , - path_list[i], -strerror (errno)); + path_list[i],strerror (errno)); goto out_free_name; }if (fstat (path_beneath.parent_fd, &statbuf)) {
@@ -127,9 +125,10 @@ static int populate_ruleset(if (!S_ISDIR (statbuf.st_mode)) path_beneath.allowed_access &=ACCESS_FILE ;if (landlock_add_rule (ruleset_fd,LANDLOCK_RULE_PATH_BENEATH , - &path_beneath,0 )) { -fprintf (stderr,"Failed to update the ruleset with \"%s\": %s\n" , - path_list[i],strerror (errno)); + &path_beneath,0 )) { +fprintf (stderr, +"Failed to update the ruleset with \"%s\": %s\n" , + path_list[i],strerror (errno));close (path_beneath.parent_fd); goto out_free_name; }
@@ -171,55 +170,64 @@ int main(const int argc, char *const argint ruleset_fd;struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs =ACCESS_FS_ROUGHLY_READ | -ACCESS_FS_ROUGHLY_WRITE , +ACCESS_FS_ROUGHLY_WRITE , };if (argc <2 ) { -fprintf (stderr,"usage: %s=\"...\" %s=\"...\" %s <cmd> [args]...\n\n" , -ENV_FS_RO_NAME ,ENV_FS_RW_NAME , argv[0 ]); -fprintf (stderr,"Launch a command in a restricted environment.\n\n" ); +fprintf (stderr, +"usage: %s=\"...\" %s=\"...\" %s <cmd> [args]...\n\n" , +ENV_FS_RO_NAME ,ENV_FS_RW_NAME , argv[0 ]); +fprintf (stderr, +"Launch a command in a restricted environment.\n\n" );fprintf (stderr,"Environment variables containing paths, " "each separated by a colon:\n" ); -fprintf (stderr,"* %s: list of paths allowed to be used in a read-only way.\n" , -ENV_FS_RO_NAME ); -fprintf (stderr,"* %s: list of paths allowed to be used in a read-write way.\n" , -ENV_FS_RW_NAME ); -fprintf (stderr,"\nexample:\n" -"%s=\"/bin:/lib:/usr:/proc:/etc:/dev/urandom\" " -"%s=\"/dev/null:/dev/full:/dev/zero:/dev/pts:/tmp\" " -"%s bash -i\n" , -ENV_FS_RO_NAME ,ENV_FS_RW_NAME , argv[0 ]); +fprintf (stderr, +"* %s: list of paths allowed to be used in a read-only way.\n" , +ENV_FS_RO_NAME ); +fprintf (stderr, +"* %s: list of paths allowed to be used in a read-write way.\n" , +ENV_FS_RW_NAME ); +fprintf (stderr, +"\nexample:\n" +"%s=\"/bin:/lib:/usr:/proc:/etc:/dev/urandom\" " +"%s=\"/dev/null:/dev/full:/dev/zero:/dev/pts:/tmp\" " +"%s bash -i\n" , +ENV_FS_RO_NAME ,ENV_FS_RW_NAME , argv[0 ]);return 1 ; } - ruleset_fd =landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 ); + ruleset_fd = +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 );if (ruleset_fd <0 ) {const int err = errno;perror ("Failed to create a ruleset" );switch (err) {case ENOSYS : -fprintf (stderr,"Hint: Landlock is not supported by the current kernel. " -"To support it, build the kernel with " -"CONFIG_SECURITY_LANDLOCK=y and prepend " -"\"landlock,\" to the content of CONFIG_LSM.\n" ); +fprintf (stderr, +"Hint: Landlock is not supported by the current kernel. " +"To support it, build the kernel with " +"CONFIG_SECURITY_LANDLOCK=y and prepend " +"\"landlock,\" to the content of CONFIG_LSM.\n" );break ;case EOPNOTSUPP : -fprintf (stderr,"Hint: Landlock is currently disabled. " -"It can be enabled in the kernel configuration by " -"prepending \"landlock,\" to the content of CONFIG_LSM, " -"or at boot time by setting the same content to the " -"\"lsm\" kernel parameter.\n" ); +fprintf (stderr, +"Hint: Landlock is currently disabled. " +"It can be enabled in the kernel configuration by " +"prepending \"landlock,\" to the content of CONFIG_LSM, " +"or at boot time by setting the same content to the " +"\"lsm\" kernel parameter.\n" );break ; }return 1 ; }if (populate_ruleset (ENV_FS_RO_NAME , ruleset_fd, -ACCESS_FS_ROUGHLY_READ )) { +ACCESS_FS_ROUGHLY_READ )) { goto err_close_ruleset; }if (populate_ruleset (ENV_FS_RW_NAME , ruleset_fd, -ACCESS_FS_ROUGHLY_READ |ACCESS_FS_ROUGHLY_WRITE )) { +ACCESS_FS_ROUGHLY_READ | +ACCESS_FS_ROUGHLY_WRITE )) { goto err_close_ruleset; }if (prctl (PR_SET_NO_NEW_PRIVS ,1 ,0 ,0 ,0 )) {
@@ -236,7 +244,7 @@ int main(const int argc, char *const arg cmd_argv = argv +1 ;execvpe (cmd_path, cmd_argv, envp);fprintf (stderr,"Failed to execute \"%s\": %s\n" , cmd_path, -strerror (errno)); +strerror (errno));fprintf (stderr,"Hint: access to the binary, the interpreter or " "shared libraries may be denied.\n" );return 1 ;
Greg Kroah-Hartman
maintainerPATCH 777/879 landlock: Fix landlock_add_rule(2) documentation
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit a13e248ff90e81e9322406c0e618cf2168702f4e upstream.
It is not mandatory to pass a file descriptor obtained with the O_PATH flag. Also, replace rule's accesses with ruleset's accesses.
--- include/uapi/linux/landlock.h | 5 +++-- security/landlock/syscalls.c | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-)
include/uapi/linux/landlock.h +3 -2
@@ -62,8 +62,9 @@ struct landlock_path_beneath_attr {*/ __u64 allowed_access;/** -* @parent_fd: File descriptor, open with ``O_PATH``, which identifies -* the parent directory of a file hierarchy, or just a file. +* @parent_fd: File descriptor, preferably opened with ``O_PATH``, +* which identifies the parent directory of a file hierarchy, or just a +* file. */ __s32 parent_fd;/*
security/landlock/syscalls.c +3 -4
@@ -292,14 +292,13 @@ out_fdput:* * - EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time; * - EINVAL: @flags is not 0, or inconsistent access in the rule (i.e. -* &landlock_path_beneath_attr.allowed_access is not a subset of the rule's -* accesses); +* &landlock_path_beneath_attr.allowed_access is not a subset of the +* ruleset handled accesses); * - ENOMSG: Empty accesses (e.g. &landlock_path_beneath_attr.allowed_access); * - EBADF: @ruleset_fd is not a file descriptor for the current thread, or a * member of @rule_attr is not a file descriptor as expected; * - EBADFD: @ruleset_fd is not a ruleset file descriptor, or a member of -* @rule_attr is not the expected file descriptor type (e.g. file open -* without O_PATH); +* @rule_attr is not the expected file descriptor type; * - EPERM: @ruleset_fd has no write access to the underlying ruleset; * - EFAULT: @rule_attr inconsistency. */
Greg Kroah-Hartman
maintainerPATCH 778/879 selftests/landlock: Make tests build with old libc
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 87129ef13603ae46c82bcd09eed948acf0506dbb upstream.
Replace SYS_<syscall> with __NR_<syscall>. Using the __NR_<syscall> notation, provided by UAPI, is useful to build tests on systems without the SYS_<syscall> definitions.
Replace SYS_pivot_root with __NR_pivot_root, and SYS_move_mount with __NR_move_mount.
Define renameat2() and RENAME_EXCHANGE if they are unknown to old build systems.
--- tools/testing/selftests/landlock/fs_test.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-)
tools/testing/selftests/landlock/fs_test.c +18 -5
@@ -22,6 +22,19 @@#include "common.h" +#ifndef renameat2 +int renameat2 (int olddirfd,const char *oldpath,int newdirfd, +const char *newpath,unsigned int flags) +{ +return syscall (__NR_renameat2, olddirfd, oldpath, newdirfd, newpath, + flags); +} +#endif + +#ifndef RENAME_EXCHANGE +#define RENAME_EXCHANGE (1 << 1) +#endif +#define TMP_DIR "tmp"#define BINARY_PATH "./true"
@@ -1279,7 +1292,7 @@ TEST_F_FORK(layout1, rule_inside_mount_nint ruleset_fd;set_cap (_metadata,CAP_SYS_ADMIN ); - ASSERT_EQ(0, syscall(SYS_pivot_root, dir_s3d2, dir_s3d3)) + ASSERT_EQ(0, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3)) {TH_LOG ("Failed to pivot root: %s" ,strerror (errno)); };
@@ -1313,7 +1326,7 @@ TEST_F_FORK(layout1, mount_and_pivot)set_cap (_metadata,CAP_SYS_ADMIN );ASSERT_EQ (-1 ,mount (NULL , dir_s3d2,NULL ,MS_RDONLY ,NULL ));ASSERT_EQ (EPERM , errno); -ASSERT_EQ (-1 ,syscall (SYS_pivot_root, dir_s3d2, dir_s3d3)); +ASSERT_EQ (-1 ,syscall (__NR_pivot_root, dir_s3d2, dir_s3d3));ASSERT_EQ (EPERM , errno);clear_cap (_metadata,CAP_SYS_ADMIN ); }
@@ -1332,13 +1345,13 @@ TEST_F_FORK(layout1, move_mount)ASSERT_LE (0 , ruleset_fd);set_cap (_metadata,CAP_SYS_ADMIN ); -ASSERT_EQ (0 ,syscall (SYS_move_mount,AT_FDCWD , dir_s3d2,AT_FDCWD , +ASSERT_EQ (0 ,syscall (__NR_move_mount,AT_FDCWD , dir_s3d2,AT_FDCWD , dir_s1d2, 0)) {TH_LOG ("Failed to move mount: %s" ,strerror (errno)); } -ASSERT_EQ (0 ,syscall (SYS_move_mount,AT_FDCWD , dir_s1d2,AT_FDCWD , +ASSERT_EQ (0 ,syscall (__NR_move_mount,AT_FDCWD , dir_s1d2,AT_FDCWD , dir_s3d2,0 ));clear_cap (_metadata,CAP_SYS_ADMIN );
@@ -1346,7 +1359,7 @@ TEST_F_FORK(layout1, move_mount)ASSERT_EQ (0 ,close (ruleset_fd));set_cap (_metadata,CAP_SYS_ADMIN ); -ASSERT_EQ (-1 ,syscall (SYS_move_mount,AT_FDCWD , dir_s3d2,AT_FDCWD , +ASSERT_EQ (-1 ,syscall (__NR_move_mount,AT_FDCWD , dir_s3d2,AT_FDCWD , dir_s1d2,0 ));ASSERT_EQ (EPERM , errno);clear_cap (_metadata,CAP_SYS_ADMIN );
Greg Kroah-Hartman
maintainerPATCH 779/879 selftests/landlock: Extend tests for minimal valid attribute size
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 291865bd7e8bb4b4033d341fa02dafa728e6378c upstream.
This might be useful when the struct landlock_ruleset_attr will get more fields.
--- tools/testing/selftests/landlock/base_test.c | 5 +++++ 1 file changed, 5 insertions(+)
tools/testing/selftests/landlock/base_test.c +5 -0
@@ -35,6 +35,8 @@ TEST(inconsistent_attr)ASSERT_EQ (EINVAL , errno);ASSERT_EQ (-1 ,landlock_create_ruleset (ruleset_attr,1 ,0 ));ASSERT_EQ (EINVAL , errno); +ASSERT_EQ (-1 ,landlock_create_ruleset (ruleset_attr,7 ,0 )); +ASSERT_EQ (EINVAL , errno);ASSERT_EQ (-1 ,landlock_create_ruleset (NULL ,1 ,0 ));/* The size if less than sizeof(struct landlock_attr_enforce). */
@@ -47,6 +49,9 @@ TEST(inconsistent_attr)ASSERT_EQ (-1 ,landlock_create_ruleset (ruleset_attr, page_size +1 ,0 ));ASSERT_EQ (E2BIG , errno); +/* Checks minimal valid attribute size. */ +ASSERT_EQ (-1 ,landlock_create_ruleset (ruleset_attr,8 ,0 )); +ASSERT_EQ (ENOMSG , errno);ASSERT_EQ (-1 ,landlock_create_ruleset ( ruleset_attr,sizeof (struct landlock_ruleset_attr ),0 ));
Greg Kroah-Hartman
maintainerPATCH 780/879 selftests/landlock: Add tests for unknown access rights
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit c56b3bf566da5a0dd3b58ad97a614b0928b06ebf upstream.
Make sure that trying to use unknown access rights returns an error.
--- tools/testing/selftests/landlock/fs_test.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
tools/testing/selftests/landlock/fs_test.c +16 -0
@@ -448,6 +448,22 @@ TEST_F_FORK(layout1, file_access_rights)ASSERT_EQ (0 ,close (path_beneath.parent_fd)); } +TEST_F_FORK(layout1, unknown_access_rights) +{ +__u64 access_mask; + +for (access_mask =1ULL <<63 ; access_mask !=ACCESS_LAST ; + access_mask >>=1 ) { +struct landlock_ruleset_attr ruleset_attr = { + .handled_access_fs = access_mask, + }; + +ASSERT_EQ (-1 ,landlock_create_ruleset (&ruleset_attr, +sizeof (ruleset_attr),0 )); +ASSERT_EQ (EINVAL , errno); + } +} +static void add_path_beneath (struct __test_metadata *const _metadata,const int ruleset_fd,const __u64 allowed_access,const char *const path)
Greg Kroah-Hartman
maintainerPATCH 781/879 selftests/landlock: Extend access right tests to directories
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit d18955d094d09a220cf8f533f5e896a2fe31575a upstream.
Make sure that all filesystem access rights can be tied to directories.
Rename layout1.file_access_rights to layout1.file_and_dir_access_rights to reflect this change.
--- tools/testing/selftests/landlock/fs_test.c | 30 +++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-)
tools/testing/selftests/landlock/fs_test.c +22 -8
@@ -418,11 +418,12 @@ TEST_F_FORK(layout1, inval)/* clang-format on */ -TEST_F_FORK(layout1, file_access_rights) +TEST_F_FORK(layout1, file_and_dir_access_rights) {__u64 access;int err; -struct landlock_path_beneath_attr path_beneath = {}; +struct landlock_path_beneath_attr path_beneath_file = {}, + path_beneath_dir = {};struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs =ACCESS_ALL , };
@@ -432,20 +433,33 @@ TEST_F_FORK(layout1, file_access_rights)ASSERT_LE (0 , ruleset_fd);/* Tests access rights for files. */ - path_beneath.parent_fd =open (file1_s1d2,O_PATH |O_CLOEXEC ); -ASSERT_LE (0 , path_beneath.parent_fd); + path_beneath_file.parent_fd =open (file1_s1d2,O_PATH |O_CLOEXEC ); +ASSERT_LE (0 , path_beneath_file.parent_fd); + +/* Tests access rights for directories. */ + path_beneath_dir.parent_fd = +open (dir_s1d2,O_PATH |O_DIRECTORY |O_CLOEXEC ); +ASSERT_LE (0 , path_beneath_dir.parent_fd); +for (access =1 ; access <=ACCESS_LAST ; access <<=1 ) { - path_beneath.allowed_access = access; + path_beneath_dir.allowed_access = access; +ASSERT_EQ (0 ,landlock_add_rule (ruleset_fd, +LANDLOCK_RULE_PATH_BENEATH , + &path_beneath_dir,0 )); + + path_beneath_file.allowed_access = access; err =landlock_add_rule (ruleset_fd,LANDLOCK_RULE_PATH_BENEATH , - &path_beneath,0 ); -if ((access |ACCESS_FILE ) ==ACCESS_FILE ) { + &path_beneath_file,0 ); +if (access &ACCESS_FILE ) {ASSERT_EQ (0 , err); }else {ASSERT_EQ (-1 , err);ASSERT_EQ (EINVAL , errno); } } -ASSERT_EQ (0 ,close (path_beneath.parent_fd)); +ASSERT_EQ (0 ,close (path_beneath_file.parent_fd)); +ASSERT_EQ (0 ,close (path_beneath_dir.parent_fd)); +ASSERT_EQ (0 ,close (ruleset_fd)); }TEST_F_FORK (layout1, unknown_access_rights)
Greg Kroah-Hartman
maintainerPATCH 782/879 selftests/landlock: Fully test file rename with "remove" access
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 6a1bdd4a0bfc30fa4fa2b3a979e6525f28996db9 upstream.
These tests were missing to check the check_access_path() call with all combinations of maybe_remove(old_dentry) and maybe_remove(new_dentry).
Extend layout1.link with a new complementary test and check that REMOVE_FILE is not required to link a file.
--- tools/testing/selftests/landlock/fs_test.c | 41 ++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-)
tools/testing/selftests/landlock/fs_test.c +37 -4
@@ -1659,15 +1659,21 @@ TEST_F_FORK(layout1, execute) TEST_F_FORK(layout1, link) { -const struct rule rules[] = { +const struct rule layer1[] = { { .path = dir_s1d2, .access =LANDLOCK_ACCESS_FS_MAKE_REG , }, {}, }; -const int ruleset_fd = -create_ruleset (_metadata, rules[0 ].access, rules); +const struct rule layer2[] = { + { + .path = dir_s1d3, + .access =LANDLOCK_ACCESS_FS_REMOVE_FILE , + }, + {}, + }; +int ruleset_fd =create_ruleset (_metadata, layer1[0 ].access, layer1);ASSERT_LE (0 , ruleset_fd);
@@ -1680,14 +1686,30 @@ TEST_F_FORK(layout1, link)ASSERT_EQ (-1 ,link (file2_s1d1, file1_s1d1));ASSERT_EQ (EACCES , errno); +/* Denies linking because of reparenting. */ ASSERT_EQ (-1 ,link (file1_s2d1, file1_s1d2));ASSERT_EQ (EXDEV , errno);ASSERT_EQ (-1 ,link (file2_s1d2, file1_s1d3));ASSERT_EQ (EXDEV , errno); +ASSERT_EQ (-1 ,link (file2_s1d3, file1_s1d2)); +ASSERT_EQ (EXDEV , errno);ASSERT_EQ (0 ,link (file2_s1d2, file1_s1d2));ASSERT_EQ (0 ,link (file2_s1d3, file1_s1d3)); + +/* Prepares for next unlinks. */ +ASSERT_EQ (0 ,unlink (file2_s1d2)); +ASSERT_EQ (0 ,unlink (file2_s1d3)); + + ruleset_fd =create_ruleset (_metadata, layer2[0 ].access, layer2); +ASSERT_LE (0 , ruleset_fd); +enforce_ruleset (_metadata, ruleset_fd); +ASSERT_EQ (0 ,close (ruleset_fd)); + +/* Checks that linkind doesn't require the ability to delete a file. */ +ASSERT_EQ (0 ,link (file1_s1d2, file2_s1d2)); +ASSERT_EQ (0 ,link (file1_s1d3, file2_s1d3)); }TEST_F_FORK (layout1, rename_file)
@@ -1708,7 +1730,6 @@ TEST_F_FORK(layout1, rename_file)ASSERT_LE (0 , ruleset_fd); -ASSERT_EQ (0 ,unlink (file1_s1d1));ASSERT_EQ (0 ,unlink (file1_s1d2));enforce_ruleset (_metadata, ruleset_fd);
@@ -1744,9 +1765,15 @@ TEST_F_FORK(layout1, rename_file)ASSERT_EQ (-1 ,renameat2 (AT_FDCWD , dir_s2d2,AT_FDCWD , file1_s2d1,RENAME_EXCHANGE ));ASSERT_EQ (EACCES , errno); +/* Checks that file1_s2d1 cannot be removed (instead of ENOTDIR). */ +ASSERT_EQ (-1 ,rename (dir_s2d2, file1_s2d1)); +ASSERT_EQ (EACCES , errno);ASSERT_EQ (-1 ,renameat2 (AT_FDCWD , file1_s2d1,AT_FDCWD , dir_s2d2,RENAME_EXCHANGE ));ASSERT_EQ (EACCES , errno); +/* Checks that file1_s1d1 cannot be removed (instead of EISDIR). */ +ASSERT_EQ (-1 ,rename (file1_s1d1, dir_s1d2)); +ASSERT_EQ (EACCES , errno);/* Renames files with different parents. */ ASSERT_EQ (-1 ,rename (file1_s2d2, file1_s1d2));
@@ -1809,9 +1836,15 @@ TEST_F_FORK(layout1, rename_dir)ASSERT_EQ (-1 ,renameat2 (AT_FDCWD , dir_s1d1,AT_FDCWD , dir_s2d1,RENAME_EXCHANGE ));ASSERT_EQ (EACCES , errno); +/* Checks that dir_s1d2 cannot be removed (instead of ENOTDIR). */ +ASSERT_EQ (-1 ,rename (dir_s1d2, file1_s1d1)); +ASSERT_EQ (EACCES , errno);ASSERT_EQ (-1 ,renameat2 (AT_FDCWD , file1_s1d1,AT_FDCWD , dir_s1d2,RENAME_EXCHANGE ));ASSERT_EQ (EACCES , errno); +/* Checks that dir_s1d2 cannot be removed (instead of EISDIR). */ +ASSERT_EQ (-1 ,rename (file1_s1d1, dir_s1d2)); +ASSERT_EQ (EACCES , errno);/* * Exchanges and renames directory to the same parent, which allows
Greg Kroah-Hartman
maintainerPATCH 783/879 selftests/landlock: Add tests for O_PATH
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit d1788ad990874734341b05ab8ccb6448c09c6422 upstream.
The O_PATH flag is currently not handled by Landlock. Let's make sure this behavior will remain consistent with the same ruleset over time.
--- tools/testing/selftests/landlock/fs_test.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
tools/testing/selftests/landlock/fs_test.c +8 -2
@@ -654,17 +654,23 @@ TEST_F_FORK(layout1, effective_access)enforce_ruleset (_metadata, ruleset_fd);ASSERT_EQ (0 ,close (ruleset_fd)); -/* Tests on a directory. */ +/* Tests on a directory (with or without O_PATH). */ ASSERT_EQ (EACCES ,test_open ("/" ,O_RDONLY )); +ASSERT_EQ (0 ,test_open ("/" ,O_RDONLY |O_PATH ));ASSERT_EQ (EACCES ,test_open (dir_s1d1,O_RDONLY )); +ASSERT_EQ (0 ,test_open (dir_s1d1,O_RDONLY |O_PATH ));ASSERT_EQ (EACCES ,test_open (file1_s1d1,O_RDONLY )); +ASSERT_EQ (0 ,test_open (file1_s1d1,O_RDONLY |O_PATH )); +ASSERT_EQ (0 ,test_open (dir_s1d2,O_RDONLY ));ASSERT_EQ (0 ,test_open (file1_s1d2,O_RDONLY ));ASSERT_EQ (0 ,test_open (dir_s1d3,O_RDONLY ));ASSERT_EQ (0 ,test_open (file1_s1d3,O_RDONLY )); -/* Tests on a file. */ +/* Tests on a file (with or without O_PATH). */ ASSERT_EQ (EACCES ,test_open (dir_s2d2,O_RDONLY )); +ASSERT_EQ (0 ,test_open (dir_s2d2,O_RDONLY |O_PATH )); +ASSERT_EQ (0 ,test_open (file1_s2d2,O_RDONLY ));/* Checks effective read and write actions. */
Greg Kroah-Hartman
maintainerPATCH 784/879 landlock: Change landlock_add_rule(2) argument check ordering
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 589172e5636c4d16c40b90e87543d43defe2d968 upstream.
This makes more sense to first check the ruleset FD and then the rule attribute. It will be useful to factor out code for other rule types.
Add inval_add_rule_arguments tests, extension of empty_path_beneath_attr tests, to also check error ordering for landlock_add_rule(2).
--- security/landlock/syscalls.c | 22 ++++++++++------- tools/testing/selftests/landlock/base_test.c | 34 +++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 11 deletions(-)
security/landlock/syscalls.c +13 -9
@@ -318,20 +318,24 @@ SYSCALL_DEFINE4(landlock_add_rule, constif (flags)return -EINVAL ; -if (rule_type !=LANDLOCK_RULE_PATH_BENEATH ) -return -EINVAL ; - -/* Copies raw user space buffer, only one type for now. */ - res =copy_from_user (&path_beneath_attr, rule_attr, -sizeof (path_beneath_attr)); -if (res) -return -EFAULT ; -/* Gets and checks the ruleset. */ ruleset =get_ruleset_from_fd (ruleset_fd,FMODE_CAN_WRITE );if (IS_ERR (ruleset))return PTR_ERR (ruleset); +if (rule_type !=LANDLOCK_RULE_PATH_BENEATH ) { + err = -EINVAL ; + goto out_put_ruleset; + } + +/* Copies raw user space buffer, only one type for now. */ + res =copy_from_user (&path_beneath_attr, rule_attr, +sizeof (path_beneath_attr)); +if (res) { + err = -EFAULT ; + goto out_put_ruleset; + } +/* * Informs about useless rule: empty allowed_access (i.e. deny rules) * are ignored in path walks.
tools/testing/selftests/landlock/base_test.c +32 -2
@@ -121,20 +121,50 @@ TEST(inval_create_ruleset_flags)ASSERT_EQ (EINVAL , errno); } -TEST (empty_path_beneath_attr) +/* Tests ordering of syscall argument checks. */ +TEST (add_rule_checks_ordering) {const struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs =LANDLOCK_ACCESS_FS_EXECUTE , }; +struct landlock_path_beneath_attr path_beneath_attr = { + .allowed_access =LANDLOCK_ACCESS_FS_EXECUTE , + .parent_fd =-1 , + };const int ruleset_fd =landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 );ASSERT_LE (0 , ruleset_fd); -/* Similar to struct landlock_path_beneath_attr.parent_fd = 0 */ +/* Checks invalid flags. */ +ASSERT_EQ (-1 ,landlock_add_rule (-1 ,0 ,NULL ,1 )); +ASSERT_EQ (EINVAL , errno); + +/* Checks invalid ruleset FD. */ +ASSERT_EQ (-1 ,landlock_add_rule (-1 ,0 ,NULL ,0 )); +ASSERT_EQ (EBADF , errno); + +/* Checks invalid rule type. */ +ASSERT_EQ (-1 ,landlock_add_rule (ruleset_fd,0 ,NULL ,0 )); +ASSERT_EQ (EINVAL , errno); + +/* Checks invalid rule attr. */ ASSERT_EQ (-1 ,landlock_add_rule (ruleset_fd,LANDLOCK_RULE_PATH_BENEATH ,NULL ,0 ));ASSERT_EQ (EFAULT , errno); + +/* Checks invalid path_beneath.parent_fd. */ +ASSERT_EQ (-1 ,landlock_add_rule (ruleset_fd,LANDLOCK_RULE_PATH_BENEATH , + &path_beneath_attr,0 )); +ASSERT_EQ (EBADF , errno); + +/* Checks valid call. */ + path_beneath_attr.parent_fd = +open ("/tmp" ,O_PATH |O_NOFOLLOW |O_DIRECTORY |O_CLOEXEC ); +ASSERT_LE (0 , path_beneath_attr.parent_fd); +ASSERT_EQ (0 ,landlock_add_rule (ruleset_fd,LANDLOCK_RULE_PATH_BENEATH , + &path_beneath_attr,0 )); +ASSERT_EQ (0 ,close (path_beneath_attr.parent_fd));ASSERT_EQ (0 ,close (ruleset_fd)); }
Greg Kroah-Hartman
maintainerPATCH 785/879 landlock: Change landlock_restrict_self(2) check ordering
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit eba39ca4b155c54adf471a69e91799cc1727873f upstream.
According to the Landlock goal to be a security feature available to unprivileges processes, it makes more sense to first check for no_new_privs before checking anything else (i.e. syscall arguments).
Merge inval_fd_enforce and unpriv_enforce_without_no_new_privs tests into the new restrict_self_checks_ordering. This is similar to the previous commit checking other syscalls.
--- security/landlock/syscalls.c | 8 ++-- tools/testing/selftests/landlock/base_test.c | 47 +++++++++++++++++++++------ 2 files changed, 41 insertions(+), 14 deletions(-)
security/landlock/syscalls.c +4 -4
@@ -405,10 +405,6 @@ SYSCALL_DEFINE2(landlock_restrict_self,if (!landlock_initialized)return -EOPNOTSUPP ; -/* No flag for now. */ -if (flags) -return -EINVAL ; -/* * Similar checks as for seccomp(2), except that an -EPERM may be * returned.
@@ -417,6 +413,10 @@ SYSCALL_DEFINE2(landlock_restrict_self, !ns_capable_noaudit(current_user_ns(), CAP_SYS_ADMIN))return -EPERM ; +/* No flag for now. */ +if (flags) +return -EINVAL ; +/* Gets and checks the ruleset. */ ruleset =get_ruleset_from_fd (ruleset_fd,FMODE_CAN_READ );if (IS_ERR (ruleset))
tools/testing/selftests/landlock/base_test.c +37 -10
59 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 786/879 selftests/landlock: Test landlock_create_ruleset(2) argument check ordering
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 6533d0c3a86ee1cc74ff37ac92ca597deb87015c upstream.
Add inval_create_ruleset_arguments, extension of inval_create_ruleset_flags, to also check error ordering for landlock_create_ruleset(2).
This is similar to the previous commit checking landlock_add_rule(2).
Test coverage for security/landlock is 94.4% of 504 lines accorging to gcc/gcov-11.
--- tools/testing/selftests/landlock/base_test.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
tools/testing/selftests/landlock/base_test.c +20 -1
@@ -97,14 +97,17 @@ TEST(abi_version)ASSERT_EQ (EINVAL , errno); } -TEST (inval_create_ruleset_flags) +/* Tests ordering of syscall argument checks. */ +TEST (create_ruleset_checks_ordering) {const int last_flag =LANDLOCK_CREATE_RULESET_VERSION ;const int invalid_flag = last_flag <<1 ; +int ruleset_fd;const struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs =LANDLOCK_ACCESS_FS_READ_FILE , }; +/* Checks priority for invalid flags. */ ASSERT_EQ (-1 ,landlock_create_ruleset (NULL ,0 , invalid_flag));ASSERT_EQ (EINVAL , errno);
@@ -119,6 +122,22 @@ TEST(inval_create_ruleset_flags)landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr), invalid_flag));ASSERT_EQ (EINVAL , errno); + +/* Checks too big ruleset_attr size. */ +ASSERT_EQ (-1 ,landlock_create_ruleset (&ruleset_attr,-1 ,0 )); +ASSERT_EQ (E2BIG , errno); + +/* Checks too small ruleset_attr size. */ +ASSERT_EQ (-1 ,landlock_create_ruleset (&ruleset_attr,0 ,0 )); +ASSERT_EQ (EINVAL , errno); +ASSERT_EQ (-1 ,landlock_create_ruleset (&ruleset_attr,1 ,0 )); +ASSERT_EQ (EINVAL , errno); + +/* Checks valid call. */ + ruleset_fd = +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 ); +ASSERT_LE (0 , ruleset_fd); +ASSERT_EQ (0 ,close (ruleset_fd)); }/* Tests ordering of syscall argument checks. */
Greg Kroah-Hartman
maintainerPATCH 787/879 landlock: Define access_mask_t to enforce a consistent access mask size
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 5f2ff33e10843ef51275c8611bdb7b49537aba5d upstream.
Create and use the access_mask_t typedef to enforce a consistent access mask size and uniformly use a 16-bits type. This will helps transition to a 32-bits value one day.
Add a build check to make sure all (filesystem) access rights fit in. This will be extended with a following commit.
--- security/landlock/fs.c | 19 +++++++++++-------- security/landlock/fs.h | 2 +- security/landlock/limits.h | 2 ++ security/landlock/ruleset.c | 6 ++++-- security/landlock/ruleset.h | 16 ++++++++++++---- 5 files changed, 30 insertions(+), 15 deletions(-)
security/landlock/fs.c +11 -8
@@ -152,7 +152,8 @@ retry:* @path: Should have been checked by get_path_from_fd(). */ int landlock_append_fs_rule (struct landlock_ruleset *const ruleset, -const struct path *const path,u32 access_rights) +const struct path *const path, +access_mask_t access_rights) {int err;struct landlock_object *object;
@@ -184,7 +185,8 @@ int landlock_append_fs_rule(struct landlstatic inline u64 unmask_layers (const struct landlock_ruleset *const domain,const struct path *const path, -const u32 access_request,u64 layer_mask) +const access_mask_t access_request, +u64 layer_mask) {const struct landlock_rule *rule;const struct inode *inode;
@@ -224,7 +226,8 @@ static inline u64 unmask_layers(const st }static int check_access_path (const struct landlock_ruleset *const domain, -const struct path *const path,u32 access_request) +const struct path *const path, +const access_mask_t access_request) {bool allowed = false;struct path walker_path;
@@ -309,7 +312,7 @@ jump_up: }static inline int current_check_access_path (const struct path *const path, -const u32 access_request) +const access_mask_t access_request) {const struct landlock_ruleset *const dom =landlock_get_current_domain ();
@@ -512,7 +515,7 @@ static int hook_sb_pivotroot(const struc/* Path hooks */ -static inline u32 get_mode_access (const umode_t mode) +static inline access_mask_t get_mode_access (const umode_t mode) {switch (mode &S_IFMT ) {case S_IFLNK :
@@ -565,7 +568,7 @@ static int hook_path_link(struct dentry get_mode_access(d_backing_inode(old_dentry)->i_mode)); } -static inline u32 maybe_remove (const struct dentry *const dentry) +static inline access_mask_t maybe_remove (const struct dentry *const dentry) {if (d_is_negative (dentry))return 0 ;
@@ -635,9 +638,9 @@ static int hook_path_rmdir(const struct/* File hooks */ -static inline u32 get_file_access (const struct file *const file) +static inline access_mask_t get_file_access (const struct file *const file) { -u32 access =0 ; +access_mask_t access =0 ;if (file->f_mode &FMODE_READ ) {/* A directory can only be opened in read mode. */
security/landlock/fs.h +1 -1
@@ -66,6 +66,6 @@ __init void landlock_add_fs_hooks(void);int landlock_append_fs_rule (struct landlock_ruleset *const ruleset,const struct path *const path, -u32 access_hierarchy); +access_mask_t access_hierarchy);#endif /* _SECURITY_LANDLOCK_FS_H */
security/landlock/limits.h +2 -0
@@ -9,6 +9,7 @@#ifndef _SECURITY_LANDLOCK_LIMITS_H#define _SECURITY_LANDLOCK_LIMITS_H +#include <linux/bitops.h> #include <linux/limits.h> #include <uapi/linux/landlock.h>
@@ -19,6 +20,7 @@#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_MAKE_SYM#define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1) +#define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS)/* clang-format on */
security/landlock/ruleset.c +4 -2
@@ -45,7 +45,8 @@ static struct landlock_ruleset *create_rreturn new_ruleset; } -struct landlock_ruleset *landlock_create_ruleset (const u32 fs_access_mask) +struct landlock_ruleset * +landlock_create_ruleset (const access_mask_t fs_access_mask) {struct landlock_ruleset *new_ruleset;
@@ -228,7 +229,8 @@ static void build_check_layer(void)/* @ruleset must be locked by the caller. */ int landlock_insert_rule (struct landlock_ruleset *const ruleset, -struct landlock_object *const object,const u32 access) +struct landlock_object *const object, +const access_mask_t access) {struct landlock_layer layers[] = { { .access = access,
security/landlock/ruleset.h +12 -4
@@ -9,13 +9,20 @@#ifndef _SECURITY_LANDLOCK_RULESET_H#define _SECURITY_LANDLOCK_RULESET_H +#include <linux/bitops.h> +#include <linux/build_bug.h> #include <linux/mutex.h> #include <linux/rbtree.h> #include <linux/refcount.h> #include <linux/workqueue.h> +#include "limits.h" #include "object.h" +typedef u16 access_mask_t ; +/* Makes sure all filesystem access rights can be stored. */ +static_assert (BITS_PER_TYPE (access_mask_t) >=LANDLOCK_NUM_ACCESS_FS ); +/** * struct landlock_layer - Access rights for a given layer */
@@ -28,7 +35,7 @@ struct landlock_layer {* @access: Bitfield of allowed actions on the kernel object. They are * relative to the object type (e.g. %LANDLOCK_ACTION_FS_READ). */ -u16 access; +access_mask_t access; };/**
@@ -135,19 +142,20 @@ struct landlock_ruleset {* layers are set once and never changed for the * lifetime of the ruleset. */ -u16 fs_access_masks[]; +access_mask_t fs_access_masks[]; }; }; }; -struct landlock_ruleset *landlock_create_ruleset (const u32 fs_access_mask); +struct landlock_ruleset * +landlock_create_ruleset (const access_mask_t fs_access_mask);void landlock_put_ruleset (struct landlock_ruleset *const ruleset);void landlock_put_ruleset_deferred (struct landlock_ruleset *const ruleset);int landlock_insert_rule (struct landlock_ruleset *const ruleset,struct landlock_object *const object, -const u32 access); +const access_mask_t access);struct landlock_ruleset * landlock_merge_ruleset(struct landlock_ruleset *const parent,
Greg Kroah-Hartman
maintainerPATCH 788/879 landlock: Reduce the maximum number of layers to 16
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 75c542d6c6cc48720376862d5496d51509160dfd upstream.
The maximum number of nested Landlock domains is currently 64. Because of the following fix and to help reduce the stack size, let's reduce it to 16. This seems large enough for a lot of use cases (e.g. sandboxed init service, spawning a sandboxed SSH service, in nested sandboxed containers). Reducing the number of nested domains may also help to discover misuse of Landlock (e.g. creating a domain per rule).
Add and use a dedicated layer_mask_t typedef to fit with the number of layers. This might be useful when changing it and to keep it consistent with the maximum number of layers.
--- Documentation/userspace-api/landlock.rst | 4 ++-- security/landlock/fs.c | 17 +++++++---------- security/landlock/limits.h | 2 +- security/landlock/ruleset.h | 4 ++++ tools/testing/selftests/landlock/fs_test.c | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-)
Documentation/userspace-api/landlock.rst +2 -2
@@ -267,8 +267,8 @@ restrict such paths with dedicated rules Ruleset layers -------------- -There is a limit of 64 layers of stacked rulesets. This can be an issue for a -task willing to enforce a new ruleset in complement to its 64 inherited +There is a limit of 16 layers of stacked rulesets. This can be an issue for a +task willing to enforce a new ruleset in complement to its 16 inherited rulesets. Once this limit is reached, sys_landlock_restrict_self() returns E2BIG. It is then strongly suggested to carefully build rulesets once in the life of a thread, especially for applications able to launch other applications
security/landlock/fs.c +7 -10
@@ -183,10 +183,10 @@ int landlock_append_fs_rule(struct landl/* Access-control management */ -static inline u64 unmask_layers (const struct landlock_ruleset *const domain, -const struct path *const path, -const access_mask_t access_request, -u64 layer_mask) +static inline layer_mask_t +unmask_layers (const struct landlock_ruleset *const domain, +const struct path *const path,const access_mask_t access_request, +layer_mask_t layer_mask) {const struct landlock_rule *rule;const struct inode *inode;
@@ -212,11 +212,11 @@ static inline u64 unmask_layers(const st*/ for (i =0 ; i < rule->num_layers; i++) {const struct landlock_layer *const layer = &rule->layers[i]; -const u64 layer_level =BIT_ULL (layer->level -1 ); +const layer_mask_t layer_bit =BIT_ULL (layer->level -1 );/* Checks that the layer grants access to the full request. */ if ((layer->access & access_request) == access_request) { - layer_mask &= ~layer_level; + layer_mask &= ~layer_bit;if (layer_mask ==0 )return layer_mask;
@@ -231,12 +231,9 @@ static int check_access_path(const struc {bool allowed = false;struct path walker_path; -u64 layer_mask; +layer_mask_t layer_mask;size_t i; -/* Make sure all layers can be checked. */ -BUILD_BUG_ON (BITS_PER_TYPE (layer_mask) <LANDLOCK_MAX_NUM_LAYERS ); -if (!access_request)return 0 ;if (WARN_ON_ONCE (!domain || !path))
security/landlock/limits.h +1 -1
@@ -15,7 +15,7 @@/* clang-format off */ -#define LANDLOCK_MAX_NUM_LAYERS 64 +#define LANDLOCK_MAX_NUM_LAYERS 16#define LANDLOCK_MAX_NUM_RULES U32_MAX#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_MAKE_SYM
security/landlock/ruleset.h +4 -0
@@ -23,6 +23,10 @@ typedef u16 access_mask_t;/* Makes sure all filesystem access rights can be stored. */ static_assert (BITS_PER_TYPE (access_mask_t) >=LANDLOCK_NUM_ACCESS_FS ); +typedef u16 layer_mask_t ; +/* Makes sure all layers can be checked. */ +static_assert (BITS_PER_TYPE (layer_mask_t) >=LANDLOCK_MAX_NUM_LAYERS ); +/** * struct landlock_layer - Access rights for a given layer */
tools/testing/selftests/landlock/fs_test.c +1 -1
@@ -1159,7 +1159,7 @@ TEST_F_FORK(layout1, max_layers)const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);ASSERT_LE (0 , ruleset_fd); -for (i =0 ; i <64 ; i++) +for (i =0 ; i <16 ; i++)enforce_ruleset (_metadata, ruleset_fd);for (i =0 ; i <2 ; i++) {
Greg Kroah-Hartman
maintainerPATCH 789/879 landlock: Create find_rule() from unmask_layers()
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 2cd7cd6eed88b8383cfddce589afe9c0ae1d19b4 upstream.
This refactoring will be useful in a following commit.
--- security/landlock/fs.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-)
security/landlock/fs.c +28 -13
@@ -183,23 +183,36 @@ int landlock_append_fs_rule(struct landl/* Access-control management */ -static inline layer_mask_t -unmask_layers (const struct landlock_ruleset *const domain, -const struct path *const path,const access_mask_t access_request, -layer_mask_t layer_mask) +/* +* The lifetime of the returned rule is tied to @domain. +* +* Returns NULL if no rule is found or if @dentry is negative. +*/ +static inline const struct landlock_rule * +find_rule (const struct landlock_ruleset *const domain, +const struct dentry *const dentry) {const struct landlock_rule *rule;const struct inode *inode; -size_t i; -if (d_is_negative (path->dentry)) -/* Ignore nonexistent leafs. */ -return layer_mask; - inode =d_backing_inode (path->dentry); +/* Ignores nonexistent leafs. */ +if (d_is_negative (dentry)) +return NULL ; + + inode =d_backing_inode (dentry);rcu_read_lock (); rule =landlock_find_rule ( domain,rcu_dereference (landlock_inode (inode)->object));rcu_read_unlock (); +return rule; +} + +static inline layer_mask_t unmask_layers (const struct landlock_rule *const rule, +const access_mask_t access_request, +layer_mask_t layer_mask) +{ +size_t layer_level; +if (!rule)return layer_mask;
@@ -210,8 +223,9 @@ unmask_layers(const struct landlock_rule* the remaining layers for each inode, from the first added layer to * the last one. */ -for (i =0 ; i < rule->num_layers; i++) { -const struct landlock_layer *const layer = &rule->layers[i]; +for (layer_level =0 ; layer_level < rule->num_layers; layer_level++) { +const struct landlock_layer *const layer = + &rule->layers[layer_level];const layer_mask_t layer_bit =BIT_ULL (layer->level -1 );/* Checks that the layer grants access to the full request. */
@@ -269,8 +283,9 @@ static int check_access_path(const strucwhile (true) {struct dentry *parent_dentry; - layer_mask =unmask_layers (domain, &walker_path, access_request, - layer_mask); + layer_mask = +unmask_layers (find_rule (domain, walker_path.dentry), + access_request, layer_mask);if (layer_mask ==0 ) {/* Stops when a rule from each layer grants access. */ allowed = true;
Greg Kroah-Hartman
maintainerPATCH 790/879 landlock: Fix same-layer rule unions
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 8ba0005ff418ec356e176b26eaa04a6ac755d05b upstream.
The original behavior was to check if the full set of requested accesses was allowed by at least a rule of every relevant layer. This didn't take into account requests for multiple accesses and same-layer rules allowing the union of these accesses in a complementary way. As a result, multiple accesses requested on a file hierarchy matching rules that, together, allowed these accesses, but without a unique rule allowing all of them, was illegitimately denied. This case should be rare in practice and it can only be triggered by the path_rename or file_open hook implementations.
For instance, if, for the same layer, a rule allows execution beneath /a/b and another rule allows read beneath /a, requesting access to read and execute at the same time for /a/b should be allowed for this layer.
This was an inconsistency because the union of same-layer rule accesses was already allowed if requested once at a time anyway.
This fix changes the way allowed accesses are gathered over a path walk. To take into account all these rule accesses, we store in a matrix all layer granting the set of requested accesses, according to the handled accesses. To avoid heap allocation, we use an array on the stack which is 2*13 bytes. A following commit bringing the LANDLOCK_ACCESS_FS_REFER access right will increase this size to reach 112 bytes (2*14*4) in case of link or rename actions.
Add a new layout1.layer_rule_unions test to check that accesses from different rules pertaining to the same layer are ORed in a file hierarchy. Also test that it is not the case for rules from different layers.
--- security/landlock/fs.c | 80 ++++++++++++++------- security/landlock/ruleset.h | 2 tools/testing/selftests/landlock/fs_test.c | 107 +++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 27 deletions(-)
security/landlock/fs.c +53 -27
@@ -207,45 +207,67 @@ find_rule(const struct landlock_rulesetreturn rule; } -static inline layer_mask_t unmask_layers (const struct landlock_rule *const rule, -const access_mask_t access_request, -layer_mask_t layer_mask) +/* +* @layer_masks is read and may be updated according to the access request and +* the matching rule. +* +* Returns true if the request is allowed (i.e. relevant layer masks for the +* request are empty). +*/ +static inline bool +unmask_layers (const struct landlock_rule *const rule, +const access_mask_t access_request, +layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS ]) {size_t layer_level; +if (!access_request || !layer_masks) +return true;if (!rule) -return layer_mask; +return false;/* * An access is granted if, for each policy layer, at least one rule -* encountered on the pathwalk grants the requested accesses, -* regardless of their position in the layer stack. We must then check +* encountered on the pathwalk grants the requested access, +* regardless of its position in the layer stack. We must then check * the remaining layers for each inode, from the first added layer to -* the last one. +* the last one. When there is multiple requested accesses, for each +* policy layer, the full set of requested accesses may not be granted +* by only one rule, but by the union (binary OR) of multiple rules. +* E.g. /a/b <execute> + /a <read> => /a/b <execute + read> */ for (layer_level =0 ; layer_level < rule->num_layers; layer_level++) {const struct landlock_layer *const layer = &rule->layers[layer_level];const layer_mask_t layer_bit =BIT_ULL (layer->level -1 ); - -/* Checks that the layer grants access to the full request. */ -if ((layer->access & access_request) == access_request) { - layer_mask &= ~layer_bit; - -if (layer_mask ==0 ) -return layer_mask; +const unsigned long access_req = access_request; +unsigned long access_bit; +bool is_empty; + +/* +* Records in @layer_masks which layer grants access to each +* requested access. +*/ + is_empty = true; +for_each_set_bit (access_bit, &access_req, +ARRAY_SIZE (*layer_masks)) { +if (layer->access &BIT_ULL (access_bit)) + (*layer_masks)[access_bit] &= ~layer_bit; + is_empty = is_empty && !(*layer_masks)[access_bit]; } +if (is_empty) +return true; } -return layer_mask; +return false; }static int check_access_path (const struct landlock_ruleset *const domain,const struct path *const path,const access_mask_t access_request) { -bool allowed = false; +layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS ] = {}; +bool allowed = false, has_access = false;struct path walker_path; -layer_mask_t layer_mask;size_t i;if (!access_request)
@@ -265,13 +287,20 @@ static int check_access_path(const strucreturn -EACCES ;/* Saves all layers handling a subset of requested accesses. */ - layer_mask =0 ;for (i =0 ; i < domain->num_layers; i++) { -if (domain->fs_access_masks[i] & access_request) - layer_mask |=BIT_ULL (i); +const unsigned long access_req = access_request; +unsigned long access_bit; + +for_each_set_bit (access_bit, &access_req, +ARRAY_SIZE (layer_masks)) { +if (domain->fs_access_masks[i] &BIT_ULL (access_bit)) { + layer_masks[access_bit] |=BIT_ULL (i); + has_access = true; + } + } }/* An access request not handled by the domain is allowed. */ -if (layer_mask ==0 ) +if (!has_access)return 0 ; walker_path = *path;
@@ -283,14 +312,11 @@ static int check_access_path(const strucwhile (true) {struct dentry *parent_dentry; - layer_mask = -unmask_layers (find_rule (domain, walker_path.dentry), - access_request, layer_mask); -if (layer_mask ==0 ) { + allowed =unmask_layers (find_rule (domain, walker_path.dentry), + access_request, &layer_masks); +if (allowed)/* Stops when a rule from each layer grants access. */ - allowed = true;break ; - } jump_up:if (walker_path.dentry == walker_path.mnt->mnt_root) {
security/landlock/ruleset.h +2 -0
@@ -22,6 +22,8 @@typedef u16 access_mask_t ;/* Makes sure all filesystem access rights can be stored. */ static_assert (BITS_PER_TYPE (access_mask_t) >=LANDLOCK_NUM_ACCESS_FS ); +/* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */ +static_assert (sizeof (unsigned long ) >=sizeof (access_mask_t));typedef u16 layer_mask_t ;/* Makes sure all layers can be checked. */
tools/testing/selftests/landlock/fs_test.c +107 -0
113 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 791/879 drm/amdgpu/cs: make commands with 0 chunks illegal behaviour.
In reply to Greg Kroah-HartmanFrom: Dave Airlie <[email protected]>
commit 31ab27b14daaa75541a415c6794d6f3567fea44a upstream.
Submitting a cs with 0 chunks, causes an oops later, found trying to execute the wrong userspace driver.
MESA_LOADER_DRIVER_OVERRIDE=v3d glxinfo
[172536.665184] BUG: kernel NULL pointer dereference, address: 00000000000001d8 [172536.665188] #PF: supervisor read access in kernel mode [172536.665189] #PF: error_code(0x0000) - not-present page [172536.665191] PGD 6712a0067 P4D 6712a0067 PUD 5af9ff067 PMD 0 [172536.665195] Oops: 0000 [#1] SMP NOPTI [172536.665197] CPU: 7 PID: 2769838 Comm: glxinfo Tainted: P O 5.10.81 #1-NixOS [172536.665199] Hardware name: To be filled by O.E.M. To be filled by O.E.M./CROSSHAIR V FORMULA-Z, BIOS 2201 03/23/2015 [172536.665272] RIP: 0010:amdgpu_cs_ioctl+0x96/0x1ce0 [amdgpu] [172536.665274] Code: 75 18 00 00 4c 8b b2 88 00 00 00 8b 46 08 48 89 54 24 68 49 89 f7 4c 89 5c 24 60 31 d2 4c 89 74 24 30 85 c0 0f 85 c0 01 00 00 <48> 83 ba d8 01 00 00 00 48 8b b4 24 90 00 00 00 74 16 48 8b 46 10 [172536.665276] RSP: 0018:ffffb47c0e81bbe0 EFLAGS: 00010246 [172536.665277] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 [172536.665278] RDX: 0000000000000000 RSI: ffffb47c0e81be28 RDI: ffffb47c0e81bd68 [172536.665279] RBP: ffff936524080010 R08: 0000000000000000 R09: ffffb47c0e81be38 [172536.665281] R10: ffff936524080010 R11: ffff936524080000 R12: ffffb47c0e81bc40 [172536.665282] R13: ffffb47c0e81be28 R14: ffff9367bc410000 R15: ffffb47c0e81be28 [172536.665283] FS: 00007fe35e05d740(0000) GS:ffff936c1edc0000(0000) knlGS:0000000000000000 [172536.665284] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [172536.665286] CR2: 00000000000001d8 CR3: 0000000532e46000 CR4: 00000000000406e0 [172536.665287] Call Trace: [172536.665322] ? amdgpu_cs_find_mapping+0x110/0x110 [amdgpu] [172536.665332] drm_ioctl_kernel+0xaa/0xf0 [drm] [172536.665338] drm_ioctl+0x201/0x3b0 [drm] [172536.665369] ? amdgpu_cs_find_mapping+0x110/0x110 [amdgpu] [172536.665372] ? selinux_file_ioctl+0x135/0x230 [172536.665399] amdgpu_drm_ioctl+0x49/0x80 [amdgpu] [172536.665403] __x64_sys_ioctl+0x83/0xb0 [172536.665406] do_syscall_64+0x33/0x40 [172536.665409] entry_SYSCALL_64_after_hwframe+0x44/0xa9
--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +1 -1
@@ -116,7 +116,7 @@ static int amdgpu_cs_parser_init(structint ret;if (cs->in.num_chunks ==0 ) -return 0 ; +return -EINVAL ; chunk_array =kvmalloc_array (cs->in.num_chunks,sizeof (uint64_t ),GFP_KERNEL );if (!chunk_array)
Greg Kroah-Hartman
maintainerPATCH 792/879 drm/nouveau/subdev/bus: Ratelimit logging for fault errors
In reply to Greg Kroah-HartmanFrom: Lyude Paul <[email protected]>
commit 9887bda0c831df0c044d6de147d002e48024fb4a upstream.
There's plenty of ways to fudge the GPU when developing on nouveau by mistake, some of which can result in nouveau seriously spamming dmesg with fault errors. This can be somewhat annoying, as it can quickly overrun the message buffer (or your terminal emulator's buffer) and get rid of actually useful feedback from the driver. While working on my new atomic only MST branch, I ran into this issue a couple of times.
So, let's fix this by adding nvkm_error_ratelimited(), and using it to ratelimit errors from faults. This should be fine for developers, since it's nearly always only the first few faults that we care about seeing. Plus, you can turn off rate limiting in the kernel if you really need to.
--- drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h | 2 ++ drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c | 14 +++++++------- drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c | 6 +++--- drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c | 6 +++--- 4 files changed, 15 insertions(+), 13 deletions(-)
drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h +2 -0
@@ -62,4 +62,6 @@ void nvkm_subdev_intr(struct nvkm_subdev #define nvkm_debug(s,f,a...) nvkm_printk((s), DEBUG, info, f, ##a) #define nvkm_trace(s,f,a...) nvkm_printk((s), TRACE, info, f, ##a) #define nvkm_spam(s,f,a...) nvkm_printk((s), SPAM, dbg, f, ##a) + +#define nvkm_error_ratelimited(s,f,a...) nvkm_printk((s), ERROR, err_ratelimited, f, ##a)#endif
drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c +7 -7
@@ -35,13 +35,13 @@ gf100_bus_intr(struct nvkm_bus *bus)u32 addr =nvkm_rd32 (device,0x009084 );u32 data =nvkm_rd32 (device,0x009088 ); -nvkm_error (subdev, -"MMIO %s of %08x FAULT at %06x [ %s%s%s]\n" , - (addr &0x00000002 ) ?"write" :"read" , data, - (addr &0x00fffffc ), - (stat &0x00000002 ) ?"!ENGINE " :"" , - (stat &0x00000004 ) ?"PRIVRING " :"" , - (stat &0x00000008 ) ?"TIMEOUT " :"" ); +nvkm_error_ratelimited (subdev, +"MMIO %s of %08x FAULT at %06x [ %s%s%s]\n" , + (addr &0x00000002 ) ?"write" :"read" , data, + (addr &0x00fffffc ), + (stat &0x00000002 ) ?"!ENGINE " :"" , + (stat &0x00000004 ) ?"PRIVRING " :"" , + (stat &0x00000008 ) ?"TIMEOUT " :"" );nvkm_wr32 (device,0x009084 ,0x00000000 );nvkm_wr32 (device,0x001100 , (stat &0x0000000e ));
drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c +3 -3
@@ -45,9 +45,9 @@ nv31_bus_intr(struct nvkm_bus *bus)u32 addr =nvkm_rd32 (device,0x009084 );u32 data =nvkm_rd32 (device,0x009088 ); -nvkm_error (subdev,"MMIO %s of %08x FAULT at %06x\n" , - (addr &0x00000002 ) ?"write" :"read" , data, - (addr &0x00fffffc )); +nvkm_error_ratelimited (subdev,"MMIO %s of %08x FAULT at %06x\n" , + (addr &0x00000002 ) ?"write" :"read" , data, + (addr &0x00fffffc )); stat &= ~0x00000008 ;nvkm_wr32 (device,0x001100 ,0x00000008 );
drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c +3 -3
@@ -60,9 +60,9 @@ nv50_bus_intr(struct nvkm_bus *bus)u32 addr =nvkm_rd32 (device,0x009084 );u32 data =nvkm_rd32 (device,0x009088 ); -nvkm_error (subdev,"MMIO %s of %08x FAULT at %06x\n" , - (addr &0x00000002 ) ?"write" :"read" , data, - (addr &0x00fffffc )); +nvkm_error_ratelimited (subdev,"MMIO %s of %08x FAULT at %06x\n" , + (addr &0x00000002 ) ?"write" :"read" , data, + (addr &0x00fffffc )); stat &= ~0x00000008 ;nvkm_wr32 (device,0x001100 ,0x00000008 );
Greg Kroah-Hartman
maintainerPATCH 793/879 drm/etnaviv: check for reaped mapping in etnaviv_iommu_unmap_gem
In reply to Greg Kroah-HartmanFrom: Lucas Stach <[email protected]>
commit e168c25526cd0368af098095c2ded4a008007e1b upstream.
When the mapping is already reaped the unmap must be a no-op, as we would otherwise try to remove the mapping twice, corrupting the involved data structures.
--- drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/gpu/drm/etnaviv/etnaviv_mmu.c +6 -0
@@ -286,6 +286,12 @@ void etnaviv_iommu_unmap_gem(struct etnamutex_lock (&context->lock); +/* Bail if the mapping has been reaped by another thread */ +if (!mapping->context) { +mutex_unlock (&context->lock); +return ; + } +/* If the vram node is on the mm, unmap and remove the node */ if (mapping->vram_node.mm == &context->mm)etnaviv_iommu_remove_mapping (context, mapping);
Greg Kroah-Hartman
maintainerPATCH 794/879 drm/nouveau/clk: Fix an incorrect NULL check on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 1c3b2a27def609473ed13b1cd668cb10deab49b4 upstream.
The bug is here:
if (nvkm_cstate_valid(clk, cstate, max_volt, clk->temp)) return cstate;
The list iterator value 'cstate' will *always* be set and non-NULL by list_for_each_entry_from_reverse(), so it is incorrect to assume that the iterator value will be unchanged if the list is empty or no element is found (In fact, it will be a bogus pointer to an invalid structure object containing the HEAD). Also it missed a NULL check at callsite and may lead to invalid memory access after that.
To fix this bug, just return 'encoder' when found, otherwise return NULL. And add the NULL check.
--- drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +4 -2
@@ -135,10 +135,10 @@ nvkm_cstate_find_best(struct nvkm_clk *clist_for_each_entry_from_reverse (cstate, &pstate->list, head) {if (nvkm_cstate_valid (clk, cstate, max_volt, clk->temp)) -break ; +return cstate; } -return cstate; +return NULL ; } static struct nvkm_cstate *
@@ -169,6 +169,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, sif (!list_empty (&pstate->list)) { cstate =nvkm_cstate_get (clk, pstate, cstatei); cstate =nvkm_cstate_find_best (clk, pstate, cstate); +if (!cstate) +return -EINVAL ; }else { cstate = &pstate->base; }
Greg Kroah-Hartman
maintainerPATCH 795/879 drm/nouveau/kms/nv50-: atom: fix an incorrect NULL check on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 6ce4431c7ba7954c4fa6a96ce16ca1b2943e1a83 upstream.
The bug is here:
return encoder;
The list iterator value 'encoder' will *always* be set and non-NULL by drm_for_each_encoder_mask(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element found. Otherwise it will bypass some NULL checks and lead to invalid memory access passing the check.
To fix this bug, just return 'encoder' when found, otherwise return NULL.
--- drivers/gpu/drm/nouveau/dispnv50/atom.h | 6 +++--- drivers/gpu/drm/nouveau/dispnv50/crc.c | 27 ++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-)
drivers/gpu/drm/nouveau/dispnv50/atom.h +3 -3
@@ -160,14 +160,14 @@ nv50_head_atom_get(struct drm_atomic_stastatic inline struct drm_encoder *nv50_head_atom_get_encoder (struct nv50_head_atom *atom) { -struct drm_encoder *encoder =NULL ; +struct drm_encoder *encoder;/* We only ever have a single encoder */ drm_for_each_encoder_mask (encoder, atom->state.crtc->dev, atom->state.encoder_mask) -break ; +return encoder; -return encoder; +return NULL ; }#define nv50_wndw_atom (p) container_of((p), struct nv50_wndw_atom, state)
drivers/gpu/drm/nouveau/dispnv50/crc.c +22 -5
@@ -390,9 +390,18 @@ void nv50_crc_atomic_check_outp(struct nstruct nv50_head_atom *armh =nv50_head_atom (old_crtc_state);struct nv50_head_atom *asyh =nv50_head_atom (new_crtc_state);struct nv50_outp_atom *outp_atom; -struct nouveau_encoder *outp = -nv50_real_outp (nv50_head_atom_get_encoder (armh)); -struct drm_encoder *encoder = &outp->base.base; +struct nouveau_encoder *outp; +struct drm_encoder *encoder, *enc; + + enc =nv50_head_atom_get_encoder (armh); +if (!enc) +continue ; + + outp =nv50_real_outp (enc); +if (!outp) +continue ; + + encoder = &outp->base.base;if (!asyh->clr.crc)continue ;
@@ -443,8 +452,16 @@ void nv50_crc_atomic_set(struct nv50_heastruct drm_device *dev = crtc->dev;struct nv50_crc *crc = &head->crc;const struct nv50_crc_func *func =nv50_disp (dev)->core->func->crc; -struct nouveau_encoder *outp = -nv50_real_outp (nv50_head_atom_get_encoder (asyh)); +struct nouveau_encoder *outp; +struct drm_encoder *encoder; + + encoder =nv50_head_atom_get_encoder (asyh); +if (!encoder) +return ; + + outp =nv50_real_outp (encoder); +if (!outp) +return ; func->set_src (head, outp->or,nv50_crc_source_type (outp, asyh->crc.src), &crc->ctx[crc->ctx_idx]);
Greg Kroah-Hartman
maintainerPATCH 796/879 drm/bridge: analogix_dp: Grab runtime PM reference for DP-AUX
In reply to Greg Kroah-HartmanFrom: Brian Norris <[email protected]>
commit 8fb6c44fe8468f92ac7b8bbfcca4404a4e88645f upstream.
If the display is not enable()d, then we aren't holding a runtime PM reference here. Thus, it's easy to accidentally cause a hang, if user space is poking around at /dev/drm_dp_aux0 at the "wrong" time.
Let's get a runtime PM reference, and check that we "see" the panel. Don't force any panel power-up, etc., because that can be intrusive, and that's not what other drivers do (see drivers/gpu/drm/bridge/ti-sn65dsi86.c and drivers/gpu/drm/bridge/parade-ps8640.c.)
--- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +12 -1
@@ -1632,8 +1632,19 @@ static ssize_t analogix_dpaux_transfer(s struct drm_dp_aux_msg *msg) {struct analogix_dp_device *dp =to_dp (aux); +int ret; -return analogix_dp_transfer (dp, msg); +pm_runtime_get_sync (dp->dev); + + ret =analogix_dp_detect_hpd (dp); +if (ret) + goto out; + + ret =analogix_dp_transfer (dp, msg); +out: +pm_runtime_put (dp->dev); + +return ret; } struct analogix_dp_device *
Greg Kroah-Hartman
maintainerPATCH 797/879 drm/i915/dsi: fix VBT send packet port selection for ICL+
In reply to Greg Kroah-HartmanFrom: Jani Nikula <[email protected]>
commit 0ea917819d12fed41ea4662cc26ffa0060a5c354 upstream.
The VBT send packet port selection was never updated for ICL+ where the 2nd link is on port B instead of port C as in VLV+ DSI.
First, single link DSI needs to use the configured port instead of relying on the VBT sequence block port. Remove the hard-coded port C check here and make it generic. For reference, see commit f915084edc5a ("drm/i915: Changes related to the sequence port no for") for the original VLV specific fix.
Second, the sequence block port number is either 0 or 1, where 1 indicates the 2nd link. Remove the hard-coded port C here for 2nd link. (This could be a "find second set bit" on DSI ports, but just check the two possible options.)
Third, sanity check the result with a warning to avoid a NULL pointer dereference.
--- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 33 ++++++++++++++++++--------- 1 file changed, 22 insertions(+), 11 deletions(-)
drivers/gpu/drm/i915/display/intel_dsi_vbt.c +22 -11
@@ -124,9 +124,25 @@ struct i2c_adapter_lookup {#define ICL_GPIO_DDPA_CTRLCLK_2 8#define ICL_GPIO_DDPA_CTRLDATA_2 9 -static enum port intel_dsi_seq_port_to_port (u8 port) +static enum port intel_dsi_seq_port_to_port (struct intel_dsi *intel_dsi, +u8 seq_port) { -return port ?PORT_C :PORT_A ; +/* +* If single link DSI is being used on any port, the VBT sequence block +* send packet apparently always has 0 for the port. Just use the port +* we have configured, and ignore the sequence block port. +*/ +if (hweight8 (intel_dsi->ports) ==1 ) +return ffs (intel_dsi->ports) -1 ; + +if (seq_port) { +if (intel_dsi->ports &PORT_B ) +return PORT_B ; +else if (intel_dsi->ports &PORT_C ) +return PORT_C ; + } + +return PORT_A ; } static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi,
@@ -148,15 +164,10 @@ static const u8 *mipi_exec_send_packet(s seq_port = (flags >>MIPI_PORT_SHIFT ) &3 ; -/* For DSI single link on Port A & C, the seq_port value which is -* parsed from Sequence Block#53 of VBT has been set to 0 -* Now, read/write of packets for the DSI single link on Port A and -* Port C will based on the DVO port from VBT block 2. -*/ -if (intel_dsi->ports == (1 <<PORT_C )) - port =PORT_C ; -else - port =intel_dsi_seq_port_to_port (seq_port); + port =intel_dsi_seq_port_to_port (intel_dsi, seq_port); + +if (drm_WARN_ON (&dev_priv->drm, !intel_dsi->dsi_hosts[port])) + goto out; dsi_device = intel_dsi->dsi_hosts[port]->device;if (!dsi_device) {
Greg Kroah-Hartman
maintainerPATCH 798/879 md: fix an incorrect NULL check in does_sb_need_changing
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit fc8738343eefc4ea8afb6122826dea48eacde514 upstream.
The bug is here:
if (!rdev)
The list iterator value 'rdev' will *always* be set and non-NULL by rdev_for_each(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element found. Otherwise it will bypass the NULL check and lead to invalid memory access passing the check.
To fix the bug, use a new variable 'iter' as the list iterator, while using the original variable 'rdev' as a dedicated pointer to point to the found element.
--- drivers/md/md.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/md/md.c +5 -3
@@ -2627,14 +2627,16 @@ static void sync_sbs(struct mddev *mddevstatic bool does_sb_need_changing (struct mddev *mddev) { -struct md_rdev *rdev; +struct md_rdev *rdev =NULL , *iter;struct mdp_superblock_1 *sb;int role;/* Find a good rdev */ -rdev_for_each (rdev, mddev) -if ((rdev->raid_disk >=0 ) && !test_bit (Faulty, &rdev->flags)) +rdev_for_each (iter, mddev) +if ((iter->raid_disk >=0 ) && !test_bit (Faulty, &iter->flags)) { + rdev = iter;break ; + }/* No good device found. */ if (!rdev)
Greg Kroah-Hartman
maintainerPATCH 799/879 md: fix an incorrect NULL check in md_reload_sb
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 64c54d9244a4efe9bc6e9c98e13c4bbb8bb39083 upstream.
The bug is here:
if (!rdev || rdev->desc_nr != nr) {The list iterator value 'rdev' will *always* be set and non-NULL by rdev_for_each_rcu(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element found (In fact, it will be a bogus pointer to an invalid struct object containing the HEAD). Otherwise it will bypass the check and lead to invalid memory access passing the check.
To fix the bug, use a new variable 'iter' as the list iterator, while using the original variable 'pdev' as a dedicated pointer to point to the found element.
--- drivers/md/md.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/md/md.c +6 -4
@@ -9793,16 +9793,18 @@ static int read_rdev(struct mddev *mddevvoid md_reload_sb (struct mddev *mddev,int nr) { -struct md_rdev *rdev; +struct md_rdev *rdev =NULL , *iter;int err;/* Find the rdev */ -rdev_for_each_rcu (rdev, mddev) { -if (rdev->desc_nr == nr) +rdev_for_each_rcu (iter, mddev) { +if (iter->desc_nr == nr) { + rdev = iter;break ; + } } -if (!rdev || rdev->desc_nr != nr) { +if (!rdev) {pr_warn ("%s: %d Could not find rdev with nr %d\n" , __func__, __LINE__, nr);return ; }
Greg Kroah-Hartman
maintainerPATCH 800/879 mtd: cfi_cmdset_0002: Move and rename chip_check/chip_ready/chip_good_for_write
In reply to Greg Kroah-HartmanFrom: Tokunori Ikegami <[email protected]>
commit 083084df578a8bdb18334f69e7b32d690aaa3247 upstream.
This is a preparation patch for the S29GL064N buffer writes fix. There is no functional change.
--- drivers/mtd/chips/cfi_cmdset_0002.c | 95 ++++++++++++------------------------ 1 file changed, 32 insertions(+), 63 deletions(-)
drivers/mtd/chips/cfi_cmdset_0002.c +32 -63
@@ -802,21 +802,25 @@ static struct mtd_info *cfi_amdstd_setup }/* -* Return true if the chip is ready. +* Return true if the chip is ready and has the correct value. * * Ready is one of: read mode, query mode, erase-suspend-read mode (in any * non-suspended sector) and is indicated by no toggle bits toggling. * +* Error are indicated by toggling bits or bits held with the wrong value, +* or with bits toggling. +* * Note that anything more complicated than checking if no bits are toggling * (including checking DQ5 for an error status) is tricky to get working * correctly and is therefore not done (particularly with interleaved chips * as each chip must be checked independently of the others). */ static int __xipram chip_ready(struct map_info *map, struct flchip *chip, -unsigned long addr) +unsigned long addr,map_word *expected) {struct cfi_private *cfi = map->fldrv_priv;map_word d, t; +int ret;if (cfi_use_status_reg (cfi)) {map_word ready =CMD (CFI_SR_DRB );
@@ -826,57 +830,20 @@ static int __xipram chip_ready(struct ma*/ cfi_send_gen_cmd (0x70 , cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type,NULL ); - d =map_read (map, addr); + t =map_read (map, addr); -return map_word_andequal (map, d, ready, ready); +return map_word_andequal (map, t, ready, ready); } d =map_read (map, addr); t =map_read (map, addr); -return map_word_equal (map, d, t); -} - -/* -* Return true if the chip is ready and has the correct value. -* -* Ready is one of: read mode, query mode, erase-suspend-read mode (in any -* non-suspended sector) and it is indicated by no bits toggling. -* -* Error are indicated by toggling bits or bits held with the wrong value, -* or with bits toggling. -* -* Note that anything more complicated than checking if no bits are toggling -* (including checking DQ5 for an error status) is tricky to get working -* correctly and is therefore not done (particularly with interleaved chips -* as each chip must be checked independently of the others). -* -*/ -static int __xipram chip_good(struct map_info *map, struct flchip *chip, -unsigned long addr,map_word expected) -{ -struct cfi_private *cfi = map->fldrv_priv; -map_word oldd, curd; - -if (cfi_use_status_reg (cfi)) { -map_word ready =CMD (CFI_SR_DRB ); - -/* -* For chips that support status register, check device -* ready bit -*/ -cfi_send_gen_cmd (0x70 , cfi->addr_unlock1, chip->start, map, cfi, - cfi->device_type,NULL ); - curd =map_read (map, addr); - -return map_word_andequal (map, curd, ready, ready); - } + ret =map_word_equal (map, d, t); - oldd =map_read (map, addr); - curd =map_read (map, addr); +if (!ret || !expected) +return ret; -return map_word_equal (map, oldd, curd) && -map_word_equal (map, curd, expected); +return map_word_equal (map, t, *expected); }static int get_chip (struct map_info *map,struct flchip *chip,unsigned long adr,int mode)
@@ -893,7 +860,7 @@ static int get_chip(struct map_info *mapcase FL_STATUS :for (;;) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;if (time_after (jiffies, timeo)) {
@@ -932,7 +899,7 @@ static int get_chip(struct map_info *map chip->state =FL_ERASE_SUSPENDING ; chip->erase_suspended =1 ;for (;;) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;if (time_after (jiffies, timeo)) {
@@ -1463,7 +1430,7 @@ static int do_otp_lock(struct map_info */* wait for chip to become ready */ timeo = jiffies +msecs_to_jiffies (2 );for (;;) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;if (time_after (jiffies, timeo)) {
@@ -1695,11 +1662,11 @@ static int __xipram do_write_oneword_onc }/* -* We check "time_after" and "!chip_good" before checking -* "chip_good" to avoid the failure due to scheduling. +* We check "time_after" and "!chip_ready" before checking +* "chip_ready" to avoid the failure due to scheduling. */ if (time_after (jiffies, timeo) && - !chip_good (map, chip, adr, datum)) { + !chip_ready (map, chip, adr, &datum)) {xip_enable (map, chip, adr);printk (KERN_WARNING "MTD %s(): software timeout\n" , __func__);xip_disable (map, chip, adr);
@@ -1707,7 +1674,7 @@ static int __xipram do_write_oneword_oncbreak ; } -if (chip_good (map, chip, adr, datum)) { +if (chip_ready (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -1975,18 +1942,18 @@ static int __xipram do_write_buffer_wait }/* -* We check "time_after" and "!chip_good" before checking -* "chip_good" to avoid the failure due to scheduling. +* We check "time_after" and "!chip_ready" before checking +* "chip_ready" to avoid the failure due to scheduling. */ if (time_after (jiffies, timeo) && - !chip_good (map, chip, adr, datum)) { + !chip_ready (map, chip, adr, &datum)) {pr_err ("MTD %s(): software timeout, address:0x%.8lx.\n" , __func__, adr); ret = -EIO ;break ; } -if (chip_good (map, chip, adr, datum)) { +if (chip_ready (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -2195,7 +2162,7 @@ static int cfi_amdstd_panic_wait(struct* If the driver thinks the chip is idle, and no toggle bits * are changing, then the chip is actually idle for sure. */ -if (chip->state ==FL_READY &&chip_ready (map, chip, adr)) +if (chip->state ==FL_READY &&chip_ready (map, chip, adr,NULL ))return 0 ;/*
@@ -2212,7 +2179,7 @@ static int cfi_amdstd_panic_wait(struct/* wait for the chip to become ready */ for (i =0 ; i <jiffies_to_usecs (timeo); i++) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))return 0 ;udelay (1 );
@@ -2276,13 +2243,13 @@ retry:map_write (map, datum, adr);for (i =0 ; i <jiffies_to_usecs (uWriteTimeout); i++) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;udelay (1 ); } -if (!chip_good (map, chip, adr, datum) || +if (!chip_ready (map, chip, adr, &datum) ||cfi_check_err_status (map, chip, adr)) {/* reset on all failures. */ map_write (map,CMD (0xF0 ), chip->start);
@@ -2424,6 +2391,7 @@ static int __xipram do_erase_chip(structDECLARE_WAITQUEUE (wait, current);int ret;int retry_cnt =0 ; +map_word datum =map_word_ff (map); adr = cfi->addr_unlock1;
@@ -2478,7 +2446,7 @@ static int __xipram do_erase_chip(struct chip->erase_suspended =0 ; } -if (chip_good (map, chip, adr,map_word_ff (map))) { +if (chip_ready (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -2523,6 +2491,7 @@ static int __xipram do_erase_oneblock(stDECLARE_WAITQUEUE (wait, current);int ret;int retry_cnt =0 ; +map_word datum =map_word_ff (map); adr += chip->start;
@@ -2577,7 +2546,7 @@ static int __xipram do_erase_oneblock(st chip->erase_suspended =0 ; } -if (chip_good (map, chip, adr,map_word_ff (map))) { +if (chip_ready (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -2771,7 +2740,7 @@ static int __maybe_unused do_ppb_xxlock(*/ timeo = jiffies +msecs_to_jiffies (2000 );/* 2s max (un)locking */ for (;;) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;if (time_after (jiffies, timeo)) {
Greg Kroah-Hartman
maintainerPATCH 801/879 mtd: cfi_cmdset_0002: Use chip_ready() for write on S29GL064N
In reply to Greg Kroah-HartmanFrom: Tokunori Ikegami <[email protected]>
commit 0a8e98305f63deaf0a799d5cf5532cc83af035d1 upstream.
Since commit dfeae1073583("mtd: cfi_cmdset_0002: Change write buffer to check correct value") buffered writes fail on S29GL064N. This is because, on S29GL064N, reads return 0xFF at the end of DQ polling for write completion, where as, chip_good() check expects actual data written to the last location to be returned post DQ polling completion. Fix is to revert to using chip_good() for S29GL064N which only checks for DQ lines to settle down to determine write completion.
--- drivers/mtd/chips/cfi_cmdset_0002.c | 42 +++++++++++++++++++++++++++++------- include/linux/mtd/cfi.h | 1 2 files changed, 35 insertions(+), 8 deletions(-)
drivers/mtd/chips/cfi_cmdset_0002.c +34 -8
@@ -59,6 +59,10 @@#define CFI_SR_WBASB BIT(3)#define CFI_SR_SLSB BIT(1) +enum cfi_quirks { +CFI_QUIRK_DQ_TRUE_DATA =BIT (0 ), +}; +static int cfi_amdstd_read (struct mtd_info *,loff_t ,size_t ,size_t *,u_char *);static int cfi_amdstd_write_words (struct mtd_info *,loff_t ,size_t ,size_t *,const u_char *);#if !FORCE_WORD_WRITE
@@ -436,6 +440,15 @@ static void fixup_s29ns512p_sectors(stru mtd->name); } +static void fixup_quirks (struct mtd_info *mtd) +{ +struct map_info *map = mtd->priv; +struct cfi_private *cfi = map->fldrv_priv; + +if (cfi->mfr ==CFI_MFR_AMD && cfi->id ==0x0c01 ) + cfi->quirks |=CFI_QUIRK_DQ_TRUE_DATA ; +} +/* Used to fix CFI-Tables of chips without Extended Query Tables */ static struct cfi_fixup cfi_nopri_fixup_table[] = { {CFI_MFR_SST ,0x234a , fixup_sst39vf },/* SST39VF1602 */
@@ -474,6 +487,7 @@ static struct cfi_fixup cfi_fixup_table[ #if !FORCE_WORD_WRITE { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, #endif + { CFI_MFR_ANY, CFI_ID_ANY, fixup_quirks }, { 0, 0, NULL } }; static struct cfi_fixup jedec_fixup_table[] = {
@@ -846,6 +860,18 @@ static int __xipram chip_ready(struct mareturn map_word_equal (map, t, *expected); } +static int __xipram chip_good(struct map_info *map, struct flchip *chip, +unsigned long addr,map_word *expected) +{ +struct cfi_private *cfi = map->fldrv_priv; +map_word *datum = expected; + +if (cfi->quirks &CFI_QUIRK_DQ_TRUE_DATA ) + datum =NULL ; + +return chip_ready (map, chip, addr, datum); +} +static int get_chip (struct map_info *map,struct flchip *chip,unsigned long adr,int mode) {DECLARE_WAITQUEUE (wait, current);
@@ -1662,11 +1688,11 @@ static int __xipram do_write_oneword_onc }/* -* We check "time_after" and "!chip_ready" before checking -* "chip_ready" to avoid the failure due to scheduling. +* We check "time_after" and "!chip_good" before checking +* "chip_good" to avoid the failure due to scheduling. */ if (time_after (jiffies, timeo) && - !chip_ready (map, chip, adr, &datum)) { + !chip_good (map, chip, adr, &datum)) {xip_enable (map, chip, adr);printk (KERN_WARNING "MTD %s(): software timeout\n" , __func__);xip_disable (map, chip, adr);
@@ -1674,7 +1700,7 @@ static int __xipram do_write_oneword_oncbreak ; } -if (chip_ready (map, chip, adr, &datum)) { +if (chip_good (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -1942,18 +1968,18 @@ static int __xipram do_write_buffer_wait }/* -* We check "time_after" and "!chip_ready" before checking -* "chip_ready" to avoid the failure due to scheduling. +* We check "time_after" and "!chip_good" before checking +* "chip_good" to avoid the failure due to scheduling. */ if (time_after (jiffies, timeo) && - !chip_ready (map, chip, adr, &datum)) { + !chip_good (map, chip, adr, &datum)) {pr_err ("MTD %s(): software timeout, address:0x%.8lx.\n" , __func__, adr); ret = -EIO ;break ; } -if (chip_ready (map, chip, adr, &datum)) { +if (chip_good (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
include/linux/mtd/cfi.h +1 -0
@@ -286,6 +286,7 @@ struct cfi_private {map_word sector_erase_cmd;unsigned long chipshift;/* Because they're of the same type */ const char *im_name;/* inter_module name for cmdset_setup */ +unsigned long quirks;struct flchip chips[];/* per-chip data structure for each chip */ };
Greg Kroah-Hartman
maintainerPATCH 802/879 media: coda: Fix reported H264 profile
In reply to Greg Kroah-HartmanFrom: Nicolas Dufresne <[email protected]>
commit 7110c08ea71953a7fc342f0b76046f72442cf26c upstream.
The CODA960 manual states that ASO/FMO features of baseline are not supported, so for this reason this driver should only report constrained baseline support.
This fixes negotiation issue with constrained baseline content on GStreamer 1.17.1.
ASO/FMO features are unsupported for the encoder and untested for the decoder because there is currently no userspace support. Neither GStreamer parsers nor FFMPEG parsers support ASO/FMO.
--- drivers/media/platform/chips-media/coda-common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/media/platform/chips-media/coda-common.c +3 -3
@@ -2352,8 +2352,8 @@ static void coda_encode_ctrls(struct cod V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, -12, 12, 1, 0);v4l2_ctrl_new_std_menu (&ctx->ctrls, &coda_ctrl_ops,V4L2_CID_MPEG_VIDEO_H264_PROFILE , -V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE ,0x0 , -V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE ); +V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE ,0x0 , +V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE );if (ctx->dev->devtype->product ==CODA_HX4 || ctx->dev->devtype->product ==CODA_7541 ) { v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
@@ -2434,7 +2434,7 @@ static void coda_decode_ctrls(struct cod ctx->h264_profile_ctrl =v4l2_ctrl_new_std_menu (&ctx->ctrls, &coda_ctrl_ops,V4L2_CID_MPEG_VIDEO_H264_PROFILE ,V4L2_MPEG_VIDEO_H264_PROFILE_HIGH , - ~((1 <<V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE ) | + ~((1 <<V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE ) | (1 <<V4L2_MPEG_VIDEO_H264_PROFILE_MAIN ) | (1 <<V4L2_MPEG_VIDEO_H264_PROFILE_HIGH )),V4L2_MPEG_VIDEO_H264_PROFILE_HIGH );
Greg Kroah-Hartman
maintainerPATCH 803/879 media: coda: Add more H264 levels for CODA960
In reply to Greg Kroah-HartmanFrom: Nicolas Dufresne <[email protected]>
commit eb2fd187abc878a2dfad46902becb74963473c7d upstream.
Add H264 level 1.0, 4.1, 4.2 to the list of supported formats. While the hardware does not fully support these levels, it does support most of them. The constraints on frame size and pixel formats already cover the limitation.
This fixes negotiation of level on GStreamer 1.17.1.
--- drivers/media/platform/chips-media/coda-common.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/media/platform/chips-media/coda-common.c +6 -3
@@ -2367,12 +2367,15 @@ static void coda_encode_ctrls(struct codif (ctx->dev->devtype->product ==CODA_960 ) {v4l2_ctrl_new_std_menu (&ctx->ctrls, &coda_ctrl_ops,V4L2_CID_MPEG_VIDEO_H264_LEVEL , -V4L2_MPEG_VIDEO_H264_LEVEL_4_0 , - ~((1 <<V4L2_MPEG_VIDEO_H264_LEVEL_2_0 ) | +V4L2_MPEG_VIDEO_H264_LEVEL_4_2 , + ~((1 <<V4L2_MPEG_VIDEO_H264_LEVEL_1_0 ) | + (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_2_0 ) | (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_3_0 ) | (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_3_1 ) | (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_3_2 ) | - (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_4_0 )), + (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_4_0 ) | + (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_4_1 ) | + (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_4_2 )),V4L2_MPEG_VIDEO_H264_LEVEL_4_0 ); } v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
Greg Kroah-Hartman
maintainerPATCH 804/879 ima: remove the IMA_TEMPLATE Kconfig option
In reply to Greg Kroah-HartmanFrom: GUO Zihua <[email protected]>
commit 891163adf180bc369b2f11c9dfce6d2758d2a5bd upstream.
The original 'ima' measurement list template contains a hash, defined as 20 bytes, and a null terminated pathname, limited to 255 characters. Other measurement list templates permit both larger hashes and longer pathnames. When the "ima" template is configured as the default, a new measurement list template (ima_template=) must be specified before specifying a larger hash algorithm (ima_hash=) on the boot command line.
To avoid this boot command line ordering issue, remove the legacy "ima" template configuration option, allowing it to still be specified on the boot command line.
The root cause of this issue is that during the processing of ima_hash, we would try to check whether the hash algorithm is compatible with the template. If the template is not set at the moment we do the check, we check the algorithm against the configured default template. If the default template is "ima", then we reject any hash algorithm other than sha1 and md5.
For example, if the compiled default template is "ima", and the default algorithm is sha1 (which is the current default). In the cmdline, we put in "ima_hash=sha256 ima_template=ima-ng". The expected behavior would be that ima starts with ima-ng as the template and sha256 as the hash algorithm. However, during the processing of "ima_hash=", "ima_template=" has not been processed yet, and hash_setup would check the configured hash algorithm against the compiled default: ima, and reject sha256. So at the end, the hash algorithm that is actually used will be sha1.
With template "ima" removed from the configured default, we ensure that the default tempalte would at least be "ima-ng" which allows for basically any hash algorithm.
This change would not break the algorithm compatibility checks for IMA.
--- security/integrity/ima/Kconfig | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
security/integrity/ima/Kconfig +6 -8
@@ -69,10 +69,9 @@ choice hash, defined as 20 bytes, and a null terminated pathname, limited to 255 characters. The 'ima-ng' measurement list template permits both larger hash digests and longer - pathnames. + pathnames. The configured default template can be replaced + by specifying "ima_template=" on the boot command line. - config IMA_TEMPLATE - bool "ima" config IMA_NG_TEMPLATE bool "ima-ng (default)" config IMA_SIG_TEMPLATE
@@ -82,7 +81,6 @@ endchoice config IMA_DEFAULT_TEMPLATE string depends on IMA - default "ima" if IMA_TEMPLATE default "ima-ng" if IMA_NG_TEMPLATE default "ima-sig" if IMA_SIG_TEMPLATE
@@ -102,19 +100,19 @@ choice config IMA_DEFAULT_HASH_SHA256 bool "SHA256" - depends on CRYPTO_SHA256=y && !IMA_TEMPLATE + depends on CRYPTO_SHA256=y config IMA_DEFAULT_HASH_SHA512 bool "SHA512" - depends on CRYPTO_SHA512=y && !IMA_TEMPLATE + depends on CRYPTO_SHA512=y config IMA_DEFAULT_HASH_WP512 bool "WP512" - depends on CRYPTO_WP512=y && !IMA_TEMPLATE + depends on CRYPTO_WP512=y config IMA_DEFAULT_HASH_SM3 bool "SM3" - depends on CRYPTO_SM3=y && !IMA_TEMPLATE + depends on CRYPTO_SM3=y endchoice config IMA_DEFAULT_HASH
Greg Kroah-Hartman
maintainerPATCH 805/879 Kconfig: Add option for asm goto w/ tied outputs to workaround clang-13 bug
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
commit 1aa0e8b144b6474c4914439d232d15bfe883636b upstream.
Add a config option to guard (future) usage of asm_volatile_goto() that includes "tied outputs", i.e. "+" constraints that specify both an input and output parameter. clang-13 has a bug[1] that causes compilation of such inline asm to fail, and KVM wants to use a "+m" constraint to implement a uaccess form of CMPXCHG[2]. E.g. the test code fails with
<stdin>:1:29: error: invalid operand in inline asm: '.long (${1:l}) - .'
int foo(int *x) { asm goto (".long (%l[bar]) - .\n": "+m"(*x) ::: bar); return *x; bar: return 0; }
^
<stdin>:1:29: error: unknown token in expression
<inline asm>:1:9: note: instantiated into assembly here
.long () - .
^2 errors generated.
on clang-13, but passes on gcc (with appropriate asm goto support). The bug is fixed in clang-14, but won't be backported to clang-13 as the changes are too invasive/risky.
gcc also had a similar bug[3], fixed in gcc-11, where gcc failed to account for its behavior of assigning two numbers to tied outputs (one for input, one for output) when evaluating symbolic references.
[1] https://github.com/ClangBuiltLinux/linux/issues/1512
[2] https://lore.kernel.org/all/YfMruK8%[email protected]
[3] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98096
Message-Id: <[email protected]>
--- init/Kconfig | 5 +++++ 1 file changed, 5 insertions(+)
init/Kconfig +5 -0
@@ -77,6 +77,11 @@ config CC_HAS_ASM_GOTO_OUTPUT depends on CC_HAS_ASM_GOTO def_bool $(success,echo 'int foo(int x) { asm goto ("": "=r"(x) ::: bar); return x; bar: return 0; }' | $(CC) -x c - -c -o /dev/null) +config CC_HAS_ASM_GOTO_TIED_OUTPUT + depends on CC_HAS_ASM_GOTO_OUTPUT + # Detect buggy gcc and clang, fixed in gcc-11 clang-14. + def_bool $(success,echo 'int foo(int *x) { asm goto (".long (%l[bar]) - .\n": "+m"(*x) ::: bar); return *x; bar: return 0; }' | $CC -x c - -c -o /dev/null) + config TOOLS_SUPPORT_RELR def_bool $(success,env "CC=$(CC)" "LD=$(LD)" "NM=$(NM)" "OBJCOPY=$(OBJCOPY)" $(srctree)/scripts/tools-support-relr.sh)
Greg Kroah-Hartman
maintainerPATCH 806/879 lib/string_helpers: fix not adding strarray to devices resource list
In reply to Greg Kroah-HartmanFrom: Puyou Lu <[email protected]>
commit cd290a9839cee2f6641558877e707bd373c8f6f1 upstream.
Add allocated strarray to device's resource list. This is a must to automatically release strarray when the device disappears.
Without this fix we have a memory leak in the few drivers which use devm_kasprintf_strarray().
--- lib/string_helpers.c | 3 +++ 1 file changed, 3 insertions(+)
lib/string_helpers.c +3 -0
@@ -757,6 +757,9 @@ char **devm_kasprintf_strarray(struct dereturn ERR_PTR (-ENOMEM ); } + ptr->n = n; +devres_add (dev, ptr); +return ptr->array; }EXPORT_SYMBOL_GPL (devm_kasprintf_strarray);
Greg Kroah-Hartman
maintainerPATCH 807/879 RDMA/hfi1: Fix potential integer multiplication overflow errors
In reply to Greg Kroah-HartmanFrom: Dennis Dalessandro <[email protected]>
commit f93e91a0372c922c20d5bee260b0f43b4b8a1bee upstream.
When multiplying of different types, an overflow is possible even when storing the result in a larger type. This is because the conversion is done after the multiplication. So arithmetic overflow and thus in incorrect value is possible.
Correct an instance of this in the inter packet delay calculation. Fix by ensuring one of the operands is u64 which will promote the other to u64 as well ensuring no overflow.
--- drivers/infiniband/hw/hfi1/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/hfi1/init.c +1 -1
@@ -489,7 +489,7 @@ void set_link_ipg(struct hfi1_pportdatau16 shift, mult;u64 src;u32 current_egress_rate;/* Mbits /sec */ -u32 max_pkt_time; +u64 max_pkt_time;/* * max_pkt_time is the maximum packet egress time in units * of the fabric clock period 1/(805 MHz).
Greg Kroah-Hartman
maintainerPATCH 808/879 mmc: core: Allows to override the timeout value for ioctl() path
In reply to Greg Kroah-HartmanFrom: Bean Huo <[email protected]>
commit 23e09be254f95a5b75cd87f91a4014f3b46dda3f upstream.
Occasionally, user-land applications initiate longer timeout values for certain commands through ioctl() system call. But so far we are still using a fixed timeout of 10 seconds in mmc_poll_for_busy() on the ioctl() path, even if a custom timeout is specified in the userspace application. This patch allows custom timeout values to override this default timeout values on the ioctl path.
--- drivers/mmc/core/block.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/mmc/core/block.c +4 -4
@@ -609,11 +609,11 @@ static int __mmc_blk_ioctl_cmd(struct mmif (idata->rpmb || (cmd.flags &MMC_RSP_R1B ) ==MMC_RSP_R1B ) {/* -* Ensure RPMB/R1B command has completed by polling CMD13 -* "Send Status". +* Ensure RPMB/R1B command has completed by polling CMD13 "Send Status". Here we +* allow to override the default timeout value if a custom timeout is specified. */ - err =mmc_poll_for_busy (card,MMC_BLK_TIMEOUT_MS , false, -MMC_BUSY_IO ); + err =mmc_poll_for_busy (card, idata->ic.cmd_timeout_ms ? :MMC_BLK_TIMEOUT_MS , + false,MMC_BUSY_IO ); }return err;
Greg Kroah-Hartman
maintainerPATCH 809/879 csky: patch_text: Fixup last cpu should be master
In reply to Greg Kroah-HartmanFrom: Guo Ren <[email protected]>
commit 8c4d16471e2babe9bdfe41d6ef724526629696cb upstream.
These patch_text implementations are using stop_machine_cpuslocked infrastructure with atomic cpu_count. The original idea: When the master CPU patch_text, the others should wait for it. But current implementation is using the first CPU as master, which couldn't guarantee the remaining CPUs are waiting. This patch changes the last CPU as the master to solve the potential risk.
--- arch/csky/kernel/probes/kprobes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/csky/kernel/probes/kprobes.c +1 -1
@@ -30,7 +30,7 @@ static int __kprobes patch_text_cb(voidstruct csky_insn_patch *param = priv;unsigned int addr = (unsigned int )param->addr; -if (atomic_inc_return (¶m->cpu_count) ==1 ) { +if (atomic_inc_return (¶m->cpu_count) ==num_online_cpus ()) { *(u16 *) addr =cpu_to_le16 (param->opcode);dcache_wb_range (addr, addr +2 );atomic_inc (¶m->cpu_count);
Greg Kroah-Hartman
maintainerPATCH 810/879 irqchip/armada-370-xp: Do not touch Performance Counter Overflow on A375, A38x, A39x
In reply to Greg Kroah-HartmanFrom: Pali Rohár <[email protected]>
commit a3d66a76348daf559873f19afc912a2a7c2ccdaf upstream.
Register ARMADA_370_XP_INT_FABRIC_MASK_OFFS is Armada 370 and XP specific and on new Armada platforms it has different meaning. It does not configure Performance Counter Overflow interrupt masking. So do not touch this register on non-A370/XP platforms (A375, A38x and A39x).
--- drivers/irqchip/irq-armada-370-xp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
drivers/irqchip/irq-armada-370-xp.c +10 -1
@@ -308,7 +308,16 @@ static inline int armada_370_xp_msi_initstatic void armada_xp_mpic_perf_init (void ) { -unsigned long cpuid =cpu_logical_map (smp_processor_id ()); +unsigned long cpuid; + +/* +* This Performance Counter Overflow interrupt is specific for +* Armada 370 and XP. It is not available on Armada 375, 38x and 39x. +*/ +if (!of_machine_is_compatible ("marvell,armada-370-xp" )) +return ; + + cpuid =cpu_logical_map (smp_processor_id ());/* Enable Performance Counter Overflow interrupts */ writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid),
Greg Kroah-Hartman
maintainerPATCH 811/879 irqchip: irq-xtensa-mx: fix initial IRQ affinity
In reply to Greg Kroah-HartmanFrom: Max Filippov <[email protected]>
commit a255ee29252066d621df5d6b420bf534c6ba5bc0 upstream.
When irq-xtensa-mx chip is used in non-SMP configuration its irq_set_affinity callback is not called leaving IRQ affinity set empty. As a result IRQ delivery does not work in that configuration. Initialize IRQ affinity of the xtensa MX interrupt distributor to CPU 0 for all external IRQ lines.
--- drivers/irqchip/irq-xtensa-mx.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
drivers/irqchip/irq-xtensa-mx.c +14 -4
@@ -151,14 +151,25 @@ static struct irq_chip xtensa_mx_irq_chi .irq_set_affinity = xtensa_mx_irq_set_affinity, }; +static void __init xtensa_mx_init_common (struct irq_domain *root_domain) +{ +unsigned int i; + +irq_set_default_host (root_domain); +secondary_init_irq (); + +/* Initialize default IRQ routing to CPU 0 */ +for (i =0 ; i <XCHAL_NUM_EXTINTERRUPTS ; ++i) +set_er (1 ,MIROUT (i)); +} +int __init xtensa_mx_init_legacy (struct device_node *interrupt_parent) {struct irq_domain *root_domain =irq_domain_add_legacy (NULL ,NR_IRQS -1 ,1 ,0 , &xtensa_mx_irq_domain_ops, &xtensa_mx_irq_chip); -irq_set_default_host (root_domain); -secondary_init_irq (); +xtensa_mx_init_common (root_domain);return 0 ; }
@@ -168,8 +179,7 @@ static int __init xtensa_mx_init(structstruct irq_domain *root_domain =irq_domain_add_linear (np,NR_IRQS , &xtensa_mx_irq_domain_ops, &xtensa_mx_irq_chip); -irq_set_default_host (root_domain); -secondary_init_irq (); +xtensa_mx_init_common (root_domain);return 0 ; }IRQCHIP_DECLARE (xtensa_mx_irq_chip,"cdns,xtensa-mx" , xtensa_mx_init);