Skip to contentSkip to conversation

arm64: Enable BTI for the executable as well as the interpreter

PATCH Applied Mark Brown 5 participants 15 messages Apr 19, 2022 – Apr 21, 2022

Subsystems (4)
lore
Share & tools
lore

Mark Brown

author
#0 lore raw

v13 cover arm64: Enable BTI for the executable as well as the interpreter

Deployments of BTI on arm64 have run into issues interacting with systemd's MemoryDenyWriteExecute feature. Currently for dynamically linked executables the kernel will only handle architecture specific properties like BTI for the interpreter, the expectation is that the interpreter will then handle any properties on the main executable. For BTI this means remapping the executable segments PROT_EXEC | PROT_BTI.

This interacts poorly with MemoryDenyWriteExecute since that is implemented using a seccomp filter which prevents setting PROT_EXEC on already mapped memory and lacks the context to be able to detect that memory is already mapped with PROT_EXEC. This series resolves this by providing a sysctl which when enabled will cause the kernel to handle the BTI property for both the interpreter and the main executable.

v13:
- Rebase onto v5.18-rc3.
v12:
- Rebase onto v5.18-rc1.
v11:
- Ignore extra PT_INTERPs.
v10:
- Add a sysctl abi.bti_main controlling the new behaviour.
v9:
- Rebase onto v5.17-rc3.
v8:
- Rebase onto v5.17-rc1.
v7:
- Rebase onto v5.16-rc1.
v6:
- Rebase onto v5.15-rc1.
v5:
- Rebase onto v5.14-rc2.
- Tweak changelog on patch 1.
- Use the helper for interpreter/executable flag in elf.h as well.
v4:
- Rebase onto v5.14-rc1.
v3:
- Fix passing of properties for parsing by the main executable.
- Drop has_interp from arch_parse_elf_property().
- Coding style tweaks.
v2:
- Add a patch dropping has_interp from arch_adjust_elf_prot()
- Fix bisection issue with static executables on arm64 in the first patch.

Mark Brown (2):
elf: Allow architectures to parse properties on the main executable
arm64: Enable BTI for main executable as well as the interpreter

 arch/arm64/include/asm/elf.h | 14 ++++++++--
 arch/arm64/kernel/process.c  | 52 +++++++++++++++++++++++++++---------
 fs/binfmt_elf.c              | 34 ++++++++++++++++-------
 include/linux/elf.h          |  4 ++-
 4 files changed, 78 insertions(+), 26 deletions(-)

base-commit: b2d229d4ddb17db541098b83524d901257e93845

Signature · 1 line
2.30.2
author
#1 lore raw

PATCH v13 1/2 elf: Allow architectures to parse properties on the main executable

Currently the ELF code only attempts to parse properties on the image that will start execution, either the interpreter or for statically linked executables the main executable. The expectation is that any property handling for the main executable will be done by the interpreter. This is a bit inconsistent since we do map the executable and is causing problems for the arm64 BTI support when used in conjunction with systemd's use of seccomp to implement MemoryDenyWriteExecute which stops the dynamic linker adjusting the permissions of executable segments.

Allow architectures to handle properties for both the dynamic linker and main executable, adjusting arch_parse_elf_properties() to have a new flag is_interp flag as with arch_elf_adjust_prot() and calling it for both the main executable and any intepreter.

The user of this code, arm64, is adapted to ensure that there is no functional change.

---
 arch/arm64/include/asm/elf.h |  3 ++-
 fs/binfmt_elf.c              | 34 ++++++++++++++++++++++++----------
 include/linux/elf.h          |  4 +++-
 3 files changed, 29 insertions(+), 12 deletions(-)
arch/arm64/include/asm/elf.h +2 -1
index 97932fbf973d..5cc002376abe 100644
@@ -259,6 +259,7 @@ struct arch_elf_state {
 
 static inline int arch_parse_elf_property(u32 type, const void *data,
 					  size_t datasz, bool compat,
+					  bool has_interp, bool is_interp,
 					  struct arch_elf_state *arch)
 {
 	/* No known properties for AArch32 yet */
@@ -271,7 +272,7 @@ static inline int arch_parse_elf_property(u32 type, const void *data,
 		if (datasz != sizeof(*p))
 			return -ENOEXEC;
 
-		if (system_supports_bti() &&
+		if (system_supports_bti() && has_interp == is_interp &&
 		    (*p & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
 			arch->flags |= ARM64_ELF_BTI;
 	}
fs/binfmt_elf.c +24 -10
index 63c7ebb0da89..ed09918d6d69 100644
@@ -717,8 +717,9 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
  */
 
 static int parse_elf_property(const char *data, size_t *off, size_t datasz,
-			      struct arch_elf_state *arch,
-			      bool have_prev_type, u32 *prev_type)
+			      struct arch_elf_state *arch, bool has_interp,
+			      bool is_interp, bool have_prev_type,
+			      u32 *prev_type)
 {
 	size_t o, step;
 	const struct gnu_property *pr;
@@ -752,7 +753,8 @@ static int parse_elf_property(const char *data, size_t *off, size_t datasz,
 	*prev_type = pr->pr_type;
 
 	ret = arch_parse_elf_property(pr->pr_type, data + o,
-				      pr->pr_datasz, ELF_COMPAT, arch);
+				      pr->pr_datasz, ELF_COMPAT,
+				      has_interp, is_interp, arch);
 	if (ret)
 		return ret;
 
@@ -765,6 +767,7 @@ static int parse_elf_property(const char *data, size_t *off, size_t datasz,
 #define NOTE_NAME_SZ (sizeof(GNU_PROPERTY_TYPE_0_NAME))
 
 static int parse_elf_properties(struct file *f, const struct elf_phdr *phdr,
+				bool has_interp, bool is_interp,
 				struct arch_elf_state *arch)
 {
 	union {
@@ -814,7 +817,8 @@ static int parse_elf_properties(struct file *f, const struct elf_phdr *phdr,
 	have_prev_type = false;
 	do {
 		ret = parse_elf_property(note.data, &off, datasz, arch,
-					 have_prev_type, &prev_type);
+					 has_interp, is_interp, have_prev_type,
+					 &prev_type);
 		have_prev_type = true;
 	} while (!ret);
 
@@ -829,6 +833,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
 	unsigned long error;
 	struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL;
 	struct elf_phdr *elf_property_phdata = NULL;
+	struct elf_phdr *interp_elf_property_phdata = NULL;
 	unsigned long elf_bss, elf_brk;
 	int bss_prot = 0;
 	int retval, i;
@@ -866,12 +871,15 @@ static int load_elf_binary(struct linux_binprm *bprm)
 	for (i = 0; i < elf_ex->e_phnum; i++, elf_ppnt++) {
 		char *elf_interpreter;
 
+		if (interpreter && elf_property_phdata)
+			break;
+
 		if (elf_ppnt->p_type == PT_GNU_PROPERTY) {
 			elf_property_phdata = elf_ppnt;
 			continue;
 		}
 
-		if (elf_ppnt->p_type != PT_INTERP)
+		if (interpreter || elf_ppnt->p_type != PT_INTERP)
 			continue;
 
 		/*
@@ -920,7 +928,7 @@ static int load_elf_binary(struct linux_binprm *bprm)
 		if (retval < 0)
 			goto out_free_dentry;
 
-		break;
+		continue;
 
 out_free_interp:
 		kfree(elf_interpreter);
@@ -964,12 +972,11 @@ static int load_elf_binary(struct linux_binprm *bprm)
 			goto out_free_dentry;
 
 		/* Pass PT_LOPROC..PT_HIPROC headers to arch code */
-		elf_property_phdata = NULL;
 		elf_ppnt = interp_elf_phdata;
 		for (i = 0; i < interp_elf_ex->e_phnum; i++, elf_ppnt++)
 			switch (elf_ppnt->p_type) {
 			case PT_GNU_PROPERTY:
-				elf_property_phdata = elf_ppnt;
+				interp_elf_property_phdata = elf_ppnt;
 				break;
 
 			case PT_LOPROC ... PT_HIPROC:
@@ -980,10 +987,17 @@ static int load_elf_binary(struct linux_binprm *bprm)
 					goto out_free_dentry;
 				break;
 			}
+
+		retval = parse_elf_properties(interpreter,
+					      interp_elf_property_phdata,
+					      true, true, &arch_state);
+		if (retval)
+			goto out_free_dentry;
+
 	}
 
-	retval = parse_elf_properties(interpreter ?: bprm->file,
-				      elf_property_phdata, &arch_state);
+	retval = parse_elf_properties(bprm->file, elf_property_phdata,
+				      interpreter, false, &arch_state);
 	if (retval)
 		goto out_free_dentry;
 
include/linux/elf.h +3 -1
index c9a46c4e183b..1c45ecf29147 100644
@@ -88,13 +88,15 @@ struct arch_elf_state;
 #ifndef CONFIG_ARCH_USE_GNU_PROPERTY
 static inline int arch_parse_elf_property(u32 type, const void *data,
 					  size_t datasz, bool compat,
+					  bool has_interp, bool is_interp,
 					  struct arch_elf_state *arch)
 {
 	return 0;
 }
 #else
 extern int arch_parse_elf_property(u32 type, const void *data, size_t datasz,
-				   bool compat, struct arch_elf_state *arch);
+				   bool compat, bool has_interp, bool is_interp,
+				   struct arch_elf_state *arch);
 #endif
 
 #ifdef CONFIG_ARCH_HAVE_ELF_PROT
Signature · 1 line
2.30.2
Acked-by on v13 1/2
#2 lore raw

Re: [PATCH v13 1/2] elf: Allow architectures to parse properties on the main executable

Quoted 14 lines · Mark Brown

Currently the ELF code only attempts to parse properties on the image that will start execution, either the interpreter or for statically linked executables the main executable. The expectation is that any property handling for the main executable will be done by the interpreter. This is a bit inconsistent since we do map the executable and is causing problems for the arm64 BTI support when used in conjunction with systemd's use of seccomp to implement MemoryDenyWriteExecute which stops the dynamic linker adjusting the permissions of executable segments.

Allow architectures to handle properties for both the dynamic linker and main executable, adjusting arch_parse_elf_properties() to have a new flag is_interp flag as with arch_elf_adjust_prot() and calling it for both the main executable and any intepreter.

Quoted 4 lines

The user of this code, arm64, is adapted to ensure that there is no functional change.

Signature · 1 line
Kees Cook
author
#3 lore raw

PATCH v13 2/2 arm64: Enable BTI for main executable as well as the interpreter

In reply to Mark Brown

Currently for dynamically linked ELF executables we only enable BTI for the interpreter, expecting the interpreter to do this for the main executable. This is a bit inconsistent since we do map main executable and is causing issues with systemd's MemoryDenyWriteExecute feature which is implemented using a seccomp filter which prevents setting PROT_EXEC on already mapped memory and lacks the context to be able to detect that memory is already mapped with PROT_EXEC.

Resolve this by adding a sysctl abi.bti_main which causes the kernel to checking the BTI property for the main executable and enable BTI if it is present when doing the initial mapping. This sysctl is disabled by default.

---
 arch/arm64/include/asm/elf.h | 15 ++++++++---
 arch/arm64/kernel/process.c  | 52 +++++++++++++++++++++++++++---------
 2 files changed, 51 insertions(+), 16 deletions(-)
arch/arm64/include/asm/elf.h +12 -3
index 5cc002376abe..c4aa60db76a4 100644
@@ -251,12 +251,21 @@ struct arch_elf_state {
 	int flags;
 };
 
-#define ARM64_ELF_BTI		(1 << 0)
+#define ARM64_ELF_INTERP_BTI		(1 << 0)
+#define ARM64_ELF_EXEC_BTI		(1 << 1)
 
 #define INIT_ARCH_ELF_STATE {			\
 	.flags = 0,				\
 }
 
+static inline int arm64_elf_bti_flag(bool is_interp)
+{
+	if (is_interp)
+		return ARM64_ELF_INTERP_BTI;
+	else
+		return ARM64_ELF_EXEC_BTI;
+}
+
 static inline int arch_parse_elf_property(u32 type, const void *data,
 					  size_t datasz, bool compat,
 					  bool has_interp, bool is_interp,
@@ -272,9 +281,9 @@ static inline int arch_parse_elf_property(u32 type, const void *data,
 		if (datasz != sizeof(*p))
 			return -ENOEXEC;
 
-		if (system_supports_bti() && has_interp == is_interp &&
+		if (system_supports_bti() &&
 		    (*p & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
-			arch->flags |= ARM64_ELF_BTI;
+			arch->flags |= arm64_elf_bti_flag(is_interp);
 	}
 
 	return 0;
arch/arm64/kernel/process.c +39 -13

62 lines not on this page · raw message

Signature · 1 line
2.30.2
Applied
#4 lore raw
In reply to Mark Brown
Quoted 9 lines · Mark Brown

Deployments of BTI on arm64 have run into issues interacting with systemd's MemoryDenyWriteExecute feature. Currently for dynamically linked executables the kernel will only handle architecture specific properties like BTI for the interpreter, the expectation is that the interpreter will then handle any properties on the main executable. For BTI this means remapping the executable segments PROT_EXEC | PROT_BTI.

[...]

Applied to for-next/execve, thanks!

[1/2] elf: Allow architectures to parse properties on the main executable

      https://git.kernel.org/kees/c/b2f2553c8e89
[2/2] arm64: Enable BTI for main executable as well as the interpreter
      https://git.kernel.org/kees/c/b65c760600e2
Signature · 1 line
Kees Cook
maintainer
#5 lore raw
Quoted 9 lines · Kees Cook
Quoted 8 lines · Mark Brown

Deployments of BTI on arm64 have run into issues interacting with systemd's MemoryDenyWriteExecute feature. Currently for dynamically linked executables the kernel will only handle architecture specific properties like BTI for the interpreter, the expectation is that the interpreter will then handle any properties on the main executable. For BTI this means remapping the executable segments PROT_EXEC | PROT_BTI.

Quoted 8 lines
Quoted 1 line

[...]

Applied to for-next/execve, thanks!

[1/2] elf: Allow architectures to parse properties on the main executable

      https://git.kernel.org/kees/c/b2f2553c8e89
[2/2] arm64: Enable BTI for main executable as well as the interpreter
      https://git.kernel.org/kees/c/b65c760600e2

Kees, please can you drop this series while Catalin's alternative solution is under discussion (his Reviewed-by preceded the other patches)?

https://lore.kernel.org/r/[email protected]

Both series expose new behaviours to userspace and we don't need both.

Thanks,

Will

maintainer
#6 lore raw
Quoted 19 lines · Will Deacon
Quoted 9 lines · Kees Cook
Quoted 8 lines · Mark Brown

Deployments of BTI on arm64 have run into issues interacting with systemd's MemoryDenyWriteExecute feature. Currently for dynamically linked executables the kernel will only handle architecture specific properties like BTI for the interpreter, the expectation is that the interpreter will then handle any properties on the main executable. For BTI this means remapping the executable segments PROT_EXEC | PROT_BTI.

Quoted 8 lines
Quoted 1 line

[...]

Applied to for-next/execve, thanks!

[1/2] elf: Allow architectures to parse properties on the main executable

      https://git.kernel.org/kees/c/b2f2553c8e89
[2/2] arm64: Enable BTI for main executable as well as the interpreter
      https://git.kernel.org/kees/c/b65c760600e2
Quoted 6 lines

Kees, please can you drop this series while Catalin's alternative solution is under discussion (his Reviewed-by preceded the other patches)?

https://lore.kernel.org/r/[email protected]

Both series expose new behaviours to userspace and we don't need both.

I agree. Even though the patches have my reviewed-by, I think we should postpone them until we figure out a better W^X solution that does not affect BTI (and if we can't, we revisit these patches).

Arguably, the two approaches are complementary but the way this series turned out is for the BTI on main executable to be default off. I have a worry that the feature won't get used, so we just carry unnecessary code in the kernel. Jeremy also found this approach less than ideal:

https://lore.kernel.org/r/[email protected]

Signature · 1 line
Catalin
author
#7 lore raw
Quoted 5 lines · Catalin Marinas
Quoted 2 lines · Will Deacon

Kees, please can you drop this series while Catalin's alternative solution is under discussion (his Reviewed-by preceded the other patches)?

Quoted 7 lines
Quoted 3 lines

https://lore.kernel.org/r/[email protected]

Both series expose new behaviours to userspace and we don't need both.

I agree. Even though the patches have my reviewed-by, I think we should postpone them until we figure out a better W^X solution that does not affect BTI (and if we can't, we revisit these patches).

Indeed. I had been expecting this to follow the pattern of the previous nine months or so and be mostly ignored for the time being while Catalin's new series goes forward. Now that it's applied it might be worth keeping the first patch still in case someone else needs it but the second patch can probably wait.

Quoted 6 lines

Arguably, the two approaches are complementary but the way this series turned out is for the BTI on main executable to be default off. I have a worry that the feature won't get used, so we just carry unnecessary code in the kernel. Jeremy also found this approach less than ideal:

https://lore.kernel.org/r/[email protected]

I'm not sure there was a fundamental concern with the approach there but rather some pushback on the instance on turning it off by default.

#8 lore raw

Hi,

Quoted 25 lines · Mark Brown
Quoted 5 lines · Catalin Marinas
Quoted 2 lines · Will Deacon

Kees, please can you drop this series while Catalin's alternative solution is under discussion (his Reviewed-by preceded the other patches)?

Quoted 7 lines
Quoted 3 lines

https://lore.kernel.org/r/[email protected]

Both series expose new behaviours to userspace and we don't need both.

I agree. Even though the patches have my reviewed-by, I think we should postpone them until we figure out a better W^X solution that does not affect BTI (and if we can't, we revisit these patches).

Indeed. I had been expecting this to follow the pattern of the previous nine months or so and be mostly ignored for the time being while Catalin's new series goes forward. Now that it's applied it might be worth keeping the first patch still in case someone else needs it but the second patch can probably wait.

Quoted 4 lines

Arguably, the two approaches are complementary but the way this series turned out is for the BTI on main executable to be default off. I have a worry that the feature won't get used, so we just carry unnecessary code in the kernel. Jeremy also found this approach less than ideal:

Quoted 4 lines
Quoted 1 line

https://lore.kernel.org/r/[email protected]

I'm not sure there was a fundamental concern with the approach there but rather some pushback on the instance on turning it off by default.

Right, this one seems to have the smallest impact on systemd as it exists today. I would have expected the default to be on, because IMHO this set corrects what at first glance just looks like a small oversight. I find the ABI questions a bit theoretical, given that this should only affect environments that don't exist outside of labs/development orgs at this point (aka systemd services on HW that implements BTI).

The other approach works, and if the systemd folks are on board with it also should solve the underlying problem, but it creates a bit of a compatibility problem with existing containers/etc that might exist today (although running systemd/services in a container is itself a discussion).

So, frankly, I don't see why they aren't complementary. This fixes a bug we have today, the other set creates a generic mechanism for the future.

Thanks,

#9 lore raw
Quoted 39 lines · Jeremy Linton
Quoted 25 lines · Mark Brown
Quoted 5 lines · Catalin Marinas
Quoted 2 lines · Will Deacon

Kees, please can you drop this series while Catalin's alternative solution is under discussion (his Reviewed-by preceded the other patches)?

Quoted 7 lines
Quoted 3 lines

https://lore.kernel.org/r/[email protected]

Both series expose new behaviours to userspace and we don't need both.

I agree. Even though the patches have my reviewed-by, I think we should postpone them until we figure out a better W^X solution that does not affect BTI (and if we can't, we revisit these patches).

Indeed. I had been expecting this to follow the pattern of the previous nine months or so and be mostly ignored for the time being while Catalin's new series goes forward. Now that it's applied it might be worth keeping the first patch still in case someone else needs it but the second patch can probably wait.

Quoted 4 lines

Arguably, the two approaches are complementary but the way this series turned out is for the BTI on main executable to be default off. I have a worry that the feature won't get used, so we just carry unnecessary code in the kernel. Jeremy also found this approach less than ideal:

Quoted 4 lines
Quoted 1 line

https://lore.kernel.org/r/[email protected]

I'm not sure there was a fundamental concern with the approach there but rather some pushback on the instance on turning it off by default.

Right, this one seems to have the smallest impact on systemd as it exists today. I would have expected the default to be on, because IMHO this set corrects what at first glance just looks like a small oversight. I find the ABI questions a bit theoretical, given that this should only affect environments that don't exist outside of labs/development orgs at this point (aka systemd services on HW that implements BTI).

Quoted 7 lines

The other approach works, and if the systemd folks are on board with it also should solve the underlying problem, but it creates a bit of a compatibility problem with existing containers/etc that might exist today (although running systemd/services in a container is itself a discussion).

So, frankly, I don't see why they aren't complementary. This fixes a bug we have today, the other set creates a generic mechanism for the future.

Okay, well, how about I drop this for now, and I'll Ack the ELF loader changes so this can go through the arm64 tree if there is consensus.

Signature · 1 line
Kees Cook
maintainer
#10 lore raw
In reply to Jeremy Linton
Quoted 9 lines · Jeremy Linton
Quoted 8 lines · Mark Brown
Quoted 7 lines · Catalin Marinas
Quoted 6 lines · Will Deacon

Kees, please can you drop this series while Catalin's alternative solution is under discussion (his Reviewed-by preceded the other patches)?

https://lore.kernel.org/r/[email protected]

Both series expose new behaviours to userspace and we don't need both.

[...]

Quoted 5 lines
Quoted 5 lines
Quoted 4 lines

Arguably, the two approaches are complementary but the way this series turned out is for the BTI on main executable to be default off. I have a worry that the feature won't get used, so we just carry unnecessary code in the kernel. Jeremy also found this approach less than ideal:

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

https://lore.kernel.org/r/[email protected]

I'm not sure there was a fundamental concern with the approach there but rather some pushback on the instance on turning it off by default.

Right, this one seems to have the smallest impact on systemd as it exists today.

It had a bigger impact on glibc which had to rework the dynamic library mapping to use munmap/mmap() instead of an mprotect() (though that's already done). I think glibc still prefers the mprotect() approach for dynamic libraries.

Quoted 2 lines

I would have expected the default to be on, because IMHO this set corrects what at first glance just looks like a small oversight.

This was a design decision at the time, maybe not the best but it gives us some flexibility (and we haven't thought of MDWE).

Quoted 3 lines

I find the ABI questions a bit theoretical, given that this should only affect environments that don't exist outside of labs/development orgs at this point (aka systemd services on HW that implements BTI).

The worry is not what breaks now but rather what happens when today's distros will eventually be deployed on large-scale BTI-capable hardware. It's a very small risk but non-zero. The idea is that if we come across some weird problem, a fixed-up dynamic loader could avoid enabling BTI on a per-process basis without the need to do this at the system level.

Personally I'm fine with this risk. Will is not and I respect his position, hence I started the other thread to come up with a MDWE alternative.

Quoted 6 lines

The other approach works, and if the systemd folks are on board with it also should solve the underlying problem, but it creates a bit of a compatibility problem with existing containers/etc that might exist today (although running systemd/services in a container is itself a discussion).

So, frankly, I don't see why they aren't complementary.

They are complementary, though if we change the MDWE approach, there's less of a need for this patchset.

Signature · 1 line
Catalin
#11 lore raw

Hi,

Quoted 45 lines · Catalin Marinas
Quoted 9 lines · Jeremy Linton
Quoted 8 lines · Mark Brown
Quoted 7 lines · Catalin Marinas
Quoted 6 lines · Will Deacon

Kees, please can you drop this series while Catalin's alternative solution is under discussion (his Reviewed-by preceded the other patches)?

https://lore.kernel.org/r/[email protected]

Both series expose new behaviours to userspace and we don't need both.

[...]

Quoted 5 lines
Quoted 5 lines
Quoted 4 lines

Arguably, the two approaches are complementary but the way this series turned out is for the BTI on main executable to be default off. I have a worry that the feature won't get used, so we just carry unnecessary code in the kernel. Jeremy also found this approach less than ideal:

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

https://lore.kernel.org/r/[email protected]

I'm not sure there was a fundamental concern with the approach there but rather some pushback on the instance on turning it off by default.

Right, this one seems to have the smallest impact on systemd as it exists today.

It had a bigger impact on glibc which had to rework the dynamic library mapping to use munmap/mmap() instead of an mprotect() (though that's already done). I think glibc still prefers the mprotect() approach for dynamic libraries.

Quoted 2 lines

I would have expected the default to be on, because IMHO this set corrects what at first glance just looks like a small oversight.

This was a design decision at the time, maybe not the best but it gives us some flexibility (and we haven't thought of MDWE).

Quoted 3 lines

I find the ABI questions a bit theoretical, given that this should only affect environments that don't exist outside of labs/development orgs at this point (aka systemd services on HW that implements BTI).

The worry is not what breaks now but rather what happens when today's distros will eventually be deployed on large-scale BTI-capable hardware. It's a very small risk but non-zero. The idea is that if we come across some weird problem, a fixed-up dynamic loader could avoid enabling BTI on a per-process basis without the need to do this at the system level.

Quoted 3 lines

Personally I'm fine with this risk. Will is not and I respect his position, hence I started the other thread to come up with a MDWE alternative.

To clarify though, there is already a way to restore process functionality to the small subset of services with the MDWE enabled, which is simply to flip off MDWE on the service and let some future loader flag clear PROT_BTI in the code path it would normally be setting PROT_EXE|PROT_BIT on.

Or maybe simpler yet, we provide a tool which wipes out the gnu BTI note on binaries that are found to have BTI bugs, thereby (correctly) fixing the problem at its source. This is at least presumably doable if we are also assuming we can update glibc/etc in any environment with the problem.

But again, systemd MDWE + BTI are less than a dozen processes, and if we are worried about the big hammer of disabling BTI system wide, we probably should have the ability to disable it per-process rather than worrying about this obscure edge case.

Quoted 11 lines
Quoted 7 lines

The other approach works, and if the systemd folks are on board with it also should solve the underlying problem, but it creates a bit of a compatibility problem with existing containers/etc that might exist today (although running systemd/services in a container is itself a discussion).

So, frankly, I don't see why they aren't complementary.

They are complementary, though if we change the MDWE approach, there's less of a need for this patchset.

author
#12 lore raw
Quoted 4 lines · Jeremy Linton

Or maybe simpler yet, we provide a tool which wipes out the gnu BTI note on binaries that are found to have BTI bugs, thereby (correctly) fixing the problem at its source. This is at least presumably doable if we are also assuming we can update glibc/etc in any environment with the problem.

This seems like the most sensible thing if we do find we're running into BTI executables that are incorrectly annotated and difficult to fix - it avoids having to manage any new permissions for bypassing BTI.

#13 lore raw
In reply to Will Deacon
Quoted 19 lines · Will Deacon
Quoted 9 lines · Kees Cook
Quoted 8 lines · Mark Brown

Deployments of BTI on arm64 have run into issues interacting with systemd's MemoryDenyWriteExecute feature. Currently for dynamically linked executables the kernel will only handle architecture specific properties like BTI for the interpreter, the expectation is that the interpreter will then handle any properties on the main executable. For BTI this means remapping the executable segments PROT_EXEC | PROT_BTI.

Quoted 8 lines
Quoted 1 line

[...]

Applied to for-next/execve, thanks!

[1/2] elf: Allow architectures to parse properties on the main executable

      https://git.kernel.org/kees/c/b2f2553c8e89
[2/2] arm64: Enable BTI for main executable as well as the interpreter
      https://git.kernel.org/kees/c/b65c760600e2
Quoted 6 lines

Kees, please can you drop this series while Catalin's alternative solution is under discussion (his Reviewed-by preceded the other patches)?

https://lore.kernel.org/r/[email protected]

Both series expose new behaviours to userspace and we don't need both.

Ah-ha! I wasn't sure if they were solving the same problem or not.

Signature · 1 line
Kees Cook
#14 lore raw
In reply to Kees Cook
Quoted 9 lines · Kees Cook
Quoted 8 lines · Mark Brown

Deployments of BTI on arm64 have run into issues interacting with systemd's MemoryDenyWriteExecute feature. Currently for dynamically linked executables the kernel will only handle architecture specific properties like BTI for the interpreter, the expectation is that the interpreter will then handle any properties on the main executable. For BTI this means remapping the executable segments PROT_EXEC | PROT_BTI.

Quoted 3 lines
Quoted 1 line

[...]

Applied to for-next/execve, thanks!

Now un-applied! :)

Signature · 1 line
Kees Cook