diff --git a/include/asm-generic/mm_hooks.h b/include/asm-generic/mm_hooks.h
index 4dbb177d1150..7f7f9fa6a17e 100644
--- a/include/asm-generic/mm_hooks.h
+++ b/include/asm-generic/mm_hooks.h
@@ -26,6 +26,11 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
 		bool write, bool execute, bool foreign)
 {
 	/* by default, allow everything */
-	return true;
+	if (likely(vma_write_allowed(vma, write, foreign)))
+		return true;
+
+	pr_err_once("Error : PID[%d] %s writes to read only memory\n",
+		    current->tgid, current->comm);
+	return false;
 }
 #endif	/* _ASM_GENERIC_MM_HOOKS_H */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 5a323422d783..9f259ef35011 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -5,7 +5,6 @@
 #include <linux/errno.h>
 
 #ifdef __KERNEL__
-
 #include <linux/mmdebug.h>
 #include <linux/gfp.h>
 #include <linux/bug.h>
@@ -603,6 +602,26 @@ struct vm_operations_struct {
 					  unsigned long addr);
 };
 
+extern int sysctl_forbid_write_ro_mem __read_mostly;
+
+static inline bool vma_write_allowed(struct vm_area_struct *vma,
+		bool write, bool foreign)
+{
+	if (likely(sysctl_forbid_write_ro_mem == 0))
+		return true;
+
+	/* This function was called when write is true */
+	if (likely(write && (!(vma->vm_flags & VM_WRITE)))) {
+		/* Forbid write to PROT_READ pages from any process*/
+		if (sysctl_forbid_write_ro_mem == 2)
+			return false;
+		/* Forbid write to PROT_READ pages from foreign process*/
+		if (sysctl_forbid_write_ro_mem == 1 && foreign)
+			return false;
+	}
+
+	return true;
+}
 static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
 {
 	static const struct vm_operations_struct dummy_vm_ops = {};
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 8a176d8727a3..3df5c3223c19 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1320,7 +1320,7 @@ static struct ctl_table vm_table[] = {
 		.proc_handler	= overcommit_kbytes_handler,
 	},
 	{
-		.procname	= "page-cluster", 
+		.procname	= "page-cluster",
 		.data		= &page_cluster,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
@@ -1553,6 +1553,15 @@ static struct ctl_table vm_table[] = {
 		.proc_handler	= proc_dointvec,
 		.extra1		= SYSCTL_ZERO,
 	},
+	{
+		.procname	= "forbid_write_ro_mem",
+		.data		= &sysctl_forbid_write_ro_mem,
+		.maxlen		= sizeof(sysctl_forbid_write_ro_mem),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero_ul,
+		.extra2		= &two,
+	},
 #if defined(HAVE_ARCH_PICK_MMAP_LAYOUT) || \
     defined(CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT)
 	{
@@ -1838,7 +1847,7 @@ static struct ctl_table fs_table[] = {
 		.mode		= 0555,
 		.child		= inotify_table,
 	},
-#endif	
+#endif
 #ifdef CONFIG_EPOLL
 	{
 		.procname	= "epoll",
@@ -2319,12 +2328,12 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
 	int *i, vleft, first = 1, err = 0;
 	size_t left;
 	char *kbuf = NULL, *p;
-	
+
 	if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) {
 		*lenp = 0;
 		return 0;
 	}
-	
+
 	i = (int *) tbl_data;
 	vleft = table->maxlen / sizeof(*i);
 	left = *lenp;
@@ -2550,7 +2559,7 @@ static int do_proc_douintvec(struct ctl_table *table, int write,
  * @ppos: file position
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
- * values from/to the user buffer, treated as an ASCII string. 
+ * values from/to the user buffer, treated as an ASCII string.
  *
  * Returns 0 on success.
  */
@@ -3087,7 +3096,7 @@ static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp,
  * @ppos: file position
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
- * values from/to the user buffer, treated as an ASCII string. 
+ * values from/to the user buffer, treated as an ASCII string.
  * The values read are assumed to be in seconds, and are converted into
  * jiffies.
  *
@@ -3109,8 +3118,8 @@ int proc_dointvec_jiffies(struct ctl_table *table, int write,
  * @ppos: pointer to the file position
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
- * values from/to the user buffer, treated as an ASCII string. 
- * The values read are assumed to be in 1/USER_HZ seconds, and 
+ * values from/to the user buffer, treated as an ASCII string.
+ * The values read are assumed to be in 1/USER_HZ seconds, and
  * are converted into jiffies.
  *
  * Returns 0 on success.
@@ -3132,8 +3141,8 @@ int proc_dointvec_userhz_jiffies(struct ctl_table *table, int write,
  * @ppos: the current position in the file
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
- * values from/to the user buffer, treated as an ASCII string. 
- * The values read are assumed to be in 1/1000 seconds, and 
+ * values from/to the user buffer, treated as an ASCII string.
+ * The values read are assumed to be in 1/1000 seconds, and
  * are converted into jiffies.
  *
  * Returns 0 on success.
diff --git a/mm/util.c b/mm/util.c
index 988d11e6c17c..99366829c759 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -911,3 +911,5 @@ int memcmp_pages(struct page *page1, struct page *page2)
 	kunmap_atomic(addr1);
 	return ret;
 }
+
+int sysctl_forbid_write_ro_mem __read_mostly = CONFIG_PROTECT_READONLY_USER_MEMORY;
diff --git a/security/Kconfig b/security/Kconfig
index cd3cc7da3a55..3d4ffcd8ec24 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -143,6 +143,24 @@ config LSM_MMAP_MIN_ADDR
 	  this low address space will need the permission specific to the
 	  systems running LSM.
 
+
+config PROTECT_READONLY_USER_MEMORY
+	int "Protect read only process memory 0 - 2"
+	default 0
+	range 0 2
+	help
+	  Protects read only memory of process code and PLT/GOT table
+	  from possible attack. Attack vector might be /proc/PID/mem, /dev/mem
+	  or process_vm_write() or ptrace() syscalls.
+	  Mostly advised for embedded and production system.
+	  Controlled by sysctl_forbid_write_ro_mem.
+	  Select 0 to allow write to read only memory
+	  Select 1 to forbid write to read only memory from other processes.
+	  As en effect, GDB will refuse to insert a breakpoints.
+	  Select 2 to forbid write to read only memory from any process including itself
+	  As en effect, will stop self modifing code
+
+
 config HAVE_HARDENED_USERCOPY_ALLOCATOR
 	bool
 	help
