linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] mm: exitz syscall
@ 2023-11-10 18:47 York Jasper Niebuhr
  2023-11-10 21:40 ` kernel test robot
  2023-11-10 22:35 ` kernel test robot
  0 siblings, 2 replies; 3+ messages in thread
From: York Jasper Niebuhr @ 2023-11-10 18:47 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, York Jasper Niebuhr

Adds a system call to flag a process' resources to be cleared on
exit (or, in the case of memory, on free). Currently, only zeroing
memory is implemented. This system call is meant to act as an
alternative to CONFIG_INIT_ON_FREE_DEFAULT_ON that does not generally
impact the entire system's performance, but is restricted to occasional
applications for single process' that require the extra security.

---
 arch/x86/entry/syscalls/syscall_32.tbl |   1 +
 arch/x86/entry/syscalls/syscall_64.tbl |   1 +
 include/linux/exitz.h                  |  27 ++++++
 include/linux/sched.h                  |   4 +
 include/linux/syscalls.h               |   1 +
 include/uapi/asm-generic/unistd.h      |   4 +-
 kernel/Makefile                        |   2 +
 kernel/exit.c                          |   5 ++
 kernel/exitz.c                         | 112 +++++++++++++++++++++++++
 kernel/sys_ni.c                        |   3 +
 mm/mmap.c                              |  12 +++
 security/Kconfig                       |   9 ++
 12 files changed, 180 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/exitz.h
 create mode 100644 kernel/exitz.c

diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index c8fac5205803..8be9d1471b5c 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -461,3 +461,4 @@
 454	i386	futex_wake		sys_futex_wake
 455	i386	futex_wait		sys_futex_wait
 456	i386	futex_requeue		sys_futex_requeue
+457	i386	exitz			sys_exitz
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 8cb8bf68721c..e6aeca443a88 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -378,6 +378,7 @@
 454	common	futex_wake		sys_futex_wake
 455	common	futex_wait		sys_futex_wait
 456	common	futex_requeue		sys_futex_requeue
+457	common	exitz			sys_exitz
 
 #
 # Due to a historical design error, certain syscalls are numbered differently
diff --git a/include/linux/exitz.h b/include/linux/exitz.h
new file mode 100644
index 000000000000..b1a5ad194839
--- /dev/null
+++ b/include/linux/exitz.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifdef CONFIG_EXITZ_SYSCALL
+
+/*
+ * Zero resource on exit flags
+ */
+#define EZ_NONE			0x00000000
+#define EZ_MEM                  0x00000001      /* Memory pages are cleared on exit */
+#define EZ_FLAGS (EZ_MEM)
+
+/*
+ * Overwrite current process memory range with zeros (end excluded).
+ */
+int memz_range(unsigned long start, unsigned long end);
+
+/*
+ * Overwrite all flagged resources with zeros.
+ */
+void exit_z(void);
+
+/*
+ * Set task_struct flags to zero flagged resources on exit.
+ */
+void do_exitz(int flags);
+
+#endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 292c31697248..cbe8c198f28e 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -766,6 +766,10 @@ struct task_struct {
 	refcount_t			usage;
 	/* Per task flags (PF_*), defined further below: */
 	unsigned int			flags;
+#ifdef CONFIG_EXITZ_SYSCALL
+	/* Zero resource on exit flags (EZ_*). */
+	unsigned int			ezflags;
+#endif
 	unsigned int			ptrace;
 
 #ifdef CONFIG_SMP
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index fd9d12de7e92..8c29b9ea3677 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -949,6 +949,7 @@ asmlinkage long sys_cachestat(unsigned int fd,
 		struct cachestat_range __user *cstat_range,
 		struct cachestat __user *cstat, unsigned int flags);
 asmlinkage long sys_map_shadow_stack(unsigned long addr, unsigned long size, unsigned int flags);
+asmlinkage long sys_exitz(int flags);
 
 /*
  * Architecture-specific system calls
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index 756b013fb832..782222ffa0d7 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -828,9 +828,11 @@ __SYSCALL(__NR_futex_wake, sys_futex_wake)
 __SYSCALL(__NR_futex_wait, sys_futex_wait)
 #define __NR_futex_requeue 456
 __SYSCALL(__NR_futex_requeue, sys_futex_requeue)
+#define __NR_exitz 457
+__SYSCALL(__NR_exitz, sys_exitz)
 
 #undef __NR_syscalls
-#define __NR_syscalls 457
+#define __NR_syscalls 458
 
 /*
  * 32 bit systems traditionally used different
diff --git a/kernel/Makefile b/kernel/Makefile
index 3947122d618b..17602af88adc 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -158,3 +158,5 @@ $(obj)/kheaders_data.tar.xz: FORCE
 	$(call cmd,genikh)
 
 clean-files := kheaders_data.tar.xz kheaders.md5
+
+obj-$(CONFIG_EXITZ_SYSCALL) += exitz.o
diff --git a/kernel/exit.c b/kernel/exit.c
index ee9f43bed49a..35469decd9e9 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -69,6 +69,7 @@
 #include <linux/rethook.h>
 #include <linux/sysfs.h>
 #include <linux/user_events.h>
+#include <linux/exitz.h>
 
 #include <linux/uaccess.h>
 #include <asm/unistd.h>
@@ -808,6 +809,10 @@ static void synchronize_group_exit(struct task_struct *tsk, long code)
 
 void __noreturn do_exit(long code)
 {
+#ifdef CONFIG_EXITZ_SYSCALL
+	exit_z();
+#endif
+
 	struct task_struct *tsk = current;
 	int group_dead;
 
diff --git a/kernel/exitz.c b/kernel/exitz.c
new file mode 100644
index 000000000000..75875685bd3c
--- /dev/null
+++ b/kernel/exitz.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/exitz.h>
+#include <linux/syscalls.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mm_types.h>
+#include <linux/slab.h>
+#include <linux/highmem.h>
+#include <linux/string.h>
+
+#define EZ_MAX_PAGES_ARRAY_COUNT 16
+#define EZ_MAX_KMALLOC_PAGES (PAGE_SIZE * 2)
+#define EZ_MAX_PAGES_PER_LOOP (EZ_MAX_KMALLOC_PAGES / sizeof(struct page *))
+
+/*
+ * Overwrite a range of process memory with zeros (end excluded).
+ */
+int memz_range(unsigned long start, unsigned long end)
+{
+	if (end <= start)
+		return 0;
+
+	unsigned long nr_pages = (end - 1) / PAGE_SIZE - start / PAGE_SIZE + 1;
+
+	struct page *pages_stack[EZ_MAX_PAGES_ARRAY_COUNT];
+	struct page **pages = pages_stack;
+
+	if (nr_pages > EZ_MAX_PAGES_ARRAY_COUNT) {
+		/* For reliability, cap kmalloc size */
+		pages = kmalloc(min_t(size_t, EZ_MAX_KMALLOC_PAGES,
+					sizeof(struct page *) * nr_pages),
+				GFP_KERNEL);
+
+		if (!pages)
+			return -ENOMEM;
+	}
+
+	unsigned long page_address = start & PAGE_MASK;
+
+	while (nr_pages) {
+		long pinned_pages = min(nr_pages, EZ_MAX_PAGES_PER_LOOP);
+
+		pinned_pages = pin_user_pages(page_address, pinned_pages, FOLL_WRITE, pages);
+
+		if (pinned_pages <= 0)
+			return -EFAULT;
+
+		/* Map and zero each page */
+		for (long i = 0; i < pinned_pages; i++) {
+			void *kaddr = kmap_local_page(pages[i]);
+
+			memset(kaddr, 0, PAGE_SIZE);
+
+			kunmap_local(kaddr);
+		}
+
+		nr_pages -= pinned_pages;
+		page_address += pinned_pages * PAGE_SIZE;
+
+		unpin_user_pages_dirty_lock(pages, pinned_pages, 1);
+	}
+
+	if (pages != pages_stack)
+		kfree(pages);
+
+	return 0;
+}
+
+/*
+ * Overwrite any memory associated to current process with zeros.
+ */
+void exit_memz(void)
+{
+	if (!(current->ezflags & EZ_MEM))
+		return;
+
+	struct vm_area_struct *vma;
+
+	VMA_ITERATOR(vmi, current->mm, 0);
+
+	for_each_vma(vmi, vma) {
+		memz_range(vma->vm_start, vma->vm_end);
+	}
+}
+
+/*
+ * Overwrite all flagged resources with zeros.
+ */
+void exit_z(void)
+{
+	exit_memz();
+}
+
+/*
+ * Set task_struct flags to zero flagged resources on exit.
+ */
+void do_exitz(int flags)
+{
+	current->ezflags = flags;
+}
+
+#ifdef CONFIG_EXITZ_SYSCALL
+SYSCALL_DEFINE1(exitz, int, flags)
+{
+	if (flags & ~EZ_FLAGS)
+		return -EINVAL;
+
+	do_exitz(flags);
+	return 0;
+}
+#endif
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index e1a6e3c675c0..ff5468f1d2f2 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -254,6 +254,9 @@ COND_SYSCALL(pkey_free);
 /* memfd_secret */
 COND_SYSCALL(memfd_secret);
 
+/* exitz */
+COND_SYSCALL(exitz);
+
 /*
  * Architecture specific weak syscall entries.
  */
diff --git a/mm/mmap.c b/mm/mmap.c
index 4f1cb814586d..d66bd314aca9 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -47,6 +47,7 @@
 #include <linux/oom.h>
 #include <linux/sched/mm.h>
 #include <linux/ksm.h>
+#include <linux/exitz.h>
 
 #include <linux/uaccess.h>
 #include <asm/cacheflush.h>
@@ -225,6 +226,12 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
 
 	/* Always allow shrinking brk. */
 	if (brk <= mm->brk) {
+		/* Overwrite memory with zeros */
+#ifdef CONFIG_EXITZ_SYSCALL
+		if (current->ezflags & EZ_MEM)
+			memz_range(brk, mm->brk);
+#endif
+
 		/* Search one past newbrk */
 		vma_iter_init(&vmi, mm, newbrk);
 		brkvma = vma_find(&vmi, oldbrk);
@@ -3001,6 +3008,11 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
 
 static int __vm_munmap(unsigned long start, size_t len, bool unlock)
 {
+#ifdef CONFIG_EXITZ_SYSCALL
+	if (current->ezflags & EZ_MEM)
+		memz_range(start, start + len);
+#endif
+
 	int ret;
 	struct mm_struct *mm = current->mm;
 	LIST_HEAD(uf);
diff --git a/security/Kconfig b/security/Kconfig
index 52c9af08ad35..3509bb5fb2f4 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -249,5 +249,14 @@ config LSM
 
 source "security/Kconfig.hardening"
 
+config EXITZ_SYSCALL
+	bool "Exitz syscall" if EXPERT
+	default y
+	help
+	  sys_exitz is a system call to flag a process' resources to be erased
+	  on exit. It can be used to harden the system against memory forensics
+	  attacks after a process has finished. It is meant to be a more fine
+	  grained alternative to CONFIG_INIT_ON_FREE_DEFAULT_ON.
+
 endmenu
 

base-commit: 8728c14129df7a6e29188a2e737b4774fb200953
-- 
2.34.1

Signed-off-by: York Jasper Niebuhr <yjnworkstation@gmail.com>

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] mm: exitz syscall
  2023-11-10 18:47 [PATCH] mm: exitz syscall York Jasper Niebuhr
@ 2023-11-10 21:40 ` kernel test robot
  2023-11-10 22:35 ` kernel test robot
  1 sibling, 0 replies; 3+ messages in thread
From: kernel test robot @ 2023-11-10 21:40 UTC (permalink / raw)
  To: York Jasper Niebuhr, akpm
  Cc: oe-kbuild-all, linux-kernel, York Jasper Niebuhr

Hi York,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 8728c14129df7a6e29188a2e737b4774fb200953]

url:    https://github.com/intel-lab-lkp/linux/commits/York-Jasper-Niebuhr/mm-exitz-syscall/20231111-031729
base:   8728c14129df7a6e29188a2e737b4774fb200953
patch link:    https://lore.kernel.org/r/20231110184720.39780-1-yjnworkstation%40gmail.com
patch subject: [PATCH] mm: exitz syscall
config: loongarch-randconfig-001-20231111 (https://download.01.org/0day-ci/archive/20231111/202311110549.g5gj4ZVU-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231111/202311110549.g5gj4ZVU-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202311110549.g5gj4ZVU-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> kernel/exitz.c:73:6: warning: no previous prototype for 'exit_memz' [-Wmissing-prototypes]
      73 | void exit_memz(void)
         |      ^~~~~~~~~


vim +/exit_memz +73 kernel/exitz.c

    69	
    70	/*
    71	 * Overwrite any memory associated to current process with zeros.
    72	 */
  > 73	void exit_memz(void)
    74	{
    75		if (!(current->ezflags & EZ_MEM))
    76			return;
    77	
    78		struct vm_area_struct *vma;
    79	
    80		VMA_ITERATOR(vmi, current->mm, 0);
    81	
    82		for_each_vma(vmi, vma) {
    83			memz_range(vma->vm_start, vma->vm_end);
    84		}
    85	}
    86	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] mm: exitz syscall
  2023-11-10 18:47 [PATCH] mm: exitz syscall York Jasper Niebuhr
  2023-11-10 21:40 ` kernel test robot
@ 2023-11-10 22:35 ` kernel test robot
  1 sibling, 0 replies; 3+ messages in thread
From: kernel test robot @ 2023-11-10 22:35 UTC (permalink / raw)
  To: York Jasper Niebuhr, akpm
  Cc: llvm, oe-kbuild-all, linux-kernel, York Jasper Niebuhr

Hi York,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 8728c14129df7a6e29188a2e737b4774fb200953]

url:    https://github.com/intel-lab-lkp/linux/commits/York-Jasper-Niebuhr/mm-exitz-syscall/20231111-031729
base:   8728c14129df7a6e29188a2e737b4774fb200953
patch link:    https://lore.kernel.org/r/20231110184720.39780-1-yjnworkstation%40gmail.com
patch subject: [PATCH] mm: exitz syscall
config: um-allnoconfig (https://download.01.org/0day-ci/archive/20231111/202311110615.TXNCRihT-lkp@intel.com/config)
compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231111/202311110615.TXNCRihT-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202311110615.TXNCRihT-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from kernel/exitz.c:4:
   In file included from include/linux/syscalls.h:90:
   In file included from include/trace/syscall.h:7:
   In file included from include/linux/trace_events.h:9:
   In file included from include/linux/hardirq.h:11:
   In file included from arch/um/include/asm/hardirq.h:5:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/um/include/asm/io.h:24:
   include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     547 |         val = __raw_readb(PCI_IOBASE + addr);
         |                           ~~~~~~~~~~ ^
   include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     560 |         val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:37:51: note: expanded from macro '__le16_to_cpu'
      37 | #define __le16_to_cpu(x) ((__force __u16)(__le16)(x))
         |                                                   ^
   In file included from kernel/exitz.c:4:
   In file included from include/linux/syscalls.h:90:
   In file included from include/trace/syscall.h:7:
   In file included from include/linux/trace_events.h:9:
   In file included from include/linux/hardirq.h:11:
   In file included from arch/um/include/asm/hardirq.h:5:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/um/include/asm/io.h:24:
   include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     573 |         val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr));
         |                                                         ~~~~~~~~~~ ^
   include/uapi/linux/byteorder/little_endian.h:35:51: note: expanded from macro '__le32_to_cpu'
      35 | #define __le32_to_cpu(x) ((__force __u32)(__le32)(x))
         |                                                   ^
   In file included from kernel/exitz.c:4:
   In file included from include/linux/syscalls.h:90:
   In file included from include/trace/syscall.h:7:
   In file included from include/linux/trace_events.h:9:
   In file included from include/linux/hardirq.h:11:
   In file included from arch/um/include/asm/hardirq.h:5:
   In file included from include/asm-generic/hardirq.h:17:
   In file included from include/linux/irq.h:20:
   In file included from include/linux/io.h:13:
   In file included from arch/um/include/asm/io.h:24:
   include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     584 |         __raw_writeb(value, PCI_IOBASE + addr);
         |                             ~~~~~~~~~~ ^
   include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     594 |         __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     604 |         __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr);
         |                                                       ~~~~~~~~~~ ^
   include/asm-generic/io.h:692:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     692 |         readsb(PCI_IOBASE + addr, buffer, count);
         |                ~~~~~~~~~~ ^
   include/asm-generic/io.h:700:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     700 |         readsw(PCI_IOBASE + addr, buffer, count);
         |                ~~~~~~~~~~ ^
   include/asm-generic/io.h:708:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     708 |         readsl(PCI_IOBASE + addr, buffer, count);
         |                ~~~~~~~~~~ ^
   include/asm-generic/io.h:717:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     717 |         writesb(PCI_IOBASE + addr, buffer, count);
         |                 ~~~~~~~~~~ ^
   include/asm-generic/io.h:726:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     726 |         writesw(PCI_IOBASE + addr, buffer, count);
         |                 ~~~~~~~~~~ ^
   include/asm-generic/io.h:735:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
     735 |         writesl(PCI_IOBASE + addr, buffer, count);
         |                 ~~~~~~~~~~ ^
>> kernel/exitz.c:73:6: warning: no previous prototype for function 'exit_memz' [-Wmissing-prototypes]
      73 | void exit_memz(void)
         |      ^
   kernel/exitz.c:73:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
      73 | void exit_memz(void)
         | ^
         | static 
   13 warnings generated.


vim +/exit_memz +73 kernel/exitz.c

    69	
    70	/*
    71	 * Overwrite any memory associated to current process with zeros.
    72	 */
  > 73	void exit_memz(void)
    74	{
    75		if (!(current->ezflags & EZ_MEM))
    76			return;
    77	
    78		struct vm_area_struct *vma;
    79	
    80		VMA_ITERATOR(vmi, current->mm, 0);
    81	
    82		for_each_vma(vmi, vma) {
    83			memz_range(vma->vm_start, vma->vm_end);
    84		}
    85	}
    86	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2023-11-10 22:35 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-10 18:47 [PATCH] mm: exitz syscall York Jasper Niebuhr
2023-11-10 21:40 ` kernel test robot
2023-11-10 22:35 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).