diff --git a/fs/proc/base.c b/fs/proc/base.c
index ec158dd02b3ac2b758fbbf527820c1f0f83a486a..a721acfd4fdcd3a008befe2a8a185a863b5e0903 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1447,11 +1447,29 @@ static const struct file_operations proc_fd_operations = {
 	.readdir	= proc_readfd,
 };
 
+/*
+ * /proc/pid/fd needs a special permission handler so that a process can still
+ * access /proc/self/fd after it has executed a setuid().
+ */
+static int proc_fd_permission(struct inode *inode, int mask,
+				struct nameidata *nd)
+{
+	int rv;
+
+	rv = generic_permission(inode, mask, NULL);
+	if (rv == 0)
+		return 0;
+	if (task_pid(current) == proc_pid(inode))
+		rv = 0;
+	return rv;
+}
+
 /*
  * proc directories can do almost nothing..
  */
 static const struct inode_operations proc_fd_inode_operations = {
 	.lookup		= proc_lookupfd,
+	.permission	= proc_fd_permission,
 	.setattr	= proc_setattr,
 };