==== patch 1 =====

From 7ee1ed5a723723112167ca8603f4e2945d133b33 Mon Sep 17 00:00:00 2001
From: chengengjia <chengjia4574@gmail.com>
Date: Wed, 16 Nov 2016 21:46:49 +0800
Subject: [PATCH] arch: introduce write-rarely memory section

This introduces __write_rarely section as a way
to mark those memory that read only in most case,
but also need to be written to sometimes.

Signed-off-by: chengengjia <chengjia4574@gmail.com>
---
 include/asm-generic/vmlinux.lds.h | 9 +++++++++
 include/linux/cache.h             | 9 +++++++++
 2 files changed, 18 insertions(+)

diff --git a/include/asm-generic/vmlinux.lds.h
b/include/asm-generic/vmlinux.lds.h
index 3074796..684bcf2 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -263,6 +263,14 @@
 #endif

 /*
+ * Allow architectures to handle write_rarely data on their
+ * own by defining an empty WRITE_RARELY_DATA.
+ */
+#ifndef WRITE_RARELY_DATA
+#define WRITE_RARELY_DATA *(.data..write_rarely)
+#endif
+
+/*
  * Read only Data
  */
 #define RO_DATA_SECTION(align) \
@@ -271,6 +279,7 @@
  VMLINUX_SYMBOL(__start_rodata) = .; \
  *(.rodata) *(.rodata.*) \
  RO_AFTER_INIT_DATA /* Read only after init */ \
+ WRITE_RARELY_DATA /* write rarely*/ \
  *(__vermagic) /* Kernel version magic */ \
  . = ALIGN(8); \
  VMLINUX_SYMBOL(__start___tracepoints_ptrs) = .; \
diff --git a/include/linux/cache.h b/include/linux/cache.h
index 1be04f8..d2c30cd 100644
--- a/include/linux/cache.h
+++ b/include/linux/cache.h
@@ -30,6 +30,15 @@
 #define __ro_after_init
__attribute__((__section__(".data..ro_after_init")))
 #endif

+/*
+ * __write_rarely is used to mark things that are read-only mostly but
need to be
+ * written to sometimes. To write to __write_rarely variables,
mark_wrdata_rw()
+ * need to be called, after write, mark_wrdata_ro() should be called.
+ */
+#ifndef __write_rarely
+#define __write_rarely __attribute__((__section__(".data..write_rarely")))
+#endif
+
 #ifndef ____cacheline_aligned
 #define ____cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES)))
 #endif
-- 
1.9.1


==== patch 2 =====

From 0472f3f14532577a1963d517da8a0edfe1d99375 Mon Sep 17 00:00:00 2001
From: chengengjia <chengjia4574@gmail.com>
Date: Wed, 16 Nov 2016 22:16:43 +0800
Subject: [PATCH] arch: arm: add mark_wrdata_rw/mark_wrdata_ro functions

This introduces mark_wrdata_rw/mark_wrdata_ro to
mark __write_rarely section writable/unwritable.
Based on work by PaxTeam and Grsecurity.

Signed-off-by: chengengjia <chengjia4574@gmail.com>
---
 arch/arm/include/asm/domain.h  | 14 ++++++++++++++
 arch/arm/include/asm/pgtable.h | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/arch/arm/include/asm/domain.h b/arch/arm/include/asm/domain.h
index 99d9f63..01f18a5 100644
--- a/arch/arm/include/asm/domain.h
+++ b/arch/arm/include/asm/domain.h
@@ -54,6 +54,10 @@
 #else
 #define DOMAIN_MANAGER 1
 #endif
+#ifdef  CONFIG_DEBUG_RODATA
+#define DOMAIN_OPENKERN 3
+#endif
+

 #define domain_mask(dom) ((3) << (2 * (dom)))
 #define domain_val(dom,type) ((type) << (2 * (dom)))
@@ -124,6 +128,16 @@ static inline void set_domain(unsigned val)
  set_domain(domain); \
  } while (0)

+#elif defined(CONFIG_DEBUG_RODATA)
+#define modify_domain(dom,type)                                 \
+        do {                                                    \
+                struct thread_info *thread = current_thread_info(); \
+                unsigned int domain = get_domain();             \
+                domain &= ~domain_mask(dom);                    \
+                domain = domain | domain_val(dom, type);        \
+                thread->cpu_domain = domain;                    \
+                set_domain(domain);                             \
+        } while (0)
 #else
 static inline void modify_domain(unsigned dom, unsigned type) { }
 #endif
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index a8d656d..5e6f553 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -56,6 +56,44 @@
 #define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd)
 #define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd)

+#ifdef  CONFIG_DEBUG_RODATA
+#include <asm/domain.h>
+#include <linux/thread_info.h>
+#include <linux/preempt.h>
+
+static inline int test_domain(int domain, int domaintype)
+{
+        return ((current_thread_info()->cpu_domain) & domain_val(domain,
3))
+ == domain_val(domain, domaintype);
+}
+
+static inline unsigned long mark_wrdata_rw(void) {
+#ifdef CONFIG_ARM_LPAE
+        /* TODO */
+#else
+        preempt_disable();
+        BUG_ON(test_domain(DOMAIN_KERNEL, DOMAIN_OPENKERN));
+        modify_domain(DOMAIN_KERNEL, DOMAIN_OPENKERN);
+#endif
+        return 0;
+}
+
+static inline unsigned long mark_wrdata_ro(void) {
+#ifdef CONFIG_ARM_LPAE
+        /* TODO */
+#else
+        BUG_ON(test_domain(DOMAIN_KERNEL, DOMAIN_MANAGER));
+        modify_domain(DOMAIN_KERNEL, DOMAIN_MANAGER);
+        preempt_enable_no_resched();
+#endif
+        return 0;
+}
+#else
+static inline unsigned long mark_wrdata_rw(void) { return 0; }
+static inline unsigned long mark_wrdata_ro(void) { return 0; }
+#endif
+
+
 /*
  * This is the lowest virtual address we can permit any user space
