sys-kernel/hardened-kernel: version 6.14.6 with bcachefs and openpax upstream patches
Signed-off-by: Alexander Miroshnichenko <alex@millerson.name>
This commit is contained in:
7212
sys-kernel/hardened-kernel/files/linux-6.14.amd64.config
Normal file
7212
sys-kernel/hardened-kernel/files/linux-6.14.amd64.config
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,128 @@
|
||||
From ee3912c8c293b09acc90ba6ad7443ceacc33ef79 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Miroshnichenko <alex@millerson.name>
|
||||
Date: Wed, 14 May 2025 16:48:38 +0300
|
||||
Subject: [PATCH] bcachefs: revert 6.14 backport fixes
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: Alexander Miroshnichenko <alex@millerson.name>
|
||||
---
|
||||
fs/bcachefs/btree_update_interior.c | 17 +----------------
|
||||
fs/bcachefs/error.c | 8 --------
|
||||
fs/bcachefs/error.h | 2 --
|
||||
fs/bcachefs/fs-ioctl.c | 6 ++----
|
||||
fs/bcachefs/xattr_format.h | 8 +-------
|
||||
5 files changed, 4 insertions(+), 37 deletions(-)
|
||||
|
||||
diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c
|
||||
index e9be8b5571a4..e4e7c804625e 100644
|
||||
--- a/fs/bcachefs/btree_update_interior.c
|
||||
+++ b/fs/bcachefs/btree_update_interior.c
|
||||
@@ -35,8 +35,6 @@ static const char * const bch2_btree_update_modes[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
-static void bch2_btree_update_to_text(struct printbuf *, struct btree_update *);
|
||||
-
|
||||
static int bch2_btree_insert_node(struct btree_update *, struct btree_trans *,
|
||||
btree_path_idx_t, struct btree *, struct keylist *);
|
||||
static void bch2_btree_update_add_new_node(struct btree_update *, struct btree *);
|
||||
@@ -1784,24 +1782,11 @@ static int bch2_btree_insert_node(struct btree_update *as, struct btree_trans *t
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&c->gc_lock);
|
||||
+ BUG_ON(!btree_node_intent_locked(path, b->c.level));
|
||||
BUG_ON(!b->c.level);
|
||||
BUG_ON(!as || as->b);
|
||||
bch2_verify_keylist_sorted(keys);
|
||||
|
||||
- if (!btree_node_intent_locked(path, b->c.level)) {
|
||||
- struct printbuf buf = PRINTBUF;
|
||||
- bch2_log_msg_start(c, &buf);
|
||||
- prt_printf(&buf, "%s(): node not locked at level %u\n",
|
||||
- __func__, b->c.level);
|
||||
- bch2_btree_update_to_text(&buf, as);
|
||||
- bch2_btree_path_to_text(&buf, trans, path_idx);
|
||||
-
|
||||
- bch2_print_string_as_lines(KERN_ERR, buf.buf);
|
||||
- printbuf_exit(&buf);
|
||||
- bch2_fs_emergency_read_only(c);
|
||||
- return -EIO;
|
||||
- }
|
||||
-
|
||||
ret = bch2_btree_node_lock_write(trans, path, &b->c);
|
||||
if (ret)
|
||||
return ret;
|
||||
diff --git a/fs/bcachefs/error.c b/fs/bcachefs/error.c
|
||||
index 6cbf4819e923..038da6a61f6b 100644
|
||||
--- a/fs/bcachefs/error.c
|
||||
+++ b/fs/bcachefs/error.c
|
||||
@@ -11,14 +11,6 @@
|
||||
|
||||
#define FSCK_ERR_RATELIMIT_NR 10
|
||||
|
||||
-void bch2_log_msg_start(struct bch_fs *c, struct printbuf *out)
|
||||
-{
|
||||
-#ifdef BCACHEFS_LOG_PREFIX
|
||||
- prt_printf(out, bch2_log_msg(c, ""));
|
||||
-#endif
|
||||
- printbuf_indent_add(out, 2);
|
||||
-}
|
||||
-
|
||||
bool bch2_inconsistent_error(struct bch_fs *c)
|
||||
{
|
||||
set_bit(BCH_FS_error, &c->flags);
|
||||
diff --git a/fs/bcachefs/error.h b/fs/bcachefs/error.h
|
||||
index 5730eb6b2f38..7acf2a27ca28 100644
|
||||
--- a/fs/bcachefs/error.h
|
||||
+++ b/fs/bcachefs/error.h
|
||||
@@ -18,8 +18,6 @@ struct work_struct;
|
||||
|
||||
/* Error messages: */
|
||||
|
||||
-void bch2_log_msg_start(struct bch_fs *, struct printbuf *);
|
||||
-
|
||||
/*
|
||||
* Inconsistency errors: The on disk data is inconsistent. If these occur during
|
||||
* initial recovery, they don't indicate a bug in the running code - we walk all
|
||||
diff --git a/fs/bcachefs/fs-ioctl.c b/fs/bcachefs/fs-ioctl.c
|
||||
index 4d6193820483..15725b4ce393 100644
|
||||
--- a/fs/bcachefs/fs-ioctl.c
|
||||
+++ b/fs/bcachefs/fs-ioctl.c
|
||||
@@ -515,12 +515,10 @@ static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp,
|
||||
ret = -ENOENT;
|
||||
goto err;
|
||||
}
|
||||
-
|
||||
- ret = inode_permission(file_mnt_idmap(filp), d_inode(victim), MAY_WRITE) ?:
|
||||
- __bch2_unlink(dir, victim, true);
|
||||
+ ret = __bch2_unlink(dir, victim, true);
|
||||
if (!ret) {
|
||||
fsnotify_rmdir(dir, victim);
|
||||
- d_invalidate(victim);
|
||||
+ d_delete(victim);
|
||||
}
|
||||
err:
|
||||
inode_unlock(dir);
|
||||
diff --git a/fs/bcachefs/xattr_format.h b/fs/bcachefs/xattr_format.h
|
||||
index 67426e33d04e..c7916011ef34 100644
|
||||
--- a/fs/bcachefs/xattr_format.h
|
||||
+++ b/fs/bcachefs/xattr_format.h
|
||||
@@ -13,13 +13,7 @@ struct bch_xattr {
|
||||
__u8 x_type;
|
||||
__u8 x_name_len;
|
||||
__le16 x_val_len;
|
||||
- /*
|
||||
- * x_name contains the name and value counted by
|
||||
- * x_name_len + x_val_len. The introduction of
|
||||
- * __counted_by(x_name_len) caused a false positive
|
||||
- * detection of an out of bounds write.
|
||||
- */
|
||||
- __u8 x_name[];
|
||||
+ __u8 x_name[] __counted_by(x_name_len);
|
||||
} __packed __aligned(8);
|
||||
|
||||
#endif /* _BCACHEFS_XATTR_FORMAT_H */
|
||||
--
|
||||
2.49.0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,720 @@
|
||||
From a80207aef480f66179564003807d7a4ecf5aef8e Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Miroshnichenko <alex@millerson.name>
|
||||
Date: Wed, 14 May 2025 19:33:06 +0300
|
||||
Subject: [PATCH] openpax: cherry-pick updates from master fb1be96e0a3e
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: Alexander Miroshnichenko <alex@millerson.name>
|
||||
---
|
||||
.../admin-guide/kernel-parameters.txt | 3 +
|
||||
arch/x86/mm/fault.c | 218 ++++++++++++++++++
|
||||
fs/binfmt_elf.c | 88 ++++++-
|
||||
fs/proc/array.c | 15 ++
|
||||
fs/xattr.c | 16 ++
|
||||
include/linux/init.h | 1 +
|
||||
include/linux/mm_types.h | 11 +
|
||||
include/linux/mman.h | 11 +-
|
||||
include/linux/xattr.h | 4 +
|
||||
include/uapi/linux/xattr.h | 5 +
|
||||
init/main.c | 11 +
|
||||
kernel/sysctl.c | 15 ++
|
||||
security/Kconfig | 1 +
|
||||
security/Kconfig.openpax | 89 +++++++
|
||||
14 files changed, 485 insertions(+), 3 deletions(-)
|
||||
create mode 100644 security/Kconfig.openpax
|
||||
|
||||
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
|
||||
index bd53e2675c75..d46f21aa6a26 100644
|
||||
--- a/Documentation/admin-guide/kernel-parameters.txt
|
||||
+++ b/Documentation/admin-guide/kernel-parameters.txt
|
||||
@@ -4579,6 +4579,9 @@
|
||||
from the first 4GB of memory as the bootmem allocator
|
||||
passes the memory pages to the buddy allocator.
|
||||
|
||||
+ pax_softmode=<int>
|
||||
+ Enables OpenPaX soft mode if set to a non-zero value.
|
||||
+
|
||||
pcbit= [HW,ISDN]
|
||||
|
||||
pci=option[,option...] [PCI,EARLY] various PCI subsystem options.
|
||||
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
|
||||
index 296d294142c8..65665982e401 100644
|
||||
--- a/arch/x86/mm/fault.c
|
||||
+++ b/arch/x86/mm/fault.c
|
||||
@@ -1198,6 +1198,217 @@ do_kern_addr_fault(struct pt_regs *regs, unsigned long hw_error_code,
|
||||
}
|
||||
NOKPROBE_SYMBOL(do_kern_addr_fault);
|
||||
|
||||
+#ifdef CONFIG_OPENPAX_EMUTRAMP
|
||||
+/*
|
||||
+ * Determine if a fault is possibly caused by an emulatable stack or
|
||||
+ * heap trampoline. We return false if trampoline emulation is not
|
||||
+ * enabled.
|
||||
+ */
|
||||
+static inline
|
||||
+bool openpax_fault_is_trampoline(unsigned long error_code,
|
||||
+ struct pt_regs *regs,
|
||||
+ unsigned long address)
|
||||
+{
|
||||
+ struct mm_struct *mm = current->mm;
|
||||
+ unsigned long ip = regs->ip;
|
||||
+
|
||||
+ if (!test_bit(PAXF_EMUTRAMP, &mm->pax_flags))
|
||||
+ return false;
|
||||
+
|
||||
+ if (v8086_mode(regs))
|
||||
+ ip = ((regs->cs & 0xffff) << 4) + (ip & 0xffff);
|
||||
+
|
||||
+ if (test_bit(PAXF_PAGEEXEC, &mm->pax_flags)) {
|
||||
+ if ((__supported_pte_mask & _PAGE_NX) && (error_code & X86_PF_INSTR))
|
||||
+ return true;
|
||||
+ if (!(error_code & (X86_PF_PROT | X86_PF_WRITE)) && ip == address)
|
||||
+ return true;
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+NOKPROBE_SYMBOL(openpax_fault_is_trampoline);
|
||||
+
|
||||
+static inline
|
||||
+bool openpax_emulate_trampoline_32(struct pt_regs *regs)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ /* libffi trampoline type 1, gcc trampoline type 2 */
|
||||
+ do {
|
||||
+ unsigned char mov, jmp;
|
||||
+ unsigned int addr1, addr2;
|
||||
+
|
||||
+#ifdef CONFIG_X86_64
|
||||
+ if ((regs->ip + 9) >> 32)
|
||||
+ break;
|
||||
+#endif
|
||||
+
|
||||
+ err = get_user(mov, (unsigned char __user *) regs->ip);
|
||||
+ err |= get_user(addr1, (unsigned int __user *) (regs->ip + 1));
|
||||
+ err |= get_user(jmp, (unsigned char __user *) (regs->ip + 5));
|
||||
+ err |= get_user(addr2, (unsigned int __user *) (regs->ip + 6));
|
||||
+
|
||||
+ if (err)
|
||||
+ break;
|
||||
+
|
||||
+ if ((mov == 0xB8 || mov == 0xB9) && jmp == 0xE9) {
|
||||
+ if (mov == 0xB8)
|
||||
+ regs->ax = addr1;
|
||||
+ else
|
||||
+ regs->cx = addr1;
|
||||
+
|
||||
+ regs->ip = (unsigned int)(regs->ip + addr2 + 10);
|
||||
+ return true;
|
||||
+ }
|
||||
+ } while (0);
|
||||
+
|
||||
+ /* older gcc trampoline type... */
|
||||
+ do {
|
||||
+ unsigned char mov1, mov2;
|
||||
+ unsigned short jmp;
|
||||
+ unsigned int addr1, addr2;
|
||||
+
|
||||
+#ifdef CONFIG_X86_64
|
||||
+ if ((regs->ip + 11) >> 32)
|
||||
+ break;
|
||||
+#endif
|
||||
+
|
||||
+ err = get_user(mov1, (unsigned char __user *) regs->ip);
|
||||
+ err |= get_user(addr1, (unsigned int __user *) (regs->ip + 1));
|
||||
+ err |= get_user(mov2, (unsigned char __user *) (regs->ip + 5));
|
||||
+ err |= get_user(addr2, (unsigned int __user *) (regs->ip + 6));
|
||||
+ err |= get_user(jmp, (unsigned short __user *) (regs->ip + 10));
|
||||
+
|
||||
+ if (err)
|
||||
+ break;
|
||||
+
|
||||
+ if (mov1 == 0xB9 && mov2 == 0xB8 && jmp == 0xE0FF) {
|
||||
+ regs->cx = addr1;
|
||||
+ regs->ax = addr2;
|
||||
+ regs->ip = addr2;
|
||||
+ return true;
|
||||
+ }
|
||||
+ } while (0);
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+NOKPROBE_SYMBOL(openpax_emulate_trampoline_32);
|
||||
+
|
||||
+#ifdef CONFIG_X86_64
|
||||
+static inline
|
||||
+bool openpax_emulate_trampoline_64(struct pt_regs *regs)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ /* libffi trampoline type 1 */
|
||||
+ do {
|
||||
+ unsigned short mov1, mov2, jmp1;
|
||||
+ unsigned char stcclc, jmp2;
|
||||
+ unsigned long addr1, addr2;
|
||||
+
|
||||
+ err = get_user(mov1, (unsigned short __user *) regs->ip);
|
||||
+ err |= get_user(addr1, (unsigned long __user *) (regs->ip + 2));
|
||||
+ err |= get_user(mov2, (unsigned short __user *) (regs->ip + 10));
|
||||
+ err |= get_user(addr2, (unsigned long __user *) (regs->ip + 12));
|
||||
+ err |= get_user(stcclc, (unsigned char __user *) (regs->ip + 20));
|
||||
+ err |= get_user(jmp1, (unsigned short __user *) (regs->ip + 21));
|
||||
+ err |= get_user(jmp2, (unsigned char __user *) (regs->ip + 23));
|
||||
+
|
||||
+ if (err)
|
||||
+ break;
|
||||
+
|
||||
+ if (mov1 == 0xBB49 && mov2 == 0xBA49 && (stcclc == 0xF8 || stcclc == 0xF9) && jmp1 == 0xFF49 && jmp2 == 0xE3) {
|
||||
+ regs->r11 = addr1;
|
||||
+ regs->r10 = addr2;
|
||||
+
|
||||
+ if (stcclc == 0xF8)
|
||||
+ regs->flags &= ~X86_EFLAGS_CF;
|
||||
+ else
|
||||
+ regs->flags |= X86_EFLAGS_CF;
|
||||
+
|
||||
+ regs->ip = addr1;
|
||||
+ return true;
|
||||
+ }
|
||||
+ } while (0);
|
||||
+
|
||||
+ /* gcc trampoline type 1 */
|
||||
+ do {
|
||||
+ unsigned short mov1, mov2, jmp1;
|
||||
+ unsigned char jmp2;
|
||||
+ unsigned int addr1;
|
||||
+ unsigned long addr2;
|
||||
+
|
||||
+ err = get_user(mov1, (unsigned short __user *) regs->ip);
|
||||
+ err |= get_user(addr1, (unsigned int __user *) (regs->ip + 2));
|
||||
+ err |= get_user(mov2, (unsigned short __user *) (regs->ip + 6));
|
||||
+ err |= get_user(addr2, (unsigned long __user *) (regs->ip + 8));
|
||||
+ err |= get_user(jmp1, (unsigned short __user *) (regs->ip + 16));
|
||||
+ err |= get_user(jmp2, (unsigned char __user *) (regs->ip + 18));
|
||||
+
|
||||
+ if (err)
|
||||
+ break;
|
||||
+
|
||||
+ if (mov1 == 0xBB41 && mov2 == 0xBA49 && jmp1 == 0xFF49 && jmp2 == 0xE3) {
|
||||
+ regs->r11 = addr1;
|
||||
+ regs->r10 = addr2;
|
||||
+ regs->ip = addr1;
|
||||
+ return true;
|
||||
+ }
|
||||
+ } while (0);
|
||||
+
|
||||
+ /* gcc trampoline type 2 */
|
||||
+ do {
|
||||
+ unsigned short mov1, mov2, jmp1;
|
||||
+ unsigned char jmp2;
|
||||
+ unsigned long addr1, addr2;
|
||||
+
|
||||
+ err = get_user(mov1, (unsigned short __user *) regs->ip);
|
||||
+ err |= get_user(addr1, (unsigned long __user *) (regs->ip + 2));
|
||||
+ err |= get_user(mov2, (unsigned short __user *) (regs->ip + 10));
|
||||
+ err |= get_user(addr2, (unsigned long __user *) (regs->ip + 12));
|
||||
+ err |= get_user(jmp1, (unsigned short __user *) (regs->ip + 20));
|
||||
+ err |= get_user(jmp2, (unsigned char __user *) (regs->ip + 22));
|
||||
+
|
||||
+ if (err)
|
||||
+ break;
|
||||
+
|
||||
+ if (mov1 == 0xBB49 && mov2 == 0xBA49 && jmp1 == 0xFF49 && jmp2 == 0xE3) {
|
||||
+ regs->r11 = addr1;
|
||||
+ regs->r10 = addr2;
|
||||
+ regs->ip = addr1;
|
||||
+ return true;
|
||||
+ }
|
||||
+ } while (0);
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+NOKPROBE_SYMBOL(openpax_emulate_trampoline_64);
|
||||
+#endif
|
||||
+
|
||||
+/*
|
||||
+ * Emulate a trampoline. Returns false if emulation failed, meaning
|
||||
+ * that the task should be killed.
|
||||
+ */
|
||||
+static inline
|
||||
+bool openpax_emulate_trampoline(struct pt_regs *regs)
|
||||
+{
|
||||
+ if (v8086_mode(regs))
|
||||
+ return false;
|
||||
+
|
||||
+ if (regs->cs == __USER32_CS || (regs->cs & SEGMENT_LDT))
|
||||
+ return openpax_emulate_trampoline_32(regs);
|
||||
+#ifdef CONFIG_X86_64
|
||||
+ else
|
||||
+ return openpax_emulate_trampoline_64(regs);
|
||||
+#endif
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+NOKPROBE_SYMBOL(openpax_emulate_trampoline);
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* Handle faults in the user portion of the address space. Nothing in here
|
||||
* should check X86_PF_USER without a specific justification: for almost
|
||||
@@ -1322,6 +1533,13 @@ void do_user_addr_fault(struct pt_regs *regs,
|
||||
}
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_OPENPAX_EMUTRAMP
|
||||
+ if (openpax_fault_is_trampoline(error_code, regs, address)) {
|
||||
+ if (openpax_emulate_trampoline(regs))
|
||||
+ return;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
if (!(flags & FAULT_FLAG_USER))
|
||||
goto lock_mmap;
|
||||
|
||||
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
|
||||
index 8054f44d39cf..00f436d6d0a8 100644
|
||||
--- a/fs/binfmt_elf.c
|
||||
+++ b/fs/binfmt_elf.c
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <linux/dax.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/rseq.h>
|
||||
+#include <linux/xattr.h>
|
||||
#include <asm/param.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
@@ -822,6 +823,72 @@ static int parse_elf_properties(struct file *f, const struct elf_phdr *phdr,
|
||||
return ret == -ENOENT ? 0 : ret;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_OPENPAX
|
||||
+#ifdef CONFIG_OPENPAX_XATTR_PAX_FLAGS
|
||||
+static int openpax_parse_xattr_flags(struct file * const file)
|
||||
+{
|
||||
+ ssize_t xattr_size, i;
|
||||
+ unsigned char xattr_value[sizeof("pemrs") - 1];
|
||||
+
|
||||
+ xattr_size = pax_getxattr(file, xattr_value, sizeof xattr_value);
|
||||
+ if (xattr_size < 0 || xattr_size > sizeof xattr_value)
|
||||
+ return -ENOENT;
|
||||
+
|
||||
+ for (i = 0; i < xattr_size; i++)
|
||||
+ switch (xattr_value[i]) {
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+#define parse_flag(option_disable, option_enable, flag) \
|
||||
+ case option_disable: \
|
||||
+ clear_bit(flag, ¤t->mm->pax_flags); \
|
||||
+ break; \
|
||||
+ case option_enable: \
|
||||
+ set_bit(flag, ¤t->mm->pax_flags); \
|
||||
+ break;
|
||||
+
|
||||
+ parse_flag('p', 'P', PAXF_PAGEEXEC);
|
||||
+ parse_flag('e', 'E', PAXF_EMUTRAMP);
|
||||
+ parse_flag('m', 'M', PAXF_MPROTECT);
|
||||
+ parse_flag('r', 'R', PAXF_RANDMMAP);
|
||||
+ parse_flag('s', 'S', PAXF_SEGMEXEC);
|
||||
+#undef parse_flag
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+static int openpax_set_flags(struct file * const file, const int snapshot_randomize_va_space)
|
||||
+{
|
||||
+#ifdef CONFIG_OPENPAX_XATTR_PAX_FLAGS
|
||||
+ int error;
|
||||
+#endif
|
||||
+ current->mm->pax_flags = 0;
|
||||
+
|
||||
+ if (snapshot_randomize_va_space) {
|
||||
+ set_bit(PAXF_RANDMMAP, ¤t->mm->pax_flags);
|
||||
+ }
|
||||
+
|
||||
+ if (!pax_softmode) {
|
||||
+ set_bit(PAXF_PAGEEXEC, ¤t->mm->pax_flags);
|
||||
+ set_bit(PAXF_MPROTECT, ¤t->mm->pax_flags);
|
||||
+ }
|
||||
+
|
||||
+#ifdef CONFIG_OPENPAX_EMUTRAMP_DEFAULT
|
||||
+ set_bit(PAXF_EMUTRAMP, ¤t->mm->pax_flags);
|
||||
+#endif
|
||||
+
|
||||
+#ifdef CONFIG_OPENPAX_XATTR_PAX_FLAGS
|
||||
+ error = openpax_parse_xattr_flags(file);
|
||||
+ if (error != -ENOENT)
|
||||
+ return error;
|
||||
+#endif
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
static int load_elf_binary(struct linux_binprm *bprm)
|
||||
{
|
||||
struct file *interpreter = NULL; /* to shut gcc up */
|
||||
@@ -1006,11 +1073,28 @@ static int load_elf_binary(struct linux_binprm *bprm)
|
||||
/* Do this immediately, since STACK_TOP as used in setup_arg_pages
|
||||
may depend on the personality. */
|
||||
SET_PERSONALITY2(*elf_ex, &arch_state);
|
||||
+
|
||||
+ const int snapshot_randomize_va_space = READ_ONCE(randomize_va_space);
|
||||
+
|
||||
+#ifdef CONFIG_OPENPAX
|
||||
+ retval = openpax_set_flags(bprm->file, snapshot_randomize_va_space);
|
||||
+ if (retval)
|
||||
+ goto out_free_dentry;
|
||||
+
|
||||
+ if (test_bit(PAXF_PAGEEXEC, ¤t->mm->pax_flags) || test_bit(PAXF_SEGMEXEC, ¤t->mm->pax_flags)) {
|
||||
+ executable_stack = EXSTACK_DISABLE_X;
|
||||
+ current->personality &= ~READ_IMPLIES_EXEC;
|
||||
+ } else
|
||||
+#endif
|
||||
+
|
||||
if (elf_read_implies_exec(*elf_ex, executable_stack))
|
||||
current->personality |= READ_IMPLIES_EXEC;
|
||||
|
||||
- const int snapshot_randomize_va_space = READ_ONCE(randomize_va_space);
|
||||
- if (!(current->personality & ADDR_NO_RANDOMIZE) && snapshot_randomize_va_space)
|
||||
+ if (!(current->personality & ADDR_NO_RANDOMIZE) && snapshot_randomize_va_space
|
||||
+#ifdef CONFIG_OPENPAX
|
||||
+ && test_bit(PAXF_RANDMMAP, ¤t->mm->pax_flags)
|
||||
+#endif
|
||||
+ )
|
||||
current->flags |= PF_RANDOMIZE;
|
||||
|
||||
setup_new_exec(bprm);
|
||||
diff --git a/fs/proc/array.c b/fs/proc/array.c
|
||||
index d6a0369caa93..242c8a969400 100644
|
||||
--- a/fs/proc/array.c
|
||||
+++ b/fs/proc/array.c
|
||||
@@ -436,6 +436,18 @@ __weak void arch_proc_pid_thread_features(struct seq_file *m,
|
||||
{
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_OPENPAX
|
||||
+static inline void task_pax(struct seq_file *m, struct mm_struct *mm)
|
||||
+{
|
||||
+ seq_printf(m, "PaX:\t%c%c%c%c%c\n",
|
||||
+ test_bit(PAXF_PAGEEXEC, &mm->pax_flags) ? 'P' : 'p',
|
||||
+ test_bit(PAXF_EMUTRAMP, &mm->pax_flags) ? 'E' : 'e',
|
||||
+ test_bit(PAXF_MPROTECT, &mm->pax_flags) ? 'M' : 'm',
|
||||
+ test_bit(PAXF_RANDMMAP, &mm->pax_flags) ? 'R' : 'r',
|
||||
+ test_bit(PAXF_SEGMEXEC, &mm->pax_flags) ? 'S' : 's');
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
int proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
|
||||
struct pid *pid, struct task_struct *task)
|
||||
{
|
||||
@@ -452,6 +464,9 @@ int proc_pid_status(struct seq_file *m, struct pid_namespace *ns,
|
||||
task_core_dumping(m, task);
|
||||
task_thp_status(m, mm);
|
||||
task_untag_mask(m, mm);
|
||||
+#ifdef CONFIG_OPENPAX
|
||||
+ task_pax(m, mm);
|
||||
+#endif
|
||||
mmput(mm);
|
||||
}
|
||||
task_sig(m, task);
|
||||
diff --git a/fs/xattr.c b/fs/xattr.c
|
||||
index fabb2a04501e..76c2b5f8d6e6 100644
|
||||
--- a/fs/xattr.c
|
||||
+++ b/fs/xattr.c
|
||||
@@ -424,6 +424,22 @@ __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name,
|
||||
}
|
||||
EXPORT_SYMBOL(__vfs_getxattr);
|
||||
|
||||
+#ifdef CONFIG_OPENPAX_XATTR_PAX_FLAGS
|
||||
+ssize_t
|
||||
+pax_getxattr(struct file *file, void *value, size_t size)
|
||||
+{
|
||||
+ struct inode *inode = file->f_path.dentry->d_inode;
|
||||
+ ssize_t error;
|
||||
+
|
||||
+ error = inode_permission(file_mnt_idmap(file), inode, MAY_EXEC);
|
||||
+ if (error)
|
||||
+ return error;
|
||||
+
|
||||
+ return __vfs_getxattr(file->f_path.dentry, inode, XATTR_NAME_USER_PAX_FLAGS, value, size);
|
||||
+}
|
||||
+EXPORT_SYMBOL(pax_getxattr);
|
||||
+#endif
|
||||
+
|
||||
ssize_t
|
||||
vfs_getxattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
const char *name, void *value, size_t size)
|
||||
diff --git a/include/linux/init.h b/include/linux/init.h
|
||||
index ee1309473bc6..4abbce4cf60b 100644
|
||||
--- a/include/linux/init.h
|
||||
+++ b/include/linux/init.h
|
||||
@@ -144,6 +144,7 @@ extern char __initdata boot_command_line[];
|
||||
extern char *saved_command_line;
|
||||
extern unsigned int saved_command_line_len;
|
||||
extern unsigned int reset_devices;
|
||||
+extern int pax_softmode;
|
||||
|
||||
/* used by init/main.c */
|
||||
void setup_arch(char **);
|
||||
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
|
||||
index 0234f14f2aa6..fd8bd5517e4d 100644
|
||||
--- a/include/linux/mm_types.h
|
||||
+++ b/include/linux/mm_types.h
|
||||
@@ -973,6 +973,9 @@ struct mm_struct {
|
||||
mm_context_t context;
|
||||
|
||||
unsigned long flags; /* Must use atomic bitops to access */
|
||||
+#ifdef CONFIG_OPENPAX
|
||||
+ unsigned long pax_flags;
|
||||
+#endif
|
||||
|
||||
#ifdef CONFIG_AIO
|
||||
spinlock_t ioctx_lock;
|
||||
@@ -1656,4 +1659,12 @@ static inline unsigned long mmf_init_flags(unsigned long flags)
|
||||
return flags & MMF_INIT_MASK;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_OPENPAX
|
||||
+#define PAXF_PAGEEXEC 1
|
||||
+#define PAXF_EMUTRAMP 2
|
||||
+#define PAXF_MPROTECT 3
|
||||
+#define PAXF_RANDMMAP 4
|
||||
+#define PAXF_SEGMEXEC 5
|
||||
+#endif
|
||||
+
|
||||
#endif /* _LINUX_MM_TYPES_H */
|
||||
diff --git a/include/linux/mman.h b/include/linux/mman.h
|
||||
index a842783ffa62..e108371ff12e 100644
|
||||
--- a/include/linux/mman.h
|
||||
+++ b/include/linux/mman.h
|
||||
@@ -197,12 +197,21 @@ static inline bool arch_memory_deny_write_exec_supported(void)
|
||||
* we propose to set.
|
||||
*
|
||||
* Return: false if proposed change is OK, true if not ok and should be denied.
|
||||
+ *
|
||||
+ * Note: If OpenPaX is enabled, it will be assumed that we want to deny
|
||||
+ * PROT_WRITE | PROT_EXEC by default, unless the MPROTECT feature bit is
|
||||
+ * disabled on a binary.
|
||||
*/
|
||||
static inline bool map_deny_write_exec(unsigned long old, unsigned long new)
|
||||
{
|
||||
/* If MDWE is disabled, we have nothing to deny. */
|
||||
- if (!test_bit(MMF_HAS_MDWE, ¤t->mm->flags))
|
||||
+ if (
|
||||
+#ifdef CONFIG_OPENPAX_MPROTECT
|
||||
+ !test_bit(PAXF_MPROTECT, ¤t->mm->pax_flags) &&
|
||||
+#endif
|
||||
+ !test_bit(MMF_HAS_MDWE, ¤t->mm->flags)) {
|
||||
return false;
|
||||
+ }
|
||||
|
||||
/* If the new VMA is not executable, we have nothing to deny. */
|
||||
if (!(new & VM_EXEC))
|
||||
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
|
||||
index 86b0d47984a1..c4ad3af7e1a2 100644
|
||||
--- a/include/linux/xattr.h
|
||||
+++ b/include/linux/xattr.h
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
struct inode;
|
||||
struct dentry;
|
||||
+struct file;
|
||||
|
||||
static inline bool is_posix_acl_xattr(const char *name)
|
||||
{
|
||||
@@ -75,6 +76,9 @@ struct xattr {
|
||||
size_t value_len;
|
||||
};
|
||||
|
||||
+#ifdef CONFIG_OPENPAX_XATTR_PAX_FLAGS
|
||||
+ssize_t pax_getxattr(struct file *, void *, size_t);
|
||||
+#endif
|
||||
ssize_t __vfs_getxattr(struct dentry *, struct inode *, const char *, void *, size_t);
|
||||
ssize_t vfs_getxattr(struct mnt_idmap *, struct dentry *, const char *,
|
||||
void *, size_t);
|
||||
diff --git a/include/uapi/linux/xattr.h b/include/uapi/linux/xattr.h
|
||||
index 9854f9cff3c6..843787b91ef0 100644
|
||||
--- a/include/uapi/linux/xattr.h
|
||||
+++ b/include/uapi/linux/xattr.h
|
||||
@@ -88,5 +88,10 @@ struct xattr_args {
|
||||
#define XATTR_POSIX_ACL_DEFAULT "posix_acl_default"
|
||||
#define XATTR_NAME_POSIX_ACL_DEFAULT XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_DEFAULT
|
||||
|
||||
+/* User namespace */
|
||||
+#define XATTR_PAX_PREFIX "pax."
|
||||
+#define XATTR_PAX_FLAGS_SUFFIX "flags"
|
||||
+#define XATTR_NAME_USER_PAX_FLAGS XATTR_USER_PREFIX XATTR_PAX_PREFIX XATTR_PAX_FLAGS_SUFFIX
|
||||
+#define XATTR_NAME_PAX_FLAGS XATTR_PAX_PREFIX XATTR_PAX_FLAGS_SUFFIX
|
||||
|
||||
#endif /* _UAPI_LINUX_XATTR_H */
|
||||
diff --git a/init/main.c b/init/main.c
|
||||
index 2a1757826397..4720dce1a3b9 100644
|
||||
--- a/init/main.c
|
||||
+++ b/init/main.c
|
||||
@@ -188,6 +188,17 @@ static int __init set_reset_devices(char *str)
|
||||
|
||||
__setup("reset_devices", set_reset_devices);
|
||||
|
||||
+int pax_softmode;
|
||||
+
|
||||
+#ifdef CONFIG_OPENPAX_SOFTMODE
|
||||
+static int __init setup_pax_softmode(char *str)
|
||||
+{
|
||||
+ get_option(&str, &pax_softmode);
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("pax_softmode=", setup_pax_softmode);
|
||||
+#endif
|
||||
+
|
||||
static const char *argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
|
||||
const char *envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
|
||||
static const char *panic_later, *panic_param;
|
||||
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
|
||||
index 1d600ae89f15..44aff4b84516 100644
|
||||
--- a/kernel/sysctl.c
|
||||
+++ b/kernel/sysctl.c
|
||||
@@ -1647,6 +1647,18 @@ int proc_do_static_key(const struct ctl_table *table, int write,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_OPENPAX_SOFTMODE
|
||||
+static const struct ctl_table pax_table[] = {
|
||||
+ {
|
||||
+ .procname = "softmode",
|
||||
+ .data = &pax_softmode,
|
||||
+ .maxlen = sizeof(int),
|
||||
+ .mode = 0600,
|
||||
+ .proc_handler = proc_dointvec,
|
||||
+ },
|
||||
+};
|
||||
+#endif
|
||||
+
|
||||
static const struct ctl_table kern_table[] = {
|
||||
{
|
||||
.procname = "panic",
|
||||
@@ -2279,6 +2291,9 @@ int __init sysctl_init_bases(void)
|
||||
{
|
||||
register_sysctl_init("kernel", kern_table);
|
||||
register_sysctl_init("vm", vm_table);
|
||||
+#ifdef CONFIG_OPENPAX_SOFTMODE
|
||||
+ register_sysctl_init("kernel/pax", pax_table);
|
||||
+#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
diff --git a/security/Kconfig b/security/Kconfig
|
||||
index adc4a853ce0d..e9cfe77f08e0 100644
|
||||
--- a/security/Kconfig
|
||||
+++ b/security/Kconfig
|
||||
@@ -311,6 +311,7 @@ config LSM
|
||||
If unsure, leave this as the default.
|
||||
|
||||
source "security/Kconfig.hardening"
|
||||
+source "security/Kconfig.openpax"
|
||||
|
||||
endmenu
|
||||
|
||||
diff --git a/security/Kconfig.openpax b/security/Kconfig.openpax
|
||||
new file mode 100644
|
||||
index 000000000000..76ee145094d9
|
||||
--- /dev/null
|
||||
+++ b/security/Kconfig.openpax
|
||||
@@ -0,0 +1,89 @@
|
||||
+#
|
||||
+# OpenPaX configuration
|
||||
+#
|
||||
+
|
||||
+menu "OpenPaX options"
|
||||
+
|
||||
+config OPENPAX
|
||||
+ bool "Enable OpenPaX features"
|
||||
+ default y
|
||||
+ help
|
||||
+ This configuration setting enables OpenPaX features.
|
||||
+ OpenPaX adds memory safety-related defenses to the kernel which
|
||||
+ reduce the risks posed by exploitable memory safety bugs.
|
||||
+
|
||||
+config OPENPAX_SOFTMODE
|
||||
+ bool "Support PaX soft mode"
|
||||
+ default y
|
||||
+ help
|
||||
+ Enabling this option will allow you to configure OpenPaX
|
||||
+ features to run in soft mode. In this mode, OpenPaX features
|
||||
+ will be disabled by default, only running on applications
|
||||
+ which explicitly enable them.
|
||||
+
|
||||
+ Soft mode can be enabled via the kernel.pax.softmode sysctl,
|
||||
+ or the pax_softmode=1 kernel command-line option.
|
||||
+
|
||||
+config OPENPAX_XATTR_PAX_FLAGS
|
||||
+ bool "Use filesystem extended attributes to modify OpenPaX features"
|
||||
+ depends on OPENPAX
|
||||
+ default y
|
||||
+ help
|
||||
+ Enabling this option will allow you to control whether
|
||||
+ OpenPaX features are enabled on a per-executable basis via
|
||||
+ xattr attributes.
|
||||
+
|
||||
+ For compatibility with the original PaX patch, the feature
|
||||
+ flags are read from the user.pax.flags extended attribute.
|
||||
+
|
||||
+ If you disable this feature, then all applications will run
|
||||
+ with OpenPaX enabled by default.
|
||||
+
|
||||
+config OPENPAX_MPROTECT
|
||||
+ bool "Enforce W^X for memory mappings"
|
||||
+ depends on OPENPAX
|
||||
+ default y
|
||||
+ help
|
||||
+ Enabling this option prevents programs from making pages
|
||||
+ executable when they are also writable. In addition, it
|
||||
+ also denies transition of writable mappings to executable
|
||||
+ mappings.
|
||||
+
|
||||
+ This feature is known to break programs which depend on
|
||||
+ just-in-time (JIT) compilation. It is advisable to enable
|
||||
+ this feature system-wide, but mark programs which have
|
||||
+ JIT compilation appropriately so the W^X enforcement is
|
||||
+ disabled for them.
|
||||
+
|
||||
+config OPENPAX_EMUTRAMP
|
||||
+ bool "Emulate stack and heap trampolines"
|
||||
+ depends on OPENPAX
|
||||
+ default y
|
||||
+ help
|
||||
+ Enabling this option allows programs to depend on common
|
||||
+ types of stack and heap trampolines (such as the ones
|
||||
+ generated by GCC and libffi) to continue working despite
|
||||
+ the stack and heap being non-executable memory.
|
||||
+
|
||||
+ This option works by intercepting the page faults caused
|
||||
+ by executing code in non-executable memory and emulating
|
||||
+ the side effects that would have happened from executing
|
||||
+ the trampoline.
|
||||
+
|
||||
+ Most likely, you should say 'y' here.
|
||||
+
|
||||
+config OPENPAX_EMUTRAMP_DEFAULT
|
||||
+ bool "Enable trampoline emulation by default"
|
||||
+ depends on OPENPAX_EMUTRAMP
|
||||
+ default y
|
||||
+ help
|
||||
+ Enabling this option allows programs which require
|
||||
+ trampolines to be emulated to continue working by default.
|
||||
+
|
||||
+ Otherwise, the emulation flag must be enabled in a binary's
|
||||
+ PaX marking, e.g. with paxmark -E <binary>.
|
||||
+
|
||||
+ If you do not say 'y' here, you will have to manually mark
|
||||
+ all programs which require trampoline emulation.
|
||||
+
|
||||
+endmenu
|
||||
--
|
||||
2.49.0
|
||||
|
||||
Reference in New Issue
Block a user