diff --git a/grsecurity/Kconfig b/grsecurity/Kconfig
index a326c8d..5da9574 100644
--- a/grsecurity/Kconfig
+++ b/grsecurity/Kconfig
@@ -793,15 +793,19 @@ config GRKERNSEC_SETXID
 	  a sysctl option with name "consistent_setxid" is created.
 
 config GRKERNSEC_HARDEN_IPC
-	bool "Disallow access to world-accessible IPC objects"
+	bool "Disallow access to overly-permissive IPC objects"
 	default y if GRKERNSEC_CONFIG_AUTO
 	depends on SYSVIPC
 	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
+	  If you say Y here, access to overly-permissive IPC objects (shared
+	  memory, message queues, and semaphores) will be denied for processes
+	  given the following criteria beyond normal permission checks:
+	  1) If the IPC object is world-accessible and the euid doesn't match
+	     that of the creator or current uid for the IPC object
+	  2) If the IPC object is group-accessible and the egid doesn't
+	     match that of the creator or current gid for the IPC object
+	  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/
diff --git a/grsecurity/grsec_ipc.c b/grsecurity/grsec_ipc.c
index f365de0..78d1680 100644
--- a/grsecurity/grsec_ipc.c
+++ b/grsecurity/grsec_ipc.c
@@ -11,10 +11,36 @@ 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);
+	int write;
+	int orig_granted_mode;
+	kuid_t euid;
+	kgid_t egid;
 
-	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));
+	if (!grsec_enable_harden_ipc)
+		return 0;
+
+	euid = current_euid();
+	egid = current_egid();
+
+	write = requested_mode & 00002;
+	orig_granted_mode = ipcp->mode;
+
+	if (uid_eq(euid, ipcp->cuid) || uid_eq(euid, ipcp->uid))
+		orig_granted_mode >>= 6;
+	else {
+		/* if likely wrong permissions, lock to user */
+		if (orig_granted_mode & 0007)
+			orig_granted_mode = 0;
+		/* otherwise do a egid-only check */
+		else if (gid_eq(egid, ipcp->cgid) || gid_eq(egid, ipcp->gid))
+			orig_granted_mode >>= 3;
+		/* otherwise, no access */
+		else
+			orig_granted_mode = 0;
+	}
+	if (!(requested_mode & ~granted_mode & 0007) && (requested_mode & ~orig_granted_mode & 0007) &&
+	    !ns_capable_nolog(ns->user_ns, CAP_IPC_OWNER)) {
+		gr_log_str_int(GR_DONT_AUDIT, GR_IPC_DENIED_MSG, write ? "write" : "read", GR_GLOBAL_UID(ipcp->cuid));
 		return 0;
 	}
 #endif
diff --git a/include/linux/grmsg.h b/include/linux/grmsg.h
index 378a81a..e204df0 100644
--- a/include/linux/grmsg.h
+++ b/include/linux/grmsg.h
@@ -111,4 +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 "
+#define GR_IPC_DENIED_MSG "denied %s of overly-permissive IPC object with creator uid %u by "
diff --git a/ipc/util.c b/ipc/util.c
index f1cb373..33dc169 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -547,7 +547,8 @@ 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))
+
+	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? */
