diff --git a/fs/proc/array.c b/fs/proc/array.c
index 51a4213..6350a1e 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -153,6 +153,16 @@ static inline int get_task_umask(struct task_struct *tsk)
 	return umask;
 }
 
+#ifdef CONFIG_PUI
+static inline void put_pui(struct seq_file *m, pui_t pui)
+{
+	pui_str_t str;
+
+	pui_to_str(pui, str);
+	seq_puts(m, str);
+}
+#endif
+
 static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
 				struct pid *pid, struct task_struct *p)
 {
@@ -226,6 +236,17 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
 	for (g = ns->level; g <= pid->level; g++)
 		seq_put_decimal_ull(m, "\t", task_session_nr_ns(p, pid->numbers[g].ns));
 #endif
+#ifdef CONFIG_PUI
+	seq_puts(m, "\nPui:");
+	put_pui(m, pid->numbers[ns->level].pui);
+#ifdef CONFIG_PID_NS
+	seq_puts(m, "\nNSpui:");
+	for (g = ns->level; g <= pid->level; g++) {
+		seq_putc(m, '\t');
+		put_pui(m, pid->numbers[g].pui);
+	}
+#endif
+#endif
 	seq_putc(m, '\n');
 }
 
diff --git a/include/linux/pid.h b/include/linux/pid.h
index 23705a5..9bb131c 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -2,6 +2,7 @@
 #define _LINUX_PID_H
 
 #include <linux/rcupdate.h>
+#include <linux/pui.h>
 
 enum pid_type
 {
@@ -52,6 +53,10 @@ struct upid {
 	int nr;
 	struct pid_namespace *ns;
 	struct hlist_node pid_chain;
+#ifdef CONFIG_PUI
+	struct hlist_node pui_chain;
+	pui_t pui;
+#endif
 };
 
 struct pid
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index 34cce96..cd4844c 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -9,6 +9,7 @@
 #include <linux/nsproxy.h>
 #include <linux/kref.h>
 #include <linux/ns_common.h>
+#include <linux/pui.h>
 
 struct pidmap {
        atomic_t nr_free;
@@ -26,6 +27,9 @@ struct pid_namespace {
 	struct pidmap pidmap[PIDMAP_ENTRIES];
 	struct rcu_head rcu;
 	int last_pid;
+#ifdef CONFIG_PUI
+	pui_gen_t pui_generator;
+#endif
 	unsigned int nr_hashed;
 	struct task_struct *child_reaper;
 	struct kmem_cache *pid_cachep;
diff --git a/include/linux/pui.h b/include/linux/pui.h
new file mode 100644
index 0000000..fee67e2
--- /dev/null
+++ b/include/linux/pui.h
@@ -0,0 +1,55 @@
+#ifndef _LINUX_PUI_H
+#define _LINUX_PUI_H
+
+#ifdef CONFIG_PUI
+
+#include <linux/atomic.h>
+
+typedef __u64       pui_t;
+typedef char        pui_str_t[17];
+typedef atomic64_t  pui_gen_t;
+
+struct pid;
+struct upid;
+struct task_struct;
+struct pid_namespace;
+
+#define PUI_INVALID    0
+#define PUI_GEN_INIT   ATOMIC_INIT(0)
+
+/*
+ * look up a PUI in the hash table. Must be called with the tasklist_lock
+ * or rcu_read_lock() held.
+ *
+ * find_pui_ns() finds the pui in the namespace specified
+ * find_vpui() finds the pui by its virtual id, i.e. in the current namespace
+ */
+extern struct pid *find_pui_ns(pui_t pui, struct pid_namespace *ns);
+extern struct pid *find_vpui(pui_t pui);
+
+/*
+ * find a task by its PUI
+ *
+ * find_task_by_pui_ns():
+ *      finds a task by its pui in the specified namespace
+ * find_task_by_vpui():
+ *      finds a task by its virtual pui
+ */
+extern struct task_struct *find_task_by_pui_ns(pui_t pui, struct pid_namespace *ns);
+extern struct task_struct *find_task_by_vpui(pui_t pui);
+
+extern pui_t pui_nr_ns(struct pid *pid, struct pid_namespace *ns);
+extern pui_t pui_vnr(struct pid *pid);
+
+extern void pui_init_generator(pui_gen_t *generator);
+
+extern void pui_make(struct upid *upid);
+extern void pui_add(struct upid *upid);
+extern void pui_del(struct upid *upid);
+
+extern int pui_to_str(pui_t pui, pui_str_t str);
+extern pui_t pui_from_str(const char *str);
+
+#endif
+
+#endif /* _LINUX_PUI_H */
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index 2c748dd..143bcbe 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -94,4 +94,6 @@
 
 #define SCM_TIMESTAMPING_OPT_STATS	54
 
+#define SO_PEERPUI		55
+
 #endif /* __ASM_GENERIC_SOCKET_H */
diff --git a/init/Kconfig b/init/Kconfig
index 223b734..ff4dde2 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -306,6 +306,12 @@ config USELIB
 	  earlier, you may need to enable this syscall.  Current systems
 	  running glibc can safely disable this.
 
+config PUI
+	bool "Enables Process Unic Identifier"
+	default n
+	help
+	  Provides a 64 bits unic identifier to processes and threads
+
 config AUDIT
 	bool "Auditing support"
 	depends on NET
@@ -2158,3 +2164,4 @@ config ASN1
 	  functions to call on what tags.
 
 source "kernel/Kconfig.locks"
+
diff --git a/kernel/Makefile b/kernel/Makefile
index 12c679f..ebd1cd8 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_CPUSETS) += cpuset.o
 obj-$(CONFIG_UTS_NS) += utsname.o
 obj-$(CONFIG_USER_NS) += user_namespace.o
 obj-$(CONFIG_PID_NS) += pid_namespace.o
+obj-$(CONFIG_PUI) += pui.o
 obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_SMP) += stop_machine.o
 obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
diff --git a/kernel/pid.c b/kernel/pid.c
index f66162f..24b76fe 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -75,6 +75,9 @@ struct pid_namespace init_pid_ns = {
 		[ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL }
 	},
 	.last_pid = 0,
+#ifdef CONFIG_PUI
+	.pui_generator = PUI_GEN_INIT,
+#endif
 	.nr_hashed = PIDNS_HASH_ADDING,
 	.level = 0,
 	.child_reaper = &init_task,
@@ -267,6 +270,9 @@ void free_pid(struct pid *pid)
 		struct upid *upid = pid->numbers + i;
 		struct pid_namespace *ns = upid->ns;
 		hlist_del_rcu(&upid->pid_chain);
+#ifdef CONFIG_PUI
+		pui_del(upid);
+#endif
 		switch(--ns->nr_hashed) {
 		case 2:
 		case 1:
@@ -318,6 +324,9 @@ struct pid *alloc_pid(struct pid_namespace *ns)
 
 		pid->numbers[i].nr = nr;
 		pid->numbers[i].ns = tmp;
+#ifdef CONFIG_PUI
+		pui_make(&pid->numbers[i]);
+#endif
 		tmp = tmp->parent;
 	}
 
@@ -338,6 +347,9 @@ struct pid *alloc_pid(struct pid_namespace *ns)
 	for ( ; upid >= pid->numbers; --upid) {
 		hlist_add_head_rcu(&upid->pid_chain,
 				&pid_hash[pid_hashfn(upid->nr, upid->ns)]);
+#ifdef CONFIG_PUI
+		pui_add(upid);
+#endif
 		upid->ns->nr_hashed++;
 	}
 	spin_unlock_irq(&pidmap_lock);
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index df9e8e9..ed17097 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -130,6 +130,9 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns
 	ns->ucounts = ucounts;
 	ns->nr_hashed = PIDNS_HASH_ADDING;
 	INIT_WORK(&ns->proc_work, proc_cleanup_work);
+#ifdef CONFIG_PUI
+	pui_init_generator(&ns->pui_generator);
+#endif
 
 	set_bit(0, ns->pidmap[0].page);
 	atomic_set(&ns->pidmap[0].nr_free, BITS_PER_PAGE - 1);
diff --git a/kernel/pui.c b/kernel/pui.c
new file mode 100644
index 0000000..d9ab6bb
--- /dev/null
+++ b/kernel/pui.c
@@ -0,0 +1,168 @@
+#ifdef CONFIG_PUI
+
+/*
+#include <linux/mm.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/rculist.h>
+#include <linux/bootmem.h>
+#include <linux/hash.h>
+#include <linux/init_task.h>
+#include <linux/syscalls.h>
+#include <linux/proc_ns.h>
+#include <linux/proc_fs.h>
+*/
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/rculist.h>
+#include <linux/hash.h>
+#include <linux/pui.h>
+#include <linux/pid.h>
+#include <linux/pid_namespace.h>
+
+#define pui_hashfn(pui, ns)	\
+	hash_long((unsigned long)pui + (unsigned long)ns, puihash_shift)
+
+static struct hlist_head *pui_hash;
+static unsigned int puihash_shift = 4;
+
+void __init puihash_init(void)
+{
+	unsigned int i, pidhash_size;
+
+	pui_hash = alloc_large_system_hash("PUI", sizeof(*pui_hash), 0, 18,
+					   HASH_EARLY | HASH_SMALL,
+					   &puihash_shift, NULL,
+					   0, 4096);
+	pidhash_size = 1U << puihash_shift;
+
+	for (i = 0; i < pidhash_size; i++)
+		INIT_HLIST_HEAD(&pui_hash[i]);
+}
+
+struct pid *find_pui_ns(pui_t pui, struct pid_namespace *ns)
+{
+	struct upid *pnr;
+
+	hlist_for_each_entry_rcu(pnr,
+			&pui_hash[pui_hashfn(pui, ns)], pui_chain)
+		if (pnr->pui == pui && pnr->ns == ns)
+			return container_of(pnr, struct pid,
+					numbers[ns->level]);
+
+	return NULL;
+}
+
+struct task_struct *find_task_by_pui_ns(pui_t pui, struct pid_namespace *ns)
+{
+	RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
+			 "find_task_by_pui_ns() needs rcu_read_lock() protection");
+	return pid_task(find_pui_ns(pui, ns), PIDTYPE_PID);
+}
+
+struct pid *find_vpui(pui_t pui)
+{
+	return find_pui_ns(pui, task_active_pid_ns(current));
+}
+
+struct task_struct *find_task_by_vpui(pui_t pui)
+{
+	return find_task_by_pui_ns(pui, task_active_pid_ns(current));
+}
+
+pui_t pui_nr_ns(struct pid *pid, struct pid_namespace *ns)
+{
+	struct upid *upid;
+	pui_t result = PUI_INVALID;
+
+	if (pid && ns->level <= pid->level) {
+		upid = &pid->numbers[ns->level];
+		if (upid->ns == ns)
+			result = upid->pui;
+	}
+	return result;
+}
+
+pui_t pui_vnr(struct pid *pid)
+{
+	return pui_nr_ns(pid, task_active_pid_ns(current));
+}
+
+void pui_init_generator(pui_gen_t *generator)
+{
+	atomic64_set((atomic64_t*)generator, 0);
+}
+
+void pui_del(struct upid *upid)
+{
+	hlist_del_rcu(&upid->pui_chain);
+}
+
+void pui_add(struct upid *upid)
+{
+	hlist_add_head_rcu(&upid->pui_chain,
+			&pui_hash[pui_hashfn(upid->pui, upid->ns)]);
+}
+
+static inline pui_t pui_new(pui_gen_t *generator)
+{
+	pui_t result;
+	do { result = atomic64_inc_return((atomic64_t*)&generator); } while(result == PUI_INVALID);
+	return result;
+}
+
+void pui_make(struct upid *upid)
+{
+	upid->pui = pui_new(&upid->ns->pui_generator);
+}
+
+int pui_to_str(pui_t pui, pui_str_t str)
+{
+	char c;
+	int i, j, r;
+
+	i = 0;
+	do {
+		c = (char)(pui & 15);
+		pui >>= 4;
+		str[i++] = (char)(c + (c > 9 ? 'a' - 10 : '0'));
+	} while(pui);
+	str[r = i] = 0;
+	j = 0;
+	while(j < --i) {
+		c = str[i];
+		str[i] = str[j];
+		str[j++] = c;
+	}
+	return r;
+}
+
+pui_t pui_from_str(const char *str)
+{
+	char c;
+	pui_t result = 0;
+
+	c = *str;
+	if (!c)
+		return PUI_INVALID;
+	do {
+		if ('0' <= c && c <= '9')
+			c = c - '0';
+		else if ('a' <= c && c <= 'f')
+			c = c - 'a' + 10;
+		else if ('A' <= c && c <= 'F')
+			c = c - 'A' + 10;
+		else
+			return PUI_INVALID;
+		if (result >> 60)
+			return PUI_INVALID;
+		result = (result << 4) | c;
+		c = *++str;
+	} while(c);
+	return result;
+}
+
+
+#endif
+
diff --git a/net/core/sock.c b/net/core/sock.c
index f560e08..65f5dbb 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1271,6 +1271,26 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
 		v.val = sk->sk_incoming_cpu;
 		break;
 
+#ifdef CONFIG_PUI
+	case SO_PEERPUI:
+	{
+		pui_str_t str;
+		pui_t pui;
+		int l;
+
+		pui = pui_vnr(sk->sk_peer_pid);
+		if (pui == PUI_INVALID)
+			return -ENOTCONN;
+		l = pui_to_str(pui, str);
+		if (len <= l)
+			return -EINVAL;
+		len = l + 1; /* includes leading zero */
+		if (copy_to_user(optval, str, len))
+			return -EFAULT;
+		goto lenout;
+	}
+#endif
+
 	default:
 		/* We implement the SO_SNDLOWAT etc to not be settable
 		 * (1003.1g 7).
