[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-id: <1403787354-15177-3-git-send-email-p.wilczek@samsung.com>
Date: Thu, 26 Jun 2014 14:55:54 +0200
From: Piotr Wilczek <p.wilczek@...sung.com>
To: David Miller <davem@...emloft.net>
Cc: netdev@...r.kernel.org, Kyungmin Park <kyungmin.park@...sung.com>,
Juho Son <juho80.son@...sung.com>,
Bartlomiej Zolnierkiewicz <b.zolnierkie@...sung.com>,
Jan Kaluza <jkaluza@...hat.com>,
Piotr Wilczek <p.wilczek@...sung.com>
Subject: [PATCH net-next V2 2/2] Send process status in SCM_PROCINFO
This introduces a new SCM type called SCM_PROCINFO to allow the direct
attaching of process status to SCM, which is significantly more
efficient and will reliably avoid the race with the round-trip over
procfs. This is optional and can be turned on by setting SO_PASSPROC.
To achieve that, new struct called unix_skb_parms_scm had to be created,
because otherwise unix_skb_parms would be too big.
This patch is reworked version of:
https://lkml.org/lkml/2014/1/13/40
Signed-off-by: Jan Kaluza <jkaluza@...hat.com>
Signed-off-by: Piotr Wilczek <p.wilczek@...sung.com>
---
Changes for v2:
- removed extern declaration
- removed duplication code for parsing process information
arch/alpha/include/uapi/asm/socket.h | 2 +
arch/avr32/include/uapi/asm/socket.h | 2 +
arch/cris/include/uapi/asm/socket.h | 2 +
arch/frv/include/uapi/asm/socket.h | 2 +
arch/ia64/include/uapi/asm/socket.h | 2 +
arch/m32r/include/uapi/asm/socket.h | 2 +
arch/mips/include/uapi/asm/socket.h | 2 +
arch/mn10300/include/uapi/asm/socket.h | 2 +
arch/parisc/include/uapi/asm/socket.h | 2 +
arch/powerpc/include/uapi/asm/socket.h | 2 +
arch/s390/include/uapi/asm/socket.h | 2 +
arch/sparc/include/uapi/asm/socket.h | 2 +
include/linux/net.h | 1 +
include/linux/socket.h | 2 +
include/net/af_unix.h | 9 ++
include/net/scm.h | 33 +++++++
include/uapi/asm-generic/socket.h | 2 +
net/Kconfig | 1 +
net/core/scm.c | 166 +++++++++++++++++++++++++++++++++
net/core/sock.c | 11 +++
net/unix/af_unix.c | 70 ++++++++++++++
21 files changed, 319 insertions(+)
diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
index 3de1394..29608f2 100644
--- a/arch/alpha/include/uapi/asm/socket.h
+++ b/arch/alpha/include/uapi/asm/socket.h
@@ -87,4 +87,6 @@
#define SO_BPF_EXTENSIONS 48
+#define SO_PASSPROC 49
+
#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/avr32/include/uapi/asm/socket.h b/arch/avr32/include/uapi/asm/socket.h
index 6e6cd15..a9bbc63 100644
--- a/arch/avr32/include/uapi/asm/socket.h
+++ b/arch/avr32/include/uapi/asm/socket.h
@@ -80,4 +80,6 @@
#define SO_BPF_EXTENSIONS 48
+#define SO_PASSPROC 49
+
#endif /* _UAPI__ASM_AVR32_SOCKET_H */
diff --git a/arch/cris/include/uapi/asm/socket.h b/arch/cris/include/uapi/asm/socket.h
index ed94e5e..df0c641 100644
--- a/arch/cris/include/uapi/asm/socket.h
+++ b/arch/cris/include/uapi/asm/socket.h
@@ -82,6 +82,8 @@
#define SO_BPF_EXTENSIONS 48
+#define SO_PASSPROC 49
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/frv/include/uapi/asm/socket.h b/arch/frv/include/uapi/asm/socket.h
index ca2c6e6..3cd9cb1 100644
--- a/arch/frv/include/uapi/asm/socket.h
+++ b/arch/frv/include/uapi/asm/socket.h
@@ -80,5 +80,7 @@
#define SO_BPF_EXTENSIONS 48
+#define SO_PASSPROC 49
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/ia64/include/uapi/asm/socket.h b/arch/ia64/include/uapi/asm/socket.h
index a1b49ba..656ba43 100644
--- a/arch/ia64/include/uapi/asm/socket.h
+++ b/arch/ia64/include/uapi/asm/socket.h
@@ -89,4 +89,6 @@
#define SO_BPF_EXTENSIONS 48
+#define SO_PASSPROC 49
+
#endif /* _ASM_IA64_SOCKET_H */
diff --git a/arch/m32r/include/uapi/asm/socket.h b/arch/m32r/include/uapi/asm/socket.h
index 6c9a24b..758ce55 100644
--- a/arch/m32r/include/uapi/asm/socket.h
+++ b/arch/m32r/include/uapi/asm/socket.h
@@ -80,4 +80,6 @@
#define SO_BPF_EXTENSIONS 48
+#define SO_PASSPROC 49
+
#endif /* _ASM_M32R_SOCKET_H */
diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
index a14baa2..cc7b8f5 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -98,4 +98,6 @@
#define SO_BPF_EXTENSIONS 48
+#define SO_PASSPROC 49
+
#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/mn10300/include/uapi/asm/socket.h b/arch/mn10300/include/uapi/asm/socket.h
index 6aa3ce1..b49368f2 100644
--- a/arch/mn10300/include/uapi/asm/socket.h
+++ b/arch/mn10300/include/uapi/asm/socket.h
@@ -80,4 +80,6 @@
#define SO_BPF_EXTENSIONS 48
+#define SO_PASSPROC 49
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
index fe35cea..b3facfa 100644
--- a/arch/parisc/include/uapi/asm/socket.h
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -79,4 +79,6 @@
#define SO_BPF_EXTENSIONS 0x4029
+#define SO_PASSPROC 0x402a
+
#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/powerpc/include/uapi/asm/socket.h b/arch/powerpc/include/uapi/asm/socket.h
index a9c3e2e..b582047 100644
--- a/arch/powerpc/include/uapi/asm/socket.h
+++ b/arch/powerpc/include/uapi/asm/socket.h
@@ -87,4 +87,6 @@
#define SO_BPF_EXTENSIONS 48
+#define SO_PASSPROC 49
+
#endif /* _ASM_POWERPC_SOCKET_H */
diff --git a/arch/s390/include/uapi/asm/socket.h b/arch/s390/include/uapi/asm/socket.h
index e031332..ffd6fa5 100644
--- a/arch/s390/include/uapi/asm/socket.h
+++ b/arch/s390/include/uapi/asm/socket.h
@@ -86,4 +86,6 @@
#define SO_BPF_EXTENSIONS 48
+#define SO_PASSPROC 49
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
index 54d9608..875353f 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -76,6 +76,8 @@
#define SO_BPF_EXTENSIONS 0x0032
+#define SO_PASSPROC 0x0033
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
diff --git a/include/linux/net.h b/include/linux/net.h
index 17d8339..38ad416 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -39,6 +39,7 @@ struct net;
#define SOCK_PASSCRED 3
#define SOCK_PASSSEC 4
#define SOCK_EXTERNALLY_ALLOCATED 5
+#define SOCK_PASSPROC 6
#ifndef ARCH_HAS_SOCKET_TYPES
/**
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 8e98297..a5ebf79 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -130,6 +130,8 @@ static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr
#define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */
#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */
#define SCM_SECURITY 0x03 /* rw: security label */
+#define SCM_PROCINFO 0x05 /* rw: comm + cmdline (NULL terminated
+ array of char *) */
struct ucred {
__u32 pid;
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index a175ba4..05c7678 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -27,6 +27,13 @@ struct unix_address {
struct sockaddr_un name[0];
};
+struct unix_skb_parms_scm {
+ kuid_t loginuid;
+ unsigned int sessionid;
+ char *procinfo;
+ int procinfo_len;
+};
+
struct unix_skb_parms {
struct pid *pid; /* Skb credentials */
kuid_t uid;
@@ -36,10 +43,12 @@ struct unix_skb_parms {
u32 secid; /* Security ID */
#endif
u32 consumed;
+ struct unix_skb_parms_scm *scm;
};
#define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb))
#define UNIXSID(skb) (&UNIXCB((skb)).secid)
+#define UNIXSCM(skb) (*(UNIXCB((skb)).scm))
#define unix_state_lock(s) spin_lock(&unix_sk(s)->lock)
#define unix_state_unlock(s) spin_unlock(&unix_sk(s)->lock)
diff --git a/include/net/scm.h b/include/net/scm.h
index 262532d..981aa1f 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -24,6 +24,11 @@ struct scm_fp_list {
struct file *fp[SCM_MAX_FD];
};
+struct scm_procinfo {
+ char *procinfo;
+ int len;
+};
+
struct scm_cookie {
struct pid *pid; /* Skb credentials */
struct scm_fp_list *fp; /* Passed files */
@@ -31,6 +36,7 @@ struct scm_cookie {
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
+ struct scm_procinfo procinfo; /* Skb procinfo */
};
void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm);
@@ -38,6 +44,7 @@ void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm);
int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm);
void __scm_destroy(struct scm_cookie *scm);
struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl);
+int scm_get_current_procinfo(char **procinfo);
#ifdef CONFIG_SECURITY_NETWORK
static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
@@ -49,6 +56,13 @@ static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_co
{ }
#endif /* CONFIG_SECURITY_NETWORK */
+static inline void scm_set_procinfo(struct scm_cookie *scm,
+ char *procinfo, int len)
+{
+ scm->procinfo.procinfo = procinfo;
+ scm->procinfo.len = len;
+}
+
static __inline__ void scm_set_cred(struct scm_cookie *scm,
struct pid *pid, kuid_t uid, kgid_t gid)
{
@@ -64,9 +78,17 @@ static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
scm->pid = NULL;
}
+static __inline__ void scm_destroy_procinfo(struct scm_cookie *scm)
+{
+ kfree(scm->procinfo.procinfo);
+ scm->procinfo.procinfo = NULL;
+ scm->procinfo.len = 0;
+}
+
static __inline__ void scm_destroy(struct scm_cookie *scm)
{
scm_destroy_cred(scm);
+ scm_destroy_procinfo(scm);
if (scm->fp)
__scm_destroy(scm);
}
@@ -74,11 +96,18 @@ static __inline__ void scm_destroy(struct scm_cookie *scm)
static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
struct scm_cookie *scm, bool forcecreds)
{
+ char *procinfo;
+ int len;
memset(scm, 0, sizeof(*scm));
scm->creds.uid = INVALID_UID;
scm->creds.gid = INVALID_GID;
if (forcecreds)
scm_set_cred(scm, task_tgid(current), current_uid(), current_gid());
+ if (test_bit(SOCK_PASSPROC, &sock->flags)) {
+ len = scm_get_current_procinfo(&procinfo);
+ if (len > 0)
+ scm_set_procinfo(scm, procinfo, len);
+ }
unix_get_peersec_dgram(sock, scm);
if (msg->msg_controllen <= 0)
return 0;
@@ -125,8 +154,12 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
};
put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
}
+ if (test_bit(SOCK_PASSPROC, &sock->flags))
+ put_cmsg(msg, SOL_SOCKET, SCM_PROCINFO, scm->procinfo.len,
+ scm->procinfo.procinfo);
scm_destroy_cred(scm);
+ scm_destroy_procinfo(scm);
scm_passec(sock, msg, scm);
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index ea0796b..8ce4e94 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -82,4 +82,6 @@
#define SO_BPF_EXTENSIONS 48
+#define SO_PASSPROC 49
+
#endif /* __ASM_GENERIC_SOCKET_H */
diff --git a/net/Kconfig b/net/Kconfig
index d92afe4..f438269 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -6,6 +6,7 @@ menuconfig NET
bool "Networking support"
select NLATTR
select GENERIC_NET_UTILS
+ select PROC_INFO
---help---
Unless you really know what you are doing, you should say Y here.
The reason is that some programs need kernel networking support even
diff --git a/net/core/scm.c b/net/core/scm.c
index b442e7e..ce427b4 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -28,6 +28,10 @@
#include <linux/pid.h>
#include <linux/nsproxy.h>
#include <linux/slab.h>
+#include <linux/ptrace.h>
+#include <linux/fdtable.h>
+#include <linux/cpuset.h>
+#include <linux/proc_info.h>
#include <asm/uaccess.h>
@@ -38,6 +42,9 @@
#include <net/scm.h>
#include <net/cls_cgroup.h>
+#ifdef CONFIG_USER_NS
+extern struct user_namespace init_user_ns;
+#endif
/*
* Only allow a user to send credentials, that they could set with
@@ -339,3 +346,162 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
return new_fpl;
}
EXPORT_SYMBOL(scm_fp_dup);
+
+static int get_proc_cmdline(struct mm_struct *mm, char *buffer)
+{
+ int res, i;
+ unsigned int len;
+
+ len = mm->arg_end - mm->arg_start;
+
+ if (len > PAGE_SIZE)
+ len = PAGE_SIZE;
+
+ res = access_process_vm(current, mm->arg_start, buffer, len, 0);
+
+ /* If the nul at the end of args has been overwritten, then
+ * assume application is using setproctitle(3).
+ */
+ if (res > 0 && buffer[res-1] != '\0' && len < PAGE_SIZE) {
+ len = strnlen(buffer, res);
+ if (len < res) {
+ res = len;
+ } else {
+ len = mm->env_end - mm->env_start;
+ if (len > PAGE_SIZE - res)
+ len = PAGE_SIZE - res;
+ res += access_process_vm(current, mm->env_start,
+ buffer+res, len, 0);
+ res = strnlen(buffer, res);
+ }
+ }
+
+ for (i = 0; i < res - 1; i++)
+ if (buffer[i] == '\0')
+ buffer[i] = ' ';
+
+ return res;
+}
+
+static char *get_proc_exe(struct mm_struct *mm)
+{
+ struct file *exe_file;
+ struct path exe_path;
+ char tmp[80], *exepathname;
+
+ exe_file = get_mm_exe_file(mm);
+ if (!exe_file)
+ return NULL;
+
+ exe_path = exe_file->f_path;
+ path_get(&exe_file->f_path);
+ fput(exe_file);
+
+ exepathname = d_path(&exe_path, tmp, sizeof(tmp));
+ path_put(&exe_path);
+
+ return exepathname;
+}
+
+static void get_task_status(struct mm_struct *mm, struct task_struct *task,
+ char *buf, int size)
+{
+ struct seq_file m;
+ struct pid_namespace *ns = task_active_pid_ns(task);
+ struct pid *pid = get_pid(task_tgid(task));
+
+ m.buf = buf;
+ m.size = size;
+#ifdef CONFIG_USER_NS
+ m.user_ns = &init_user_ns;
+#endif
+
+ proc_pid_status_mm(&m, ns, pid, task, mm);
+}
+
+int scm_get_current_procinfo(char **procinfo)
+{
+ int res = 0;
+ unsigned int len;
+ char *pos;
+ char *buf_cmdline = NULL;
+ char *buf_status = NULL;
+ struct mm_struct *mm;
+ int comm_len = strlen(current->comm);
+ static char *str_comm = "COMM=";
+ static char *str_cmdline = "CMDLINE=";
+ static char *str_exe = "EXE=";
+ static char *str_status = "STATUS=";
+ char *exepathname;
+
+ *procinfo = NULL;
+
+ buf_cmdline = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf_cmdline)
+ return -ENOMEM;
+
+ buf_status = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf_status) {
+ res = -ENOMEM;
+ goto out;
+ }
+ memset(buf_status, 0, PAGE_SIZE);
+
+ mm = get_task_mm(current);
+ if (!mm)
+ goto out;
+ if (!mm->arg_end)
+ goto out_mm; /* Shh! No looking before we're done */
+
+ res = get_proc_cmdline(mm, buf_cmdline);
+
+ exepathname = get_proc_exe(mm);
+ if (exepathname == NULL)
+ goto out_mm;
+
+ get_task_status(mm, current, buf_status, PAGE_SIZE);
+
+ /* strlen(comm) + \0 + len of cmdline */
+ len = strlen(str_comm) + comm_len + 1;
+ if (res)
+ len += strlen(str_cmdline) + res + 1;
+ if (!IS_ERR(exepathname))
+ len += strlen(str_exe) + strlen(exepathname) + 1;
+ if (strlen(buf_status) > 0)
+ len += strlen(str_status) + strlen(buf_status);
+
+ *procinfo = kmalloc(len, GFP_KERNEL);
+ if (!*procinfo) {
+ res = -ENOMEM;
+ goto out_mm;
+ }
+
+ pos = *procinfo;
+ pos = strcpy(*procinfo, str_comm) + strlen(str_comm);
+ pos = memcpy(pos, current->comm, comm_len + 1) + comm_len + 1;
+
+ if (res > 0) {
+ pos = strcpy(pos, str_cmdline) + strlen(str_cmdline);
+ pos = memcpy(pos, buf_cmdline, res) + res;
+ }
+
+ if (!IS_ERR(exepathname)) {
+ pos = strcpy(pos, str_exe) + strlen(str_exe);
+ pos = strcpy(pos, exepathname) + strlen(exepathname);
+ pos = strcpy(pos + 1, "") /*+ 1*/;
+ }
+
+ if (strlen(buf_status) > 0) {
+ pos = strcpy(pos, str_status) + strlen(str_status);
+ pos = strcpy(pos, buf_status) + strlen(buf_status);
+ }
+
+ res = len;
+
+out_mm:
+ mmput(mm);
+out:
+ kfree(buf_cmdline);
+ kfree(buf_status);
+ return res;
+}
diff --git a/net/core/sock.c b/net/core/sock.c
index 026e01f..1099e19 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -828,6 +828,13 @@ set_rcvbuf:
clear_bit(SOCK_PASSCRED, &sock->flags);
break;
+ case SO_PASSPROC:
+ if (valbool)
+ set_bit(SOCK_PASSPROC, &sock->flags);
+ else
+ clear_bit(SOCK_PASSPROC, &sock->flags);
+ break;
+
case SO_TIMESTAMP:
case SO_TIMESTAMPNS:
if (valbool) {
@@ -1142,6 +1149,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
v.val = !!test_bit(SOCK_PASSCRED, &sock->flags);
break;
+ case SO_PASSPROC:
+ v.val = !!test_bit(SOCK_PASSPROC, &sock->flags);
+ break;
+
case SO_PEERCRED:
{
struct ucred peercred;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index e968843..bc6c367 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1360,9 +1360,15 @@ static void unix_destruct_scm(struct sk_buff *skb)
struct scm_cookie scm;
memset(&scm, 0, sizeof(scm));
scm.pid = UNIXCB(skb).pid;
+ if (UNIXCB(skb).scm) {
+ scm.procinfo.procinfo = UNIXSCM(skb).procinfo;
+ scm.procinfo.len = UNIXSCM(skb).procinfo_len;
+ }
if (UNIXCB(skb).fp)
unix_detach_fds(&scm, skb);
+ kfree(UNIXCB(skb).scm);
+
/* Alas, it calls VFS */
/* So fscking what? fput() had been SMP-safe since the last Summer */
scm_destroy(&scm);
@@ -1409,6 +1415,13 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
{
int err = 0;
+ if (!UNIXCB(skb).scm) {
+ UNIXCB(skb).scm = kmalloc(sizeof(struct unix_skb_parms_scm),
+ GFP_KERNEL);
+ if (!UNIXCB(skb).scm)
+ return -ENOMEM;
+ }
+
UNIXCB(skb).pid = get_pid(scm->pid);
UNIXCB(skb).uid = scm->creds.uid;
UNIXCB(skb).gid = scm->creds.gid;
@@ -1416,6 +1429,15 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
if (scm->fp && send_fds)
err = unix_attach_fds(scm, skb);
+ UNIXSCM(skb).procinfo = NULL;
+ if (scm->procinfo.procinfo) {
+ UNIXSCM(skb).procinfo_len = scm->procinfo.len;
+ UNIXSCM(skb).procinfo = kmemdup(scm->procinfo.procinfo,
+ scm->procinfo.len, GFP_KERNEL);
+ if (!UNIXSCM(skb).procinfo)
+ return -ENOMEM;
+ }
+
skb->destructor = unix_destruct_scm;
return err;
}
@@ -1438,6 +1460,22 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
}
}
+
+/* Include procinfo if source or destination socket
+ * asserted SOCK_PASSPROC.
+ */
+static void maybe_add_procinfo(struct sk_buff *skb, const struct socket *sock,
+ const struct sock *other, int len,
+ char *procinfo)
+{
+ if (test_bit(SOCK_PASSPROC, &sock->flags) ||
+ !other->sk_socket ||
+ test_bit(SOCK_PASSPROC, &other->sk_socket->flags)) {
+ UNIXSCM(skb).procinfo_len = len;
+ UNIXSCM(skb).procinfo = procinfo;
+ }
+}
+
/*
* Send AF_UNIX data.
*/
@@ -1459,6 +1497,8 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
struct scm_cookie tmp_scm;
int max_level;
int data_len = 0;
+ char *procinfo = NULL;
+ int procinfo_len = 0;
if (NULL == siocb->scm)
siocb->scm = &tmp_scm;
@@ -1540,6 +1580,12 @@ restart:
goto out_free;
}
+ if (test_bit(SOCK_PASSPROC, &sock->flags) ||
+ !other->sk_socket ||
+ test_bit(SOCK_PASSPROC, &other->sk_socket->flags)) {
+ procinfo_len = scm_get_current_procinfo(&procinfo);
+ }
+
unix_state_lock(other);
err = -EPERM;
if (!unix_may_send(sk, other))
@@ -1600,6 +1646,7 @@ restart:
if (sock_flag(other, SOCK_RCVTSTAMP))
__net_timestamp(skb);
maybe_add_creds(skb, sock, other);
+ maybe_add_procinfo(skb, sock, other, procinfo_len, procinfo);
skb_queue_tail(&other->sk_receive_queue, skb);
if (max_level > unix_sk(other)->recursion_level)
unix_sk(other)->recursion_level = max_level;
@@ -1638,6 +1685,8 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
bool fds_sent = false;
int max_level;
int data_len;
+ char *procinfo = NULL;
+ int procinfo_len = 0;
if (NULL == siocb->scm)
siocb->scm = &tmp_scm;
@@ -1701,6 +1750,12 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
goto out_err;
}
+ if (test_bit(SOCK_PASSPROC, &sock->flags) ||
+ !other->sk_socket ||
+ test_bit(SOCK_PASSPROC, &other->sk_socket->flags)) {
+ procinfo_len = scm_get_current_procinfo(&procinfo);
+ }
+
unix_state_lock(other);
if (sock_flag(other, SOCK_DEAD) ||
@@ -1708,6 +1763,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
goto pipe_err_free;
maybe_add_creds(skb, sock, other);
+ maybe_add_procinfo(skb, sock, other, procinfo_len, procinfo);
skb_queue_tail(&other->sk_receive_queue, skb);
if (max_level > unix_sk(other)->recursion_level)
unix_sk(other)->recursion_level = max_level;
@@ -1837,6 +1893,12 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
memset(&tmp_scm, 0, sizeof(tmp_scm));
}
scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
+ if (UNIXCB(skb).scm && UNIXSCM(skb).procinfo)
+ scm_set_procinfo(siocb->scm,
+ kmemdup(UNIXSCM(skb).procinfo,
+ UNIXSCM(skb).procinfo_len,
+ GFP_KERNEL),
+ UNIXSCM(skb).procinfo_len);
unix_set_secdata(siocb->scm, skb);
if (!(flags & MSG_PEEK)) {
@@ -2023,6 +2085,14 @@ again:
check_creds = 1;
}
+ if (UNIXCB(skb).scm && UNIXSCM(skb).procinfo) {
+ scm_set_procinfo(siocb->scm,
+ kmemdup(UNIXSCM(skb).procinfo,
+ UNIXSCM(skb).procinfo_len,
+ GFP_KERNEL),
+ UNIXSCM(skb).procinfo_len);
+ }
+
/* Copy address just once */
if (sunaddr) {
unix_copy_addr(msg, skb->sk);
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists