diff --git a/grsecurity/Kconfig b/grsecurity/Kconfig
index 6d8c857..7c0ac36 100644
--- a/grsecurity/Kconfig
+++ b/grsecurity/Kconfig
@@ -792,6 +792,23 @@ config GRKERNSEC_SETXID
 	  running with root privileges.  If the sysctl option is enabled,
 	  a sysctl option with name "consistent_setxid" is created.
 
+config GRKERNSEC_HARDEN_IPC
+	bool "Disallow access to world-accessible IPC objects"
+	default y if GRKERNSEC_CONFIG_AUTO
+	help
+	  If you say Y here, access to overly-permissive IPC (shared memory,
+	  message queues, and semaphores) will be denied for processes whose
+	  effective user or group would not grant them permission.  It's a
+	  common error to grant too much permission to these objects, with
+	  impact ranging from denial of service and information leaking to
+	  privilege escalation.  This feature was developed in response to
+	  research by Tim Brown:
+	  http://labs.portcullis.co.uk/whitepapers/memory-squatting-attacks-on-system-v-shared-memory/
+	  who found hundreds of such insecure usages.  Processes with
+	  CAP_IPC_OWNER are still permitted to access these IPC objects.
+	  If the sysctl option is enabled, a sysctl option with name
+	  "harden_ipc" is created.
+
 config GRKERNSEC_TPE
 	bool "Trusted Path Execution (TPE)"
 	default y if GRKERNSEC_CONFIG_AUTO && GRKERNSEC_CONFIG_SERVER
diff --git a/grsecurity/Makefile b/grsecurity/Makefile
index b0b77d5..0bc0a5c 100644
--- a/grsecurity/Makefile
+++ b/grsecurity/Makefile
@@ -11,7 +11,7 @@ KBUILD_CFLAGS += -Werror
 obj-y = grsec_chdir.o grsec_chroot.o grsec_exec.o grsec_fifo.o grsec_fork.o \
 	grsec_mount.o grsec_sig.o grsec_sysctl.o \
 	grsec_time.o grsec_tpe.o grsec_link.o grsec_pax.o grsec_ptrace.o \
-	grsec_usb.o
+	grsec_usb.o grsec_ipc.o
 
 obj-$(CONFIG_GRKERNSEC) += grsec_init.o grsum.o gracl.o gracl_segv.o \
 	gracl_cap.o gracl_alloc.o gracl_shm.o grsec_mem.o gracl_fs.o \
diff --git a/grsecurity/grsec_init.c b/grsecurity/grsec_init.c
index 99a0cb9..087cf30 100644
--- a/grsecurity/grsec_init.c
+++ b/grsecurity/grsec_init.c
@@ -15,6 +15,7 @@ int grsec_enable_brute;
 int grsec_enable_link;
 int grsec_enable_dmesg;
 int grsec_enable_harden_ptrace;
+int grsec_enable_harden_ipc;
 int grsec_enable_fifo;
 int grsec_enable_execlog;
 int grsec_enable_signal;
@@ -169,6 +170,9 @@ grsecurity_init(void)
 #ifdef CONFIG_GRKERNSEC_HARDEN_PTRACE
 	grsec_enable_harden_ptrace = 1;
 #endif
+#ifdef CONFIG_GRKERNSEC_HARDEN_IPC
+	grsec_enable_harden_ipc = 1;
+#endif
 #ifdef CONFIG_GRKERNSEC_AUDIT_MOUNT
 	grsec_enable_mount = 1;
 #endif
diff --git a/grsecurity/grsec_ipc.c b/grsecurity/grsec_ipc.c
new file mode 100644
index 0000000..f365de0
--- /dev/null
+++ b/grsecurity/grsec_ipc.c
@@ -0,0 +1,22 @@
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/ipc.h>
+#include <linux/ipc_namespace.h>
+#include <linux/grsecurity.h>
+#include <linux/grinternal.h>
+
+int
+gr_ipc_permitted(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, int requested_mode, int granted_mode)
+{
+#ifdef CONFIG_GRKERNSEC_HARDEN_IPC
+	int write = (requested_mode & 00002);
+
+	if (grsec_enable_harden_ipc && !(requested_mode & ~granted_mode & 0007) && !ns_capable_nolog(ns->user_ns, CAP_IPC_OWNER)) {
+		gr_log_str2_int(GR_DONT_AUDIT, GR_IPC_DENIED_MSG, write ? "write" : "read", write ? "writ" : "read", GR_GLOBAL_UID(ipcp->cuid));
+		return 0;
+	}
+#endif
+	return 1;
+}
diff --git a/grsecurity/grsec_sysctl.c b/grsecurity/grsec_sysctl.c
index a147ae7..8159888 100644
--- a/grsecurity/grsec_sysctl.c
+++ b/grsecurity/grsec_sysctl.c
@@ -437,6 +437,15 @@ struct ctl_table grsecurity_table[] = {
 		.proc_handler	= &proc_dointvec,
 	},
 #endif
+#ifdef CONFIG_GRKERNSEC_HARDEN_IPC
+	{
+		.procname	= "harden_ipc",
+		.data		= &grsec_enable_harden_ipc,
+		.maxlen		= sizeof(int),
+		.mode		= 0600,
+		.proc_handler	= &proc_dointvec,
+	},
+#endif
 	{
 		.procname	= "grsec_lock",
 		.data		= &grsec_lock,
diff --git a/include/linux/grinternal.h b/include/linux/grinternal.h
index e337683..a5625be 100644
--- a/include/linux/grinternal.h
+++ b/include/linux/grinternal.h
@@ -81,6 +81,7 @@ extern int grsec_resource_logging;
 extern int grsec_enable_blackhole;
 extern int grsec_lastack_retries;
 extern int grsec_enable_brute;
+extern int grsec_enable_harden_ipc;
 extern int grsec_lock;
 
 extern spinlock_t grsec_alert_lock;
diff --git a/include/linux/grmsg.h b/include/linux/grmsg.h
index a4396b5..378a81a 100644
--- a/include/linux/grmsg.h
+++ b/include/linux/grmsg.h
@@ -111,3 +111,4 @@
 #define GR_SYMLINKOWNER_MSG "denied following symlink %.950s since symlink owner %u does not match target owner %u, by "
 #define GR_BRUTE_DAEMON_MSG "bruteforce prevention initiated for the next 30 minutes or until service restarted, stalling each fork 30 seconds.  Please investigate the crash report for "
 #define GR_BRUTE_SUID_MSG "bruteforce prevention initiated due to crash of %.950s against uid %u, banning suid/sgid execs for %u minutes.  Please investigate the crash report for "
+#define GR_IPC_DENIED_MSG "denied %s of globally-%sable IPC with creator uid %u by "
diff --git a/ipc/util.c b/ipc/util.c
index fdb8ae7..f1cb373 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -56,6 +56,8 @@ struct ipc_proc_iface {
 	int (*show)(struct seq_file *, void *);
 };
 
+extern int gr_ipc_permitted(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, int requested_mode, int granted_mode);
+
 static void ipc_memory_notifier(struct work_struct *work)
 {
 	ipcns_notify(IPCNS_MEMCHANGED);
@@ -545,6 +547,9 @@ int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
 		granted_mode >>= 6;
 	else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
 		granted_mode >>= 3;
+	else if (!gr_ipc_permitted(ns, ipcp, requested_mode, granted_mode))
+		return -1;
+
 	/* is there some bit set in requested_mode but not in granted_mode? */
 	if ((requested_mode & ~granted_mode & 0007) && 
 	    !ns_capable(ns->user_ns, CAP_IPC_OWNER))
