2013-08-27 14:41:28

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH 0/3] Send audit/procinfo/cgroup data in socket-level control message

Hi,

this patchset against net-next (applies also to linux-next) adds 3 new types
of "Socket"-level control message (SCM_AUDIT, SCM_PROCINFO and SCM_CGROUP).
This is needed by journald (logging daemon used as part of systemd ecosystem)
to get additional context together with log messages received using UNIX socket.

Jan Kaluza (3):
Send loginuid and sessionid in SCM_AUDIT
Send comm and cmdline in SCM_PROCINFO
Send cgroup_path in SCM_CGROUP

include/linux/socket.h | 9 ++++++
include/net/af_unix.h | 10 ++++++
include/net/scm.h | 67 ++++++++++++++++++++++++++++++++++++++--
net/core/scm.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++
net/unix/af_unix.c | 70 ++++++++++++++++++++++++++++++++++++++++++
5 files changed, 237 insertions(+), 2 deletions(-)

--
1.8.3.1


2013-08-27 14:41:39

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH 1/3] Send loginuid and sessionid in SCM_AUDIT

Signed-off-by: Jan Kaluza <[email protected]>
---
include/linux/socket.h | 6 ++++++
include/net/af_unix.h | 2 ++
include/net/scm.h | 28 ++++++++++++++++++++++++++--
net/unix/af_unix.c | 7 +++++++
4 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index 445ef75..505047a 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -130,6 +130,7 @@ 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_AUDIT 0x04 /* rw: struct uaudit */

struct ucred {
__u32 pid;
@@ -137,6 +138,11 @@ struct ucred {
__u32 gid;
};

+struct uaudit {
+ __u32 loginuid;
+ __u32 sessionid;
+};
+
/* Supported address families. */
#define AF_UNSPEC 0
#define AF_UNIX 1 /* Unix domain sockets */
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index a175ba4..3b9d22a 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -36,6 +36,8 @@ struct unix_skb_parms {
u32 secid; /* Security ID */
#endif
u32 consumed;
+ kuid_t loginuid;
+ unsigned int sessionid;
};

#define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb))
diff --git a/include/net/scm.h b/include/net/scm.h
index 8de2d37..e349a25 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -6,6 +6,7 @@
#include <linux/security.h>
#include <linux/pid.h>
#include <linux/nsproxy.h>
+#include <linux/audit.h>

/* Well, we should have at least one descriptor open
* to accept passed FDs 8)
@@ -18,6 +19,11 @@ struct scm_creds {
kgid_t gid;
};

+struct scm_audit {
+ kuid_t loginuid;
+ unsigned int sessionid;
+};
+
struct scm_fp_list {
short count;
short max;
@@ -28,6 +34,7 @@ struct scm_cookie {
struct pid *pid; /* Skb credentials */
struct scm_fp_list *fp; /* Passed files */
struct scm_creds creds; /* Skb credentials */
+ struct scm_audit audit; /* Skb audit */
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
@@ -58,6 +65,13 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm,
scm->creds.gid = gid;
}

+static inline void scm_set_audit(struct scm_cookie *scm,
+ kuid_t loginuid, unsigned int sessionid)
+{
+ scm->audit.loginuid = loginuid;
+ scm->audit.sessionid = sessionid;
+}
+
static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
{
put_pid(scm->pid);
@@ -77,8 +91,12 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
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 (forcecreds) {
+ scm_set_cred(scm, task_tgid(current), current_uid(),
+ current_gid());
+ scm_set_audit(scm, audit_get_loginuid(current),
+ audit_get_sessionid(current));
+ }
unix_get_peersec_dgram(sock, scm);
if (msg->msg_controllen <= 0)
return 0;
@@ -123,7 +141,13 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
.uid = from_kuid_munged(current_ns, scm->creds.uid),
.gid = from_kgid_munged(current_ns, scm->creds.gid),
};
+ struct uaudit uaudits = {
+ .loginuid = from_kuid_munged(current_ns,
+ scm->audit.loginuid),
+ .sessionid = scm->audit.sessionid,
+ };
put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
+ put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
}

scm_destroy_cred(scm);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 86de99a..c410f76 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1393,6 +1393,8 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
UNIXCB(skb).pid = get_pid(scm->pid);
UNIXCB(skb).uid = scm->creds.uid;
UNIXCB(skb).gid = scm->creds.gid;
+ UNIXCB(skb).loginuid = scm->audit.loginuid;
+ UNIXCB(skb).sessionid = scm->audit.sessionid;
UNIXCB(skb).fp = NULL;
if (scm->fp && send_fds)
err = unix_attach_fds(scm, skb);
@@ -1416,6 +1418,8 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
UNIXCB(skb).pid = get_pid(task_tgid(current));
current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
+ UNIXCB(skb).loginuid = audit_get_loginuid(current);
+ UNIXCB(skb).sessionid = audit_get_sessionid(current);
}
}

@@ -1812,6 +1816,7 @@ 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);
+ scm_set_audit(siocb->scm, UNIXCB(skb).loginuid, UNIXCB(skb).sessionid);
unix_set_secdata(siocb->scm, skb);

if (!(flags & MSG_PEEK)) {
@@ -1993,6 +1998,8 @@ again:
} else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
/* Copy credentials */
scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
+ scm_set_audit(siocb->scm, UNIXCB(skb).loginuid,
+ UNIXCB(skb).sessionid);
check_creds = 1;
}

--
1.8.3.1

2013-08-27 14:41:44

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH 3/3] Send cgroup_path in SCM_CGROUP

Signed-off-by: Jan Kaluza <[email protected]>
---
include/linux/socket.h | 1 +
include/net/af_unix.h | 1 +
include/net/scm.h | 15 +++++++++++++++
net/core/scm.c | 18 ++++++++++++++++++
net/unix/af_unix.c | 20 ++++++++++++++++++++
5 files changed, 55 insertions(+)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index 6c7ace0..621fff1 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -133,6 +133,7 @@ static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr
#define SCM_AUDIT 0x04 /* rw: struct uaudit */
#define SCM_PROCINFO 0x05 /* rw: comm + cmdline (NULL terminated
array of char *) */
+#define SCM_CGROUP 0x06 /* rw: cgroup path */

struct ucred {
__u32 pid;
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 05c7678..c49bf35 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -32,6 +32,7 @@ struct unix_skb_parms_scm {
unsigned int sessionid;
char *procinfo;
int procinfo_len;
+ char *cgroup_path;
};

struct unix_skb_parms {
diff --git a/include/net/scm.h b/include/net/scm.h
index 3346030..5398826 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -41,6 +41,7 @@ struct scm_cookie {
struct scm_creds creds; /* Skb credentials */
struct scm_audit audit; /* Skb audit */
struct scm_procinfo procinfo; /* Skb procinfo */
+ char *cgroup_path;
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
@@ -52,6 +53,7 @@ extern int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie
extern void __scm_destroy(struct scm_cookie *scm);
extern struct scm_fp_list * scm_fp_dup(struct scm_fp_list *fpl);
extern int scm_get_current_procinfo(char **procinfo);
+extern int scm_get_current_cgroup_path(char **cgroup_path);

#ifdef CONFIG_SECURITY_NETWORK
static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
@@ -86,6 +88,12 @@ static inline void scm_set_procinfo(struct scm_cookie *scm,
scm->procinfo.len = len;
}

+static inline void scm_set_cgroup_path(struct scm_cookie *scm,
+ char *cgroup_path)
+{
+ scm->cgroup_path = cgroup_path;
+}
+
static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
{
put_pid(scm->pid);
@@ -140,6 +148,9 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
security_release_secctx(secdata, seclen);
}
}
+
+ kfree(scm->cgroup_path);
+ scm->cgroup_path = NULL;
}
#else
static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
@@ -172,6 +183,10 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
put_cmsg(msg, SOL_SOCKET, SCM_PROCINFO, scm->procinfo.len,
scm->procinfo.procinfo);
+ if (scm->cgroup_path) {
+ put_cmsg(msg, SOL_SOCKET, SCM_CGROUP,
+ strlen(scm->cgroup_path), scm->cgroup_path);
+ }
}

scm_destroy_cred(scm);
diff --git a/net/core/scm.c b/net/core/scm.c
index 09ec044..2d408b9 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -404,3 +404,21 @@ out:
return res;
}
EXPORT_SYMBOL(scm_get_current_procinfo);
+
+int scm_get_current_cgroup_path(char **cgroup_path)
+{
+ int ret = 0;
+
+ *cgroup_path = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!(*cgroup_path))
+ return -ENOMEM;
+
+ ret = task_cgroup_path(current, *cgroup_path, PAGE_SIZE);
+ if (ret < 0) {
+ kfree(*cgroup_path);
+ *cgroup_path = NULL;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(scm_get_current_cgroup_path);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index ab0be13..b638083 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1344,6 +1344,7 @@ static void unix_destruct_scm(struct sk_buff *skb)
if (UNIXCB(skb).scm) {
scm.procinfo.procinfo = UNIXSCM(skb).procinfo;
scm.procinfo.len = UNIXSCM(skb).procinfo_len;
+ scm.cgroup_path = UNIXSCM(skb).cgroup_path;
}
if (UNIXCB(skb).fp)
unix_detach_fds(&scm, skb);
@@ -1420,6 +1421,14 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
return -ENOMEM;
}

+ UNIXSCM(skb).cgroup_path = NULL;
+ if (scm->cgroup_path) {
+ UNIXSCM(skb).cgroup_path = kstrdup(scm->cgroup_path,
+ GFP_KERNEL);
+ if (!UNIXSCM(skb).cgroup_path)
+ return -ENOMEM;
+ }
+
skb->destructor = unix_destruct_scm;
return err;
}
@@ -1443,6 +1452,7 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
UNIXSCM(skb).sessionid = audit_get_sessionid(current);
UNIXSCM(skb).procinfo_len = scm_get_current_procinfo(
&UNIXSCM(skb).procinfo);
+ scm_get_current_cgroup_path(&UNIXSCM(skb).cgroup_path);
}
}

@@ -1849,6 +1859,11 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
GFP_KERNEL),
UNIXSCM(skb).procinfo_len);
}
+ if (UNIXSCM(skb).cgroup_path) {
+ scm_set_cgroup_path(siocb->scm,
+ kstrdup(UNIXSCM(skb).cgroup_path,
+ GFP_KERNEL));
+ }
}
unix_set_secdata(siocb->scm, skb);

@@ -2042,6 +2057,11 @@ again:
GFP_KERNEL),
UNIXSCM(skb).procinfo_len);
}
+ if (UNIXSCM(skb).cgroup_path) {
+ scm_set_cgroup_path(siocb->scm,
+ kstrdup(UNIXSCM(skb).cgroup_path,
+ GFP_KERNEL));
+ }
}
check_creds = 1;
}
--
1.8.3.1

2013-08-27 14:42:13

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH 2/3] Send comm and cmdline in SCM_PROCINFO

Signed-off-by: Jan Kaluza <[email protected]>
---
include/linux/socket.h | 2 ++
include/net/af_unix.h | 11 +++++++--
include/net/scm.h | 24 +++++++++++++++++++
net/core/scm.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
net/unix/af_unix.c | 57 +++++++++++++++++++++++++++++++++++++------
5 files changed, 150 insertions(+), 9 deletions(-)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index 505047a..6c7ace0 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -131,6 +131,8 @@ static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr
#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */
#define SCM_SECURITY 0x03 /* rw: security label */
#define SCM_AUDIT 0x04 /* rw: struct uaudit */
+#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 3b9d22a..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,12 +43,12 @@ struct unix_skb_parms {
u32 secid; /* Security ID */
#endif
u32 consumed;
- kuid_t loginuid;
- unsigned int sessionid;
+ 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 e349a25..3346030 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -30,11 +30,17 @@ 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 */
struct scm_creds creds; /* Skb credentials */
struct scm_audit audit; /* Skb audit */
+ struct scm_procinfo procinfo; /* Skb procinfo */
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
@@ -45,6 +51,7 @@ extern void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm);
extern int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm);
extern void __scm_destroy(struct scm_cookie *scm);
extern struct scm_fp_list * scm_fp_dup(struct scm_fp_list *fpl);
+extern 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)
@@ -72,10 +79,20 @@ static inline void scm_set_audit(struct scm_cookie *scm,
scm->audit.sessionid = sessionid;
}

+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_destroy_cred(struct scm_cookie *scm)
{
put_pid(scm->pid);
scm->pid = NULL;
+ kfree(scm->procinfo.procinfo);
+ scm->procinfo.procinfo = NULL;
+ scm->procinfo.len = 0;
}

static __inline__ void scm_destroy(struct scm_cookie *scm)
@@ -88,6 +105,8 @@ 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;
@@ -96,6 +115,9 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
current_gid());
scm_set_audit(scm, audit_get_loginuid(current),
audit_get_sessionid(current));
+ 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)
@@ -148,6 +170,8 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
};
put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
+ put_cmsg(msg, SOL_SOCKET, SCM_PROCINFO, scm->procinfo.len,
+ scm->procinfo.procinfo);
}

scm_destroy_cred(scm);
diff --git a/net/core/scm.c b/net/core/scm.c
index 03795d0..09ec044 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -339,3 +339,68 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
return new_fpl;
}
EXPORT_SYMBOL(scm_fp_dup);
+
+int scm_get_current_procinfo(char **procinfo)
+{
+ int res = 0;
+ unsigned int len;
+ char *buffer = NULL;
+ struct mm_struct *mm;
+ int comm_len = strlen(current->comm);
+
+ *procinfo = NULL;
+
+ buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ mm = get_task_mm(current);
+ if (!mm)
+ goto out;
+ if (!mm->arg_end)
+ goto out_mm; /* Shh! No looking before we're done */
+
+ 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);
+ }
+ }
+
+ /* strlen(comm) + \0 + len of cmdline */
+ len = comm_len + 1 + res;
+ *procinfo = kmalloc(len, GFP_KERNEL);
+ if (!*procinfo) {
+ res = -ENOMEM;
+ goto out_mm;
+ }
+
+ memcpy(*procinfo, current->comm, comm_len + 1); /* include \0 */
+ if (res > 0)
+ memcpy(*procinfo + comm_len + 1, buffer, res);
+ res = len;
+
+out_mm:
+ mmput(mm);
+out:
+ kfree(buffer);
+ return res;
+}
+EXPORT_SYMBOL(scm_get_current_procinfo);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index c410f76..ab0be13 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1341,9 +1341,14 @@ 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);
@@ -1390,15 +1395,31 @@ 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;
- UNIXCB(skb).loginuid = scm->audit.loginuid;
- UNIXCB(skb).sessionid = scm->audit.sessionid;
+ UNIXSCM(skb).loginuid = scm->audit.loginuid;
+ UNIXSCM(skb).sessionid = scm->audit.sessionid;
UNIXCB(skb).fp = NULL;
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;
}
@@ -1418,8 +1439,10 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
UNIXCB(skb).pid = get_pid(task_tgid(current));
current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
- UNIXCB(skb).loginuid = audit_get_loginuid(current);
- UNIXCB(skb).sessionid = audit_get_sessionid(current);
+ UNIXSCM(skb).loginuid = audit_get_loginuid(current);
+ UNIXSCM(skb).sessionid = audit_get_sessionid(current);
+ UNIXSCM(skb).procinfo_len = scm_get_current_procinfo(
+ &UNIXSCM(skb).procinfo);
}
}

@@ -1816,7 +1839,17 @@ 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);
- scm_set_audit(siocb->scm, UNIXCB(skb).loginuid, UNIXCB(skb).sessionid);
+ if (UNIXCB(skb).scm) {
+ scm_set_audit(siocb->scm, UNIXSCM(skb).loginuid,
+ UNIXSCM(skb).sessionid);
+ if (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)) {
@@ -1998,8 +2031,18 @@ again:
} else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
/* Copy credentials */
scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
- scm_set_audit(siocb->scm, UNIXCB(skb).loginuid,
- UNIXCB(skb).sessionid);
+ if (UNIXCB(skb).scm) {
+ scm_set_audit(siocb->scm,
+ UNIXSCM(skb).loginuid,
+ UNIXSCM(skb).sessionid);
+ if (UNIXSCM(skb).procinfo) {
+ scm_set_procinfo(siocb->scm,
+ kmemdup(UNIXSCM(skb).procinfo,
+ UNIXSCM(skb).procinfo_len,
+ GFP_KERNEL),
+ UNIXSCM(skb).procinfo_len);
+ }
+ }
check_creds = 1;
}

--
1.8.3.1

2013-08-28 14:00:06

by Tejun Heo

[permalink] [raw]
Subject: Re: [PATCH 3/3] Send cgroup_path in SCM_CGROUP

Hello, Jan.

Can you please cc cgroup maintainers and mailing lists from
MAINTAINERS for cgroup related changes?

On Tue, Aug 27, 2013 at 04:40:00PM +0200, Jan Kaluza wrote:

Also, please describe what change is being made why on each patch.
Repeating the same description is fine but each patch descrption
should be more or less self-sufficient.

> +int scm_get_current_cgroup_path(char **cgroup_path)
> +{
> + int ret = 0;
> +
> + *cgroup_path = kmalloc(PAGE_SIZE, GFP_KERNEL);

PATH_MAX?

> + if (!(*cgroup_path))
> + return -ENOMEM;
> +
> + ret = task_cgroup_path(current, *cgroup_path, PAGE_SIZE);
> + if (ret < 0) {
> + kfree(*cgroup_path);
> + *cgroup_path = NULL;
> + }
> +
> + return ret;
> +}

Other than that, cgroup side looks fine to me. For cgroup bits,

Reviewed-by: Tejun Heo <[email protected]>

Thanks.

--
tejun

2013-08-29 14:14:27

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH v2 1/3] Send loginuid and sessionid in SCM_AUDIT

Add new SCM type called SCM_AUDIT to send loginuid and sessionuid in SCM.
This is useful for journald (systemd logging daemon) to get additional context
with each log line received using UNIX socket.

Signed-off-by: Jan Kaluza <[email protected]>
---
include/linux/socket.h | 6 ++++++
include/net/af_unix.h | 2 ++
include/net/scm.h | 28 ++++++++++++++++++++++++++--
net/unix/af_unix.c | 7 +++++++
4 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index 445ef75..505047a 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -130,6 +130,7 @@ 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_AUDIT 0x04 /* rw: struct uaudit */

struct ucred {
__u32 pid;
@@ -137,6 +138,11 @@ struct ucred {
__u32 gid;
};

+struct uaudit {
+ __u32 loginuid;
+ __u32 sessionid;
+};
+
/* Supported address families. */
#define AF_UNSPEC 0
#define AF_UNIX 1 /* Unix domain sockets */
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index a175ba4..3b9d22a 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -36,6 +36,8 @@ struct unix_skb_parms {
u32 secid; /* Security ID */
#endif
u32 consumed;
+ kuid_t loginuid;
+ unsigned int sessionid;
};

#define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb))
diff --git a/include/net/scm.h b/include/net/scm.h
index 8de2d37..e349a25 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -6,6 +6,7 @@
#include <linux/security.h>
#include <linux/pid.h>
#include <linux/nsproxy.h>
+#include <linux/audit.h>

/* Well, we should have at least one descriptor open
* to accept passed FDs 8)
@@ -18,6 +19,11 @@ struct scm_creds {
kgid_t gid;
};

+struct scm_audit {
+ kuid_t loginuid;
+ unsigned int sessionid;
+};
+
struct scm_fp_list {
short count;
short max;
@@ -28,6 +34,7 @@ struct scm_cookie {
struct pid *pid; /* Skb credentials */
struct scm_fp_list *fp; /* Passed files */
struct scm_creds creds; /* Skb credentials */
+ struct scm_audit audit; /* Skb audit */
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
@@ -58,6 +65,13 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm,
scm->creds.gid = gid;
}

+static inline void scm_set_audit(struct scm_cookie *scm,
+ kuid_t loginuid, unsigned int sessionid)
+{
+ scm->audit.loginuid = loginuid;
+ scm->audit.sessionid = sessionid;
+}
+
static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
{
put_pid(scm->pid);
@@ -77,8 +91,12 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
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 (forcecreds) {
+ scm_set_cred(scm, task_tgid(current), current_uid(),
+ current_gid());
+ scm_set_audit(scm, audit_get_loginuid(current),
+ audit_get_sessionid(current));
+ }
unix_get_peersec_dgram(sock, scm);
if (msg->msg_controllen <= 0)
return 0;
@@ -123,7 +141,13 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
.uid = from_kuid_munged(current_ns, scm->creds.uid),
.gid = from_kgid_munged(current_ns, scm->creds.gid),
};
+ struct uaudit uaudits = {
+ .loginuid = from_kuid_munged(current_ns,
+ scm->audit.loginuid),
+ .sessionid = scm->audit.sessionid,
+ };
put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
+ put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
}

scm_destroy_cred(scm);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 86de99a..c410f76 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1393,6 +1393,8 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
UNIXCB(skb).pid = get_pid(scm->pid);
UNIXCB(skb).uid = scm->creds.uid;
UNIXCB(skb).gid = scm->creds.gid;
+ UNIXCB(skb).loginuid = scm->audit.loginuid;
+ UNIXCB(skb).sessionid = scm->audit.sessionid;
UNIXCB(skb).fp = NULL;
if (scm->fp && send_fds)
err = unix_attach_fds(scm, skb);
@@ -1416,6 +1418,8 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
UNIXCB(skb).pid = get_pid(task_tgid(current));
current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
+ UNIXCB(skb).loginuid = audit_get_loginuid(current);
+ UNIXCB(skb).sessionid = audit_get_sessionid(current);
}
}

@@ -1812,6 +1816,7 @@ 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);
+ scm_set_audit(siocb->scm, UNIXCB(skb).loginuid, UNIXCB(skb).sessionid);
unix_set_secdata(siocb->scm, skb);

if (!(flags & MSG_PEEK)) {
@@ -1993,6 +1998,8 @@ again:
} else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
/* Copy credentials */
scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
+ scm_set_audit(siocb->scm, UNIXCB(skb).loginuid,
+ UNIXCB(skb).sessionid);
check_creds = 1;
}

--
1.8.3.1

2013-08-29 14:14:37

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH v2 2/3] Send comm and cmdline in SCM_PROCINFO

Add new SCM type called SCM_PROCINFO to send "comm" and "cmdline" in SCM.
This is useful for journald (systemd logging daemon) to get additional context
with each log line received using UNIX socket.

To achieve that I had to create new struct called unix_skb_parms_scm, because
unix_skb_parms was too big. This change made a patch more complex, because
this new struct has to be allocated/freed.

scm_get_current_procinfo is inspired by ./fs/proc/base.c.

Signed-off-by: Jan Kaluza <[email protected]>
---
include/linux/socket.h | 2 ++
include/net/af_unix.h | 11 +++++++--
include/net/scm.h | 24 +++++++++++++++++++
net/core/scm.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
net/unix/af_unix.c | 57 +++++++++++++++++++++++++++++++++++++------
5 files changed, 150 insertions(+), 9 deletions(-)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index 505047a..6c7ace0 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -131,6 +131,8 @@ static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr
#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */
#define SCM_SECURITY 0x03 /* rw: security label */
#define SCM_AUDIT 0x04 /* rw: struct uaudit */
+#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 3b9d22a..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,12 +43,12 @@ struct unix_skb_parms {
u32 secid; /* Security ID */
#endif
u32 consumed;
- kuid_t loginuid;
- unsigned int sessionid;
+ 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 e349a25..3346030 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -30,11 +30,17 @@ 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 */
struct scm_creds creds; /* Skb credentials */
struct scm_audit audit; /* Skb audit */
+ struct scm_procinfo procinfo; /* Skb procinfo */
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
@@ -45,6 +51,7 @@ extern void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm);
extern int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm);
extern void __scm_destroy(struct scm_cookie *scm);
extern struct scm_fp_list * scm_fp_dup(struct scm_fp_list *fpl);
+extern 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)
@@ -72,10 +79,20 @@ static inline void scm_set_audit(struct scm_cookie *scm,
scm->audit.sessionid = sessionid;
}

+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_destroy_cred(struct scm_cookie *scm)
{
put_pid(scm->pid);
scm->pid = NULL;
+ kfree(scm->procinfo.procinfo);
+ scm->procinfo.procinfo = NULL;
+ scm->procinfo.len = 0;
}

static __inline__ void scm_destroy(struct scm_cookie *scm)
@@ -88,6 +105,8 @@ 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;
@@ -96,6 +115,9 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
current_gid());
scm_set_audit(scm, audit_get_loginuid(current),
audit_get_sessionid(current));
+ 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)
@@ -148,6 +170,8 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
};
put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
+ put_cmsg(msg, SOL_SOCKET, SCM_PROCINFO, scm->procinfo.len,
+ scm->procinfo.procinfo);
}

scm_destroy_cred(scm);
diff --git a/net/core/scm.c b/net/core/scm.c
index 03795d0..09ec044 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -339,3 +339,68 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
return new_fpl;
}
EXPORT_SYMBOL(scm_fp_dup);
+
+int scm_get_current_procinfo(char **procinfo)
+{
+ int res = 0;
+ unsigned int len;
+ char *buffer = NULL;
+ struct mm_struct *mm;
+ int comm_len = strlen(current->comm);
+
+ *procinfo = NULL;
+
+ buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ mm = get_task_mm(current);
+ if (!mm)
+ goto out;
+ if (!mm->arg_end)
+ goto out_mm; /* Shh! No looking before we're done */
+
+ 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);
+ }
+ }
+
+ /* strlen(comm) + \0 + len of cmdline */
+ len = comm_len + 1 + res;
+ *procinfo = kmalloc(len, GFP_KERNEL);
+ if (!*procinfo) {
+ res = -ENOMEM;
+ goto out_mm;
+ }
+
+ memcpy(*procinfo, current->comm, comm_len + 1); /* include \0 */
+ if (res > 0)
+ memcpy(*procinfo + comm_len + 1, buffer, res);
+ res = len;
+
+out_mm:
+ mmput(mm);
+out:
+ kfree(buffer);
+ return res;
+}
+EXPORT_SYMBOL(scm_get_current_procinfo);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index c410f76..ab0be13 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1341,9 +1341,14 @@ 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);
@@ -1390,15 +1395,31 @@ 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;
- UNIXCB(skb).loginuid = scm->audit.loginuid;
- UNIXCB(skb).sessionid = scm->audit.sessionid;
+ UNIXSCM(skb).loginuid = scm->audit.loginuid;
+ UNIXSCM(skb).sessionid = scm->audit.sessionid;
UNIXCB(skb).fp = NULL;
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;
}
@@ -1418,8 +1439,10 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
UNIXCB(skb).pid = get_pid(task_tgid(current));
current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
- UNIXCB(skb).loginuid = audit_get_loginuid(current);
- UNIXCB(skb).sessionid = audit_get_sessionid(current);
+ UNIXSCM(skb).loginuid = audit_get_loginuid(current);
+ UNIXSCM(skb).sessionid = audit_get_sessionid(current);
+ UNIXSCM(skb).procinfo_len = scm_get_current_procinfo(
+ &UNIXSCM(skb).procinfo);
}
}

@@ -1816,7 +1839,17 @@ 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);
- scm_set_audit(siocb->scm, UNIXCB(skb).loginuid, UNIXCB(skb).sessionid);
+ if (UNIXCB(skb).scm) {
+ scm_set_audit(siocb->scm, UNIXSCM(skb).loginuid,
+ UNIXSCM(skb).sessionid);
+ if (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)) {
@@ -1998,8 +2031,18 @@ again:
} else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
/* Copy credentials */
scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
- scm_set_audit(siocb->scm, UNIXCB(skb).loginuid,
- UNIXCB(skb).sessionid);
+ if (UNIXCB(skb).scm) {
+ scm_set_audit(siocb->scm,
+ UNIXSCM(skb).loginuid,
+ UNIXSCM(skb).sessionid);
+ if (UNIXSCM(skb).procinfo) {
+ scm_set_procinfo(siocb->scm,
+ kmemdup(UNIXSCM(skb).procinfo,
+ UNIXSCM(skb).procinfo_len,
+ GFP_KERNEL),
+ UNIXSCM(skb).procinfo_len);
+ }
+ }
check_creds = 1;
}

--
1.8.3.1

2013-08-29 14:14:54

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH v2 3/3] Send cgroup_path in SCM_CGROUP

Add new SCM type called SCM_CGROUP to send "cgroup_path" in SCM.
This is useful for journald (systemd logging daemon) to get additional context
with each log line received using UNIX socket.

Signed-off-by: Jan Kaluza <[email protected]>
---
include/linux/socket.h | 1 +
include/net/af_unix.h | 1 +
include/net/scm.h | 15 +++++++++++++++
net/core/scm.c | 18 ++++++++++++++++++
net/unix/af_unix.c | 20 ++++++++++++++++++++
5 files changed, 55 insertions(+)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index 6c7ace0..621fff1 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -133,6 +133,7 @@ static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr
#define SCM_AUDIT 0x04 /* rw: struct uaudit */
#define SCM_PROCINFO 0x05 /* rw: comm + cmdline (NULL terminated
array of char *) */
+#define SCM_CGROUP 0x06 /* rw: cgroup path */

struct ucred {
__u32 pid;
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 05c7678..c49bf35 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -32,6 +32,7 @@ struct unix_skb_parms_scm {
unsigned int sessionid;
char *procinfo;
int procinfo_len;
+ char *cgroup_path;
};

struct unix_skb_parms {
diff --git a/include/net/scm.h b/include/net/scm.h
index 3346030..5398826 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -41,6 +41,7 @@ struct scm_cookie {
struct scm_creds creds; /* Skb credentials */
struct scm_audit audit; /* Skb audit */
struct scm_procinfo procinfo; /* Skb procinfo */
+ char *cgroup_path;
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
@@ -52,6 +53,7 @@ extern int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie
extern void __scm_destroy(struct scm_cookie *scm);
extern struct scm_fp_list * scm_fp_dup(struct scm_fp_list *fpl);
extern int scm_get_current_procinfo(char **procinfo);
+extern int scm_get_current_cgroup_path(char **cgroup_path);

#ifdef CONFIG_SECURITY_NETWORK
static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
@@ -86,6 +88,12 @@ static inline void scm_set_procinfo(struct scm_cookie *scm,
scm->procinfo.len = len;
}

+static inline void scm_set_cgroup_path(struct scm_cookie *scm,
+ char *cgroup_path)
+{
+ scm->cgroup_path = cgroup_path;
+}
+
static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
{
put_pid(scm->pid);
@@ -140,6 +148,9 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
security_release_secctx(secdata, seclen);
}
}
+
+ kfree(scm->cgroup_path);
+ scm->cgroup_path = NULL;
}
#else
static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
@@ -172,6 +183,10 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
put_cmsg(msg, SOL_SOCKET, SCM_PROCINFO, scm->procinfo.len,
scm->procinfo.procinfo);
+ if (scm->cgroup_path) {
+ put_cmsg(msg, SOL_SOCKET, SCM_CGROUP,
+ strlen(scm->cgroup_path), scm->cgroup_path);
+ }
}

scm_destroy_cred(scm);
diff --git a/net/core/scm.c b/net/core/scm.c
index 09ec044..2d408b9 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -404,3 +404,21 @@ out:
return res;
}
EXPORT_SYMBOL(scm_get_current_procinfo);
+
+int scm_get_current_cgroup_path(char **cgroup_path)
+{
+ int ret = 0;
+
+ *cgroup_path = kmalloc(PATH_MAX, GFP_KERNEL);
+ if (!(*cgroup_path))
+ return -ENOMEM;
+
+ ret = task_cgroup_path(current, *cgroup_path, PATH_MAX);
+ if (ret < 0) {
+ kfree(*cgroup_path);
+ *cgroup_path = NULL;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(scm_get_current_cgroup_path);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index ab0be13..b638083 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1344,6 +1344,7 @@ static void unix_destruct_scm(struct sk_buff *skb)
if (UNIXCB(skb).scm) {
scm.procinfo.procinfo = UNIXSCM(skb).procinfo;
scm.procinfo.len = UNIXSCM(skb).procinfo_len;
+ scm.cgroup_path = UNIXSCM(skb).cgroup_path;
}
if (UNIXCB(skb).fp)
unix_detach_fds(&scm, skb);
@@ -1420,6 +1421,14 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
return -ENOMEM;
}

+ UNIXSCM(skb).cgroup_path = NULL;
+ if (scm->cgroup_path) {
+ UNIXSCM(skb).cgroup_path = kstrdup(scm->cgroup_path,
+ GFP_KERNEL);
+ if (!UNIXSCM(skb).cgroup_path)
+ return -ENOMEM;
+ }
+
skb->destructor = unix_destruct_scm;
return err;
}
@@ -1443,6 +1452,7 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
UNIXSCM(skb).sessionid = audit_get_sessionid(current);
UNIXSCM(skb).procinfo_len = scm_get_current_procinfo(
&UNIXSCM(skb).procinfo);
+ scm_get_current_cgroup_path(&UNIXSCM(skb).cgroup_path);
}
}

@@ -1849,6 +1859,11 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
GFP_KERNEL),
UNIXSCM(skb).procinfo_len);
}
+ if (UNIXSCM(skb).cgroup_path) {
+ scm_set_cgroup_path(siocb->scm,
+ kstrdup(UNIXSCM(skb).cgroup_path,
+ GFP_KERNEL));
+ }
}
unix_set_secdata(siocb->scm, skb);

@@ -2042,6 +2057,11 @@ again:
GFP_KERNEL),
UNIXSCM(skb).procinfo_len);
}
+ if (UNIXSCM(skb).cgroup_path) {
+ scm_set_cgroup_path(siocb->scm,
+ kstrdup(UNIXSCM(skb).cgroup_path,
+ GFP_KERNEL));
+ }
}
check_creds = 1;
}
--
1.8.3.1

2013-08-29 14:15:29

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH v2 0/3] Send audit/procinfo/cgroup data in socket-level control message

Hi,

this patchset against net-next (applies also to linux-next) adds 3 new types
of "Socket"-level control message (SCM_AUDIT, SCM_PROCINFO and SCM_CGROUP).
This is needed by journald (logging daemon used as part of systemd ecosystem)
to get additional context together with log messages received using UNIX socket.

Changes in v2:
- use PATH_MAX instead of PAGE_SIZE in SCM_CGROUP patch
- describe each patch individually

Jan Kaluza (3):
Send loginuid and sessionid in SCM_AUDIT
Send comm and cmdline in SCM_PROCINFO
Send cgroup_path in SCM_CGROUP

include/linux/socket.h | 9 ++++++
include/net/af_unix.h | 10 ++++++
include/net/scm.h | 67 ++++++++++++++++++++++++++++++++++++++--
net/core/scm.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++
net/unix/af_unix.c | 70 ++++++++++++++++++++++++++++++++++++++++++
5 files changed, 237 insertions(+), 2 deletions(-)

--
1.8.3.1

2013-09-02 17:17:23

by Kay Sievers

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] Send cgroup_path in SCM_CGROUP

On Thu, Aug 29, 2013 at 4:13 PM, Jan Kaluza <[email protected]> wrote:
> Add new SCM type called SCM_CGROUP to send "cgroup_path" in SCM.
> This is useful for journald (systemd logging daemon) to get additional context
> with each log line received using UNIX socket.
>
> Signed-off-by: Jan Kaluza <[email protected]>

In many cases it's generally more useful to explain *why* something is
done, not *where* it is used. It makes it easier for people to match
the described problem to their own use-cases, where it possibly occurs
too. The problem this patch solves is very generic and not so much
specific to logging or the journal. Maybe something like this:

"Server-like processes in many cases need credentials and other
metadata of the peer, to decide if the calling process is allowed to
request a specific action, or the server just wants to log away this
type of information for auditing tasks.

The current practice to retrieve such process metadata is to look that
information up in procfs with the $PID received over SCM_CREDENTIALS.
This is sufficient for long-running tasks, but introduces a race which
cannot be worked around for short-living processes; the calling
process and all the information in /proc/$PID/ is gone before the
receiver of the socket message can look it up.

This introduces a new SCM type called SCM_CGROUP to allow the direct
attaching of "cgroup_path" to SCM, which is significantly more
efficient and will reliably avoid the race with the round-trip over
procfs."

Thanks,
Kay

2013-09-04 06:15:18

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH v3 0/3] Send audit/procinfo/cgroup data in socket-level control message

Hi,

this patchset against net-next (applies also to linux-next) adds 3 new types
of "Socket"-level control message (SCM_AUDIT, SCM_PROCINFO and SCM_CGROUP).

Server-like processes in many cases need credentials and other
metadata of the peer, to decide if the calling process is allowed to
request a specific action, or the server just wants to log away this
type of information for auditing tasks.

The current practice to retrieve such process metadata is to look that
information up in procfs with the $PID received over SCM_CREDENTIALS.
This is sufficient for long-running tasks, but introduces a race which
cannot be worked around for short-living processes; the calling
process and all the information in /proc/$PID/ is gone before the
receiver of the socket message can look it up.

Changes introduced in this patchset can also increase performance
of such server-like processes, because current way of opening and
parsing /proc/$PID/* files is much more expensive than receiving these
metadata using SCM.

Changes in v3:
- Better description of patches (Thanks to Kay Sievers)

Changes in v2:
- use PATH_MAX instead of PAGE_SIZE in SCM_CGROUP patch
- describe each patch individually

Jan Kaluza (3):
Send loginuid and sessionid in SCM_AUDIT
Send comm and cmdline in SCM_PROCINFO
Send cgroup_path in SCM_CGROUP

include/linux/socket.h | 9 ++++++
include/net/af_unix.h | 10 ++++++
include/net/scm.h | 67 ++++++++++++++++++++++++++++++++++++++--
net/core/scm.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++
net/unix/af_unix.c | 70 ++++++++++++++++++++++++++++++++++++++++++
5 files changed, 237 insertions(+), 2 deletions(-)

--
1.8.3.1

2013-09-04 06:15:33

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH v3 1/3] Send loginuid and sessionid in SCM_AUDIT

Server-like processes in many cases need credentials and other
metadata of the peer, to decide if the calling process is allowed to
request a specific action, or the server just wants to log away this
type of information for auditing tasks.

The current practice to retrieve such process metadata is to look that
information up in procfs with the $PID received over SCM_CREDENTIALS.
This is sufficient for long-running tasks, but introduces a race which
cannot be worked around for short-living processes; the calling
process and all the information in /proc/$PID/ is gone before the
receiver of the socket message can look it up.

This introduces a new SCM type called SCM_AUDIT to allow the direct
attaching of "loginuid" and "sessionid" to SCM, which is significantly more
efficient and will reliably avoid the race with the round-trip over
procfs.

Signed-off-by: Jan Kaluza <[email protected]>
---
include/linux/socket.h | 6 ++++++
include/net/af_unix.h | 2 ++
include/net/scm.h | 28 ++++++++++++++++++++++++++--
net/unix/af_unix.c | 7 +++++++
4 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index 445ef75..505047a 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -130,6 +130,7 @@ 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_AUDIT 0x04 /* rw: struct uaudit */

struct ucred {
__u32 pid;
@@ -137,6 +138,11 @@ struct ucred {
__u32 gid;
};

+struct uaudit {
+ __u32 loginuid;
+ __u32 sessionid;
+};
+
/* Supported address families. */
#define AF_UNSPEC 0
#define AF_UNIX 1 /* Unix domain sockets */
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index a175ba4..3b9d22a 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -36,6 +36,8 @@ struct unix_skb_parms {
u32 secid; /* Security ID */
#endif
u32 consumed;
+ kuid_t loginuid;
+ unsigned int sessionid;
};

#define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb))
diff --git a/include/net/scm.h b/include/net/scm.h
index 8de2d37..e349a25 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -6,6 +6,7 @@
#include <linux/security.h>
#include <linux/pid.h>
#include <linux/nsproxy.h>
+#include <linux/audit.h>

/* Well, we should have at least one descriptor open
* to accept passed FDs 8)
@@ -18,6 +19,11 @@ struct scm_creds {
kgid_t gid;
};

+struct scm_audit {
+ kuid_t loginuid;
+ unsigned int sessionid;
+};
+
struct scm_fp_list {
short count;
short max;
@@ -28,6 +34,7 @@ struct scm_cookie {
struct pid *pid; /* Skb credentials */
struct scm_fp_list *fp; /* Passed files */
struct scm_creds creds; /* Skb credentials */
+ struct scm_audit audit; /* Skb audit */
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
@@ -58,6 +65,13 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm,
scm->creds.gid = gid;
}

+static inline void scm_set_audit(struct scm_cookie *scm,
+ kuid_t loginuid, unsigned int sessionid)
+{
+ scm->audit.loginuid = loginuid;
+ scm->audit.sessionid = sessionid;
+}
+
static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
{
put_pid(scm->pid);
@@ -77,8 +91,12 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
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 (forcecreds) {
+ scm_set_cred(scm, task_tgid(current), current_uid(),
+ current_gid());
+ scm_set_audit(scm, audit_get_loginuid(current),
+ audit_get_sessionid(current));
+ }
unix_get_peersec_dgram(sock, scm);
if (msg->msg_controllen <= 0)
return 0;
@@ -123,7 +141,13 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
.uid = from_kuid_munged(current_ns, scm->creds.uid),
.gid = from_kgid_munged(current_ns, scm->creds.gid),
};
+ struct uaudit uaudits = {
+ .loginuid = from_kuid_munged(current_ns,
+ scm->audit.loginuid),
+ .sessionid = scm->audit.sessionid,
+ };
put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
+ put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
}

scm_destroy_cred(scm);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 86de99a..c410f76 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1393,6 +1393,8 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
UNIXCB(skb).pid = get_pid(scm->pid);
UNIXCB(skb).uid = scm->creds.uid;
UNIXCB(skb).gid = scm->creds.gid;
+ UNIXCB(skb).loginuid = scm->audit.loginuid;
+ UNIXCB(skb).sessionid = scm->audit.sessionid;
UNIXCB(skb).fp = NULL;
if (scm->fp && send_fds)
err = unix_attach_fds(scm, skb);
@@ -1416,6 +1418,8 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
UNIXCB(skb).pid = get_pid(task_tgid(current));
current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
+ UNIXCB(skb).loginuid = audit_get_loginuid(current);
+ UNIXCB(skb).sessionid = audit_get_sessionid(current);
}
}

@@ -1812,6 +1816,7 @@ 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);
+ scm_set_audit(siocb->scm, UNIXCB(skb).loginuid, UNIXCB(skb).sessionid);
unix_set_secdata(siocb->scm, skb);

if (!(flags & MSG_PEEK)) {
@@ -1993,6 +1998,8 @@ again:
} else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
/* Copy credentials */
scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
+ scm_set_audit(siocb->scm, UNIXCB(skb).loginuid,
+ UNIXCB(skb).sessionid);
check_creds = 1;
}

--
1.8.3.1

2013-09-04 06:15:44

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH v3 3/3] Send cgroup_path in SCM_CGROUP

Server-like processes in many cases need credentials and other
metadata of the peer, to decide if the calling process is allowed to
request a specific action, or the server just wants to log away this
type of information for auditing tasks.

The current practice to retrieve such process metadata is to look that
information up in procfs with the $PID received over SCM_CREDENTIALS.
This is sufficient for long-running tasks, but introduces a race which
cannot be worked around for short-living processes; the calling
process and all the information in /proc/$PID/ is gone before the
receiver of the socket message can look it up.

This introduces a new SCM type called SCM_CGROUP to allow the direct
attaching of "cgroup_path" to SCM, which is significantly more
efficient and will reliably avoid the race with the round-trip over
procfs.

Signed-off-by: Jan Kaluza <[email protected]>
---
include/linux/socket.h | 1 +
include/net/af_unix.h | 1 +
include/net/scm.h | 15 +++++++++++++++
net/core/scm.c | 18 ++++++++++++++++++
net/unix/af_unix.c | 20 ++++++++++++++++++++
5 files changed, 55 insertions(+)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index 6c7ace0..621fff1 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -133,6 +133,7 @@ static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr
#define SCM_AUDIT 0x04 /* rw: struct uaudit */
#define SCM_PROCINFO 0x05 /* rw: comm + cmdline (NULL terminated
array of char *) */
+#define SCM_CGROUP 0x06 /* rw: cgroup path */

struct ucred {
__u32 pid;
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 05c7678..c49bf35 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -32,6 +32,7 @@ struct unix_skb_parms_scm {
unsigned int sessionid;
char *procinfo;
int procinfo_len;
+ char *cgroup_path;
};

struct unix_skb_parms {
diff --git a/include/net/scm.h b/include/net/scm.h
index 3346030..5398826 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -41,6 +41,7 @@ struct scm_cookie {
struct scm_creds creds; /* Skb credentials */
struct scm_audit audit; /* Skb audit */
struct scm_procinfo procinfo; /* Skb procinfo */
+ char *cgroup_path;
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
@@ -52,6 +53,7 @@ extern int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie
extern void __scm_destroy(struct scm_cookie *scm);
extern struct scm_fp_list * scm_fp_dup(struct scm_fp_list *fpl);
extern int scm_get_current_procinfo(char **procinfo);
+extern int scm_get_current_cgroup_path(char **cgroup_path);

#ifdef CONFIG_SECURITY_NETWORK
static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
@@ -86,6 +88,12 @@ static inline void scm_set_procinfo(struct scm_cookie *scm,
scm->procinfo.len = len;
}

+static inline void scm_set_cgroup_path(struct scm_cookie *scm,
+ char *cgroup_path)
+{
+ scm->cgroup_path = cgroup_path;
+}
+
static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
{
put_pid(scm->pid);
@@ -140,6 +148,9 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
security_release_secctx(secdata, seclen);
}
}
+
+ kfree(scm->cgroup_path);
+ scm->cgroup_path = NULL;
}
#else
static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
@@ -172,6 +183,10 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
put_cmsg(msg, SOL_SOCKET, SCM_PROCINFO, scm->procinfo.len,
scm->procinfo.procinfo);
+ if (scm->cgroup_path) {
+ put_cmsg(msg, SOL_SOCKET, SCM_CGROUP,
+ strlen(scm->cgroup_path), scm->cgroup_path);
+ }
}

scm_destroy_cred(scm);
diff --git a/net/core/scm.c b/net/core/scm.c
index 09ec044..2d408b9 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -404,3 +404,21 @@ out:
return res;
}
EXPORT_SYMBOL(scm_get_current_procinfo);
+
+int scm_get_current_cgroup_path(char **cgroup_path)
+{
+ int ret = 0;
+
+ *cgroup_path = kmalloc(PATH_MAX, GFP_KERNEL);
+ if (!(*cgroup_path))
+ return -ENOMEM;
+
+ ret = task_cgroup_path(current, *cgroup_path, PATH_MAX);
+ if (ret < 0) {
+ kfree(*cgroup_path);
+ *cgroup_path = NULL;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(scm_get_current_cgroup_path);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index ab0be13..b638083 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1344,6 +1344,7 @@ static void unix_destruct_scm(struct sk_buff *skb)
if (UNIXCB(skb).scm) {
scm.procinfo.procinfo = UNIXSCM(skb).procinfo;
scm.procinfo.len = UNIXSCM(skb).procinfo_len;
+ scm.cgroup_path = UNIXSCM(skb).cgroup_path;
}
if (UNIXCB(skb).fp)
unix_detach_fds(&scm, skb);
@@ -1420,6 +1421,14 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
return -ENOMEM;
}

+ UNIXSCM(skb).cgroup_path = NULL;
+ if (scm->cgroup_path) {
+ UNIXSCM(skb).cgroup_path = kstrdup(scm->cgroup_path,
+ GFP_KERNEL);
+ if (!UNIXSCM(skb).cgroup_path)
+ return -ENOMEM;
+ }
+
skb->destructor = unix_destruct_scm;
return err;
}
@@ -1443,6 +1452,7 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
UNIXSCM(skb).sessionid = audit_get_sessionid(current);
UNIXSCM(skb).procinfo_len = scm_get_current_procinfo(
&UNIXSCM(skb).procinfo);
+ scm_get_current_cgroup_path(&UNIXSCM(skb).cgroup_path);
}
}

@@ -1849,6 +1859,11 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
GFP_KERNEL),
UNIXSCM(skb).procinfo_len);
}
+ if (UNIXSCM(skb).cgroup_path) {
+ scm_set_cgroup_path(siocb->scm,
+ kstrdup(UNIXSCM(skb).cgroup_path,
+ GFP_KERNEL));
+ }
}
unix_set_secdata(siocb->scm, skb);

@@ -2042,6 +2057,11 @@ again:
GFP_KERNEL),
UNIXSCM(skb).procinfo_len);
}
+ if (UNIXSCM(skb).cgroup_path) {
+ scm_set_cgroup_path(siocb->scm,
+ kstrdup(UNIXSCM(skb).cgroup_path,
+ GFP_KERNEL));
+ }
}
check_creds = 1;
}
--
1.8.3.1

2013-09-04 06:15:37

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH v3 2/3] Send comm and cmdline in SCM_PROCINFO

Server-like processes in many cases need credentials and other
metadata of the peer, to decide if the calling process is allowed to
request a specific action, or the server just wants to log away this
type of information for auditing tasks.

The current practice to retrieve such process metadata is to look that
information up in procfs with the $PID received over SCM_CREDENTIALS.
This is sufficient for long-running tasks, but introduces a race which
cannot be worked around for short-living processes; the calling
process and all the information in /proc/$PID/ is gone before the
receiver of the socket message can look it up.

This introduces a new SCM type called SCM_PROCINFO to allow the direct
attaching of "comm" and "cmdline" to SCM, which is significantly more
efficient and will reliably avoid the race with the round-trip over
procfs.

To achieve that, new struct called unix_skb_parms_scm had to be created,
because otherwise unix_skb_parms would be too big.

scm_get_current_procinfo is inspired by ./fs/proc/base.c.

Signed-off-by: Jan Kaluza <[email protected]>
---
include/linux/socket.h | 2 ++
include/net/af_unix.h | 11 +++++++--
include/net/scm.h | 24 +++++++++++++++++++
net/core/scm.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
net/unix/af_unix.c | 57 +++++++++++++++++++++++++++++++++++++------
5 files changed, 150 insertions(+), 9 deletions(-)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index 505047a..6c7ace0 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -131,6 +131,8 @@ static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr
#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */
#define SCM_SECURITY 0x03 /* rw: security label */
#define SCM_AUDIT 0x04 /* rw: struct uaudit */
+#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 3b9d22a..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,12 +43,12 @@ struct unix_skb_parms {
u32 secid; /* Security ID */
#endif
u32 consumed;
- kuid_t loginuid;
- unsigned int sessionid;
+ 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 e349a25..3346030 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -30,11 +30,17 @@ 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 */
struct scm_creds creds; /* Skb credentials */
struct scm_audit audit; /* Skb audit */
+ struct scm_procinfo procinfo; /* Skb procinfo */
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
@@ -45,6 +51,7 @@ extern void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm);
extern int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm);
extern void __scm_destroy(struct scm_cookie *scm);
extern struct scm_fp_list * scm_fp_dup(struct scm_fp_list *fpl);
+extern 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)
@@ -72,10 +79,20 @@ static inline void scm_set_audit(struct scm_cookie *scm,
scm->audit.sessionid = sessionid;
}

+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_destroy_cred(struct scm_cookie *scm)
{
put_pid(scm->pid);
scm->pid = NULL;
+ kfree(scm->procinfo.procinfo);
+ scm->procinfo.procinfo = NULL;
+ scm->procinfo.len = 0;
}

static __inline__ void scm_destroy(struct scm_cookie *scm)
@@ -88,6 +105,8 @@ 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;
@@ -96,6 +115,9 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
current_gid());
scm_set_audit(scm, audit_get_loginuid(current),
audit_get_sessionid(current));
+ 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)
@@ -148,6 +170,8 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
};
put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
+ put_cmsg(msg, SOL_SOCKET, SCM_PROCINFO, scm->procinfo.len,
+ scm->procinfo.procinfo);
}

scm_destroy_cred(scm);
diff --git a/net/core/scm.c b/net/core/scm.c
index 03795d0..09ec044 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -339,3 +339,68 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
return new_fpl;
}
EXPORT_SYMBOL(scm_fp_dup);
+
+int scm_get_current_procinfo(char **procinfo)
+{
+ int res = 0;
+ unsigned int len;
+ char *buffer = NULL;
+ struct mm_struct *mm;
+ int comm_len = strlen(current->comm);
+
+ *procinfo = NULL;
+
+ buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ mm = get_task_mm(current);
+ if (!mm)
+ goto out;
+ if (!mm->arg_end)
+ goto out_mm; /* Shh! No looking before we're done */
+
+ 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);
+ }
+ }
+
+ /* strlen(comm) + \0 + len of cmdline */
+ len = comm_len + 1 + res;
+ *procinfo = kmalloc(len, GFP_KERNEL);
+ if (!*procinfo) {
+ res = -ENOMEM;
+ goto out_mm;
+ }
+
+ memcpy(*procinfo, current->comm, comm_len + 1); /* include \0 */
+ if (res > 0)
+ memcpy(*procinfo + comm_len + 1, buffer, res);
+ res = len;
+
+out_mm:
+ mmput(mm);
+out:
+ kfree(buffer);
+ return res;
+}
+EXPORT_SYMBOL(scm_get_current_procinfo);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index c410f76..ab0be13 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1341,9 +1341,14 @@ 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);
@@ -1390,15 +1395,31 @@ 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;
- UNIXCB(skb).loginuid = scm->audit.loginuid;
- UNIXCB(skb).sessionid = scm->audit.sessionid;
+ UNIXSCM(skb).loginuid = scm->audit.loginuid;
+ UNIXSCM(skb).sessionid = scm->audit.sessionid;
UNIXCB(skb).fp = NULL;
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;
}
@@ -1418,8 +1439,10 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
UNIXCB(skb).pid = get_pid(task_tgid(current));
current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
- UNIXCB(skb).loginuid = audit_get_loginuid(current);
- UNIXCB(skb).sessionid = audit_get_sessionid(current);
+ UNIXSCM(skb).loginuid = audit_get_loginuid(current);
+ UNIXSCM(skb).sessionid = audit_get_sessionid(current);
+ UNIXSCM(skb).procinfo_len = scm_get_current_procinfo(
+ &UNIXSCM(skb).procinfo);
}
}

@@ -1816,7 +1839,17 @@ 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);
- scm_set_audit(siocb->scm, UNIXCB(skb).loginuid, UNIXCB(skb).sessionid);
+ if (UNIXCB(skb).scm) {
+ scm_set_audit(siocb->scm, UNIXSCM(skb).loginuid,
+ UNIXSCM(skb).sessionid);
+ if (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)) {
@@ -1998,8 +2031,18 @@ again:
} else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
/* Copy credentials */
scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
- scm_set_audit(siocb->scm, UNIXCB(skb).loginuid,
- UNIXCB(skb).sessionid);
+ if (UNIXCB(skb).scm) {
+ scm_set_audit(siocb->scm,
+ UNIXSCM(skb).loginuid,
+ UNIXSCM(skb).sessionid);
+ if (UNIXSCM(skb).procinfo) {
+ scm_set_procinfo(siocb->scm,
+ kmemdup(UNIXSCM(skb).procinfo,
+ UNIXSCM(skb).procinfo_len,
+ GFP_KERNEL),
+ UNIXSCM(skb).procinfo_len);
+ }
+ }
check_creds = 1;
}

--
1.8.3.1

2013-09-04 07:22:31

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH v3 1/3] Send loginuid and sessionid in SCM_AUDIT

Jan Kaluza <[email protected]> writes:

> Server-like processes in many cases need credentials and other
> metadata of the peer, to decide if the calling process is allowed to
> request a specific action, or the server just wants to log away this
> type of information for auditing tasks.
>
> The current practice to retrieve such process metadata is to look that
> information up in procfs with the $PID received over SCM_CREDENTIALS.
> This is sufficient for long-running tasks, but introduces a race which
> cannot be worked around for short-living processes; the calling
> process and all the information in /proc/$PID/ is gone before the
> receiver of the socket message can look it up.
>
> This introduces a new SCM type called SCM_AUDIT to allow the direct
> attaching of "loginuid" and "sessionid" to SCM, which is significantly more
> efficient and will reliably avoid the race with the round-trip over
> procfs.

Unless I am misreading something this patch will break the build if
CONFIG_AUDITSYSCALL is not defined.

Eric


> Signed-off-by: Jan Kaluza <[email protected]>
> ---
> include/linux/socket.h | 6 ++++++
> include/net/af_unix.h | 2 ++
> include/net/scm.h | 28 ++++++++++++++++++++++++++--
> net/unix/af_unix.c | 7 +++++++
> 4 files changed, 41 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/socket.h b/include/linux/socket.h
> index 445ef75..505047a 100644
> --- a/include/linux/socket.h
> +++ b/include/linux/socket.h
> @@ -130,6 +130,7 @@ 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_AUDIT 0x04 /* rw: struct uaudit */
>
> struct ucred {
> __u32 pid;
> @@ -137,6 +138,11 @@ struct ucred {
> __u32 gid;
> };
>
> +struct uaudit {
> + __u32 loginuid;
> + __u32 sessionid;
> +};
> +
> /* Supported address families. */
> #define AF_UNSPEC 0
> #define AF_UNIX 1 /* Unix domain sockets */
> diff --git a/include/net/af_unix.h b/include/net/af_unix.h
> index a175ba4..3b9d22a 100644
> --- a/include/net/af_unix.h
> +++ b/include/net/af_unix.h
> @@ -36,6 +36,8 @@ struct unix_skb_parms {
> u32 secid; /* Security ID */
> #endif
> u32 consumed;
> + kuid_t loginuid;
> + unsigned int sessionid;
> };
>
> #define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb))
> diff --git a/include/net/scm.h b/include/net/scm.h
> index 8de2d37..e349a25 100644
> --- a/include/net/scm.h
> +++ b/include/net/scm.h
> @@ -6,6 +6,7 @@
> #include <linux/security.h>
> #include <linux/pid.h>
> #include <linux/nsproxy.h>
> +#include <linux/audit.h>
>
> /* Well, we should have at least one descriptor open
> * to accept passed FDs 8)
> @@ -18,6 +19,11 @@ struct scm_creds {
> kgid_t gid;
> };
>
> +struct scm_audit {
> + kuid_t loginuid;
> + unsigned int sessionid;
> +};
> +
> struct scm_fp_list {
> short count;
> short max;
> @@ -28,6 +34,7 @@ struct scm_cookie {
> struct pid *pid; /* Skb credentials */
> struct scm_fp_list *fp; /* Passed files */
> struct scm_creds creds; /* Skb credentials */
> + struct scm_audit audit; /* Skb audit */
> #ifdef CONFIG_SECURITY_NETWORK
> u32 secid; /* Passed security ID */
> #endif
> @@ -58,6 +65,13 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm,
> scm->creds.gid = gid;
> }
>
> +static inline void scm_set_audit(struct scm_cookie *scm,
> + kuid_t loginuid, unsigned int sessionid)
> +{
> + scm->audit.loginuid = loginuid;
> + scm->audit.sessionid = sessionid;
> +}
> +
> static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
> {
> put_pid(scm->pid);
> @@ -77,8 +91,12 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
> 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 (forcecreds) {
> + scm_set_cred(scm, task_tgid(current), current_uid(),
> + current_gid());
> + scm_set_audit(scm, audit_get_loginuid(current),
> + audit_get_sessionid(current));
> + }
> unix_get_peersec_dgram(sock, scm);
> if (msg->msg_controllen <= 0)
> return 0;
> @@ -123,7 +141,13 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
> .uid = from_kuid_munged(current_ns, scm->creds.uid),
> .gid = from_kgid_munged(current_ns, scm->creds.gid),
> };
> + struct uaudit uaudits = {
> + .loginuid = from_kuid_munged(current_ns,
> + scm->audit.loginuid),
> + .sessionid = scm->audit.sessionid,
> + };
> put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
> + put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
> }
>
> scm_destroy_cred(scm);
> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index 86de99a..c410f76 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -1393,6 +1393,8 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
> UNIXCB(skb).pid = get_pid(scm->pid);
> UNIXCB(skb).uid = scm->creds.uid;
> UNIXCB(skb).gid = scm->creds.gid;
> + UNIXCB(skb).loginuid = scm->audit.loginuid;
> + UNIXCB(skb).sessionid = scm->audit.sessionid;
> UNIXCB(skb).fp = NULL;
> if (scm->fp && send_fds)
> err = unix_attach_fds(scm, skb);
> @@ -1416,6 +1418,8 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
> test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
> UNIXCB(skb).pid = get_pid(task_tgid(current));
> current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
> + UNIXCB(skb).loginuid = audit_get_loginuid(current);
> + UNIXCB(skb).sessionid = audit_get_sessionid(current);
> }
> }
>
> @@ -1812,6 +1816,7 @@ 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);
> + scm_set_audit(siocb->scm, UNIXCB(skb).loginuid, UNIXCB(skb).sessionid);
> unix_set_secdata(siocb->scm, skb);
>
> if (!(flags & MSG_PEEK)) {
> @@ -1993,6 +1998,8 @@ again:
> } else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
> /* Copy credentials */
> scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
> + scm_set_audit(siocb->scm, UNIXCB(skb).loginuid,
> + UNIXCB(skb).sessionid);
> check_creds = 1;
> }

2013-09-04 07:42:42

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Send audit/procinfo/cgroup data in socket-level control message

Jan Kaluza <[email protected]> writes:

> Hi,
>
> this patchset against net-next (applies also to linux-next) adds 3 new types
> of "Socket"-level control message (SCM_AUDIT, SCM_PROCINFO and SCM_CGROUP).
>
> Server-like processes in many cases need credentials and other
> metadata of the peer, to decide if the calling process is allowed to
> request a specific action, or the server just wants to log away this
> type of information for auditing tasks.
>
> The current practice to retrieve such process metadata is to look that
> information up in procfs with the $PID received over SCM_CREDENTIALS.
> This is sufficient for long-running tasks, but introduces a race which
> cannot be worked around for short-living processes; the calling
> process and all the information in /proc/$PID/ is gone before the
> receiver of the socket message can look it up.

> Changes introduced in this patchset can also increase performance
> of such server-like processes, because current way of opening and
> parsing /proc/$PID/* files is much more expensive than receiving these
> metadata using SCM.

Can I just say ick, blech, barf, gag.

You don't require this information to be passed. You are asking people
to suport a lot of new code for the forseeable future. The only advantage
appears to be for short lived racy processes that don't even bother to
make certain their message was acknowleged before exiting.

You sent this during the merge window which is the time for code
integration and testing not new code.

By my count you have overflowed cb in struct sk_buff and are stomping on
_skb_refdest.

If you are going to go crazy and pass things is there a reason you do
not add a patch to pass the bsd SCM_CREDS? That information seems more
relevant in a security context and for making security decisions than
about half the information you are passing.

Eric

2013-09-04 09:07:38

by Jan Kaluža

[permalink] [raw]
Subject: Re: [PATCH v3 1/3] Send loginuid and sessionid in SCM_AUDIT

On 09/04/2013 09:22 AM, Eric W. Biederman wrote:
> Jan Kaluza <[email protected]> writes:
>
>> Server-like processes in many cases need credentials and other
>> metadata of the peer, to decide if the calling process is allowed to
>> request a specific action, or the server just wants to log away this
>> type of information for auditing tasks.
>>
>> The current practice to retrieve such process metadata is to look that
>> information up in procfs with the $PID received over SCM_CREDENTIALS.
>> This is sufficient for long-running tasks, but introduces a race which
>> cannot be worked around for short-living processes; the calling
>> process and all the information in /proc/$PID/ is gone before the
>> receiver of the socket message can look it up.
>>
>> This introduces a new SCM type called SCM_AUDIT to allow the direct
>> attaching of "loginuid" and "sessionid" to SCM, which is significantly more
>> efficient and will reliably avoid the race with the round-trip over
>> procfs.
>
> Unless I am misreading something this patch will break the build if
> CONFIG_AUDITSYSCALL is not defined.

It does build. In this case, audit_get_loginuid returns INVALID_UID and
audit_get_sessionid returns -1.

Jan Kaluza

> Eric
>
>
>> Signed-off-by: Jan Kaluza <[email protected]>
>> ---
>> include/linux/socket.h | 6 ++++++
>> include/net/af_unix.h | 2 ++
>> include/net/scm.h | 28 ++++++++++++++++++++++++++--
>> net/unix/af_unix.c | 7 +++++++
>> 4 files changed, 41 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/socket.h b/include/linux/socket.h
>> index 445ef75..505047a 100644
>> --- a/include/linux/socket.h
>> +++ b/include/linux/socket.h
>> @@ -130,6 +130,7 @@ 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_AUDIT 0x04 /* rw: struct uaudit */
>>
>> struct ucred {
>> __u32 pid;
>> @@ -137,6 +138,11 @@ struct ucred {
>> __u32 gid;
>> };
>>
>> +struct uaudit {
>> + __u32 loginuid;
>> + __u32 sessionid;
>> +};
>> +
>> /* Supported address families. */
>> #define AF_UNSPEC 0
>> #define AF_UNIX 1 /* Unix domain sockets */
>> diff --git a/include/net/af_unix.h b/include/net/af_unix.h
>> index a175ba4..3b9d22a 100644
>> --- a/include/net/af_unix.h
>> +++ b/include/net/af_unix.h
>> @@ -36,6 +36,8 @@ struct unix_skb_parms {
>> u32 secid; /* Security ID */
>> #endif
>> u32 consumed;
>> + kuid_t loginuid;
>> + unsigned int sessionid;
>> };
>>
>> #define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb))
>> diff --git a/include/net/scm.h b/include/net/scm.h
>> index 8de2d37..e349a25 100644
>> --- a/include/net/scm.h
>> +++ b/include/net/scm.h
>> @@ -6,6 +6,7 @@
>> #include <linux/security.h>
>> #include <linux/pid.h>
>> #include <linux/nsproxy.h>
>> +#include <linux/audit.h>
>>
>> /* Well, we should have at least one descriptor open
>> * to accept passed FDs 8)
>> @@ -18,6 +19,11 @@ struct scm_creds {
>> kgid_t gid;
>> };
>>
>> +struct scm_audit {
>> + kuid_t loginuid;
>> + unsigned int sessionid;
>> +};
>> +
>> struct scm_fp_list {
>> short count;
>> short max;
>> @@ -28,6 +34,7 @@ struct scm_cookie {
>> struct pid *pid; /* Skb credentials */
>> struct scm_fp_list *fp; /* Passed files */
>> struct scm_creds creds; /* Skb credentials */
>> + struct scm_audit audit; /* Skb audit */
>> #ifdef CONFIG_SECURITY_NETWORK
>> u32 secid; /* Passed security ID */
>> #endif
>> @@ -58,6 +65,13 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm,
>> scm->creds.gid = gid;
>> }
>>
>> +static inline void scm_set_audit(struct scm_cookie *scm,
>> + kuid_t loginuid, unsigned int sessionid)
>> +{
>> + scm->audit.loginuid = loginuid;
>> + scm->audit.sessionid = sessionid;
>> +}
>> +
>> static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
>> {
>> put_pid(scm->pid);
>> @@ -77,8 +91,12 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
>> 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 (forcecreds) {
>> + scm_set_cred(scm, task_tgid(current), current_uid(),
>> + current_gid());
>> + scm_set_audit(scm, audit_get_loginuid(current),
>> + audit_get_sessionid(current));
>> + }
>> unix_get_peersec_dgram(sock, scm);
>> if (msg->msg_controllen <= 0)
>> return 0;
>> @@ -123,7 +141,13 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
>> .uid = from_kuid_munged(current_ns, scm->creds.uid),
>> .gid = from_kgid_munged(current_ns, scm->creds.gid),
>> };
>> + struct uaudit uaudits = {
>> + .loginuid = from_kuid_munged(current_ns,
>> + scm->audit.loginuid),
>> + .sessionid = scm->audit.sessionid,
>> + };
>> put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
>> + put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
>> }
>>
>> scm_destroy_cred(scm);
>> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
>> index 86de99a..c410f76 100644
>> --- a/net/unix/af_unix.c
>> +++ b/net/unix/af_unix.c
>> @@ -1393,6 +1393,8 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
>> UNIXCB(skb).pid = get_pid(scm->pid);
>> UNIXCB(skb).uid = scm->creds.uid;
>> UNIXCB(skb).gid = scm->creds.gid;
>> + UNIXCB(skb).loginuid = scm->audit.loginuid;
>> + UNIXCB(skb).sessionid = scm->audit.sessionid;
>> UNIXCB(skb).fp = NULL;
>> if (scm->fp && send_fds)
>> err = unix_attach_fds(scm, skb);
>> @@ -1416,6 +1418,8 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
>> test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
>> UNIXCB(skb).pid = get_pid(task_tgid(current));
>> current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
>> + UNIXCB(skb).loginuid = audit_get_loginuid(current);
>> + UNIXCB(skb).sessionid = audit_get_sessionid(current);
>> }
>> }
>>
>> @@ -1812,6 +1816,7 @@ 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);
>> + scm_set_audit(siocb->scm, UNIXCB(skb).loginuid, UNIXCB(skb).sessionid);
>> unix_set_secdata(siocb->scm, skb);
>>
>> if (!(flags & MSG_PEEK)) {
>> @@ -1993,6 +1998,8 @@ again:
>> } else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
>> /* Copy credentials */
>> scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
>> + scm_set_audit(siocb->scm, UNIXCB(skb).loginuid,
>> + UNIXCB(skb).sessionid);
>> check_creds = 1;
>> }

2013-09-04 14:45:22

by Tejun Heo

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Send audit/procinfo/cgroup data in socket-level control message

Hello, Eric.

On Wed, Sep 04, 2013 at 12:42:26AM -0700, Eric W. Biederman wrote:
> Can I just say ick, blech, barf, gag.

Gees, an awesome way to start the conversation. If your gag response
is hyper-sensitive, go see a frigging doctor. It's annoying because
you tend to go over the top while getting things wrong often enough.
Even if you don't agree, you don't have to start things this way.

> You don't require this information to be passed. You are asking people
> to suport a lot of new code for the forseeable future. The only advantage
> appears to be for short lived racy processes that don't even bother to
> make certain their message was acknowleged before exiting.

While I'm not sure whether this is *the* right appraoch, how is "we
have some pretty visible race conditions but it's probably okay" an
answer? This affects auditing and logging directly and you're saying
"ah well, the program wasn't running long enough"?

> You sent this during the merge window which is the time for code
> integration and testing not new code.

What are you talking about? It is *okay* to send new patches during
merge window even if it's headed for the next merge window. Sending
patches to maintainers doesn't mean "this should go in right now".
Maintainers are of course free to delay response or ask for
pinging/resending later but it's just stupid to accuse patch
submitters for sending patches. What the hell is that?

> By my count you have overflowed cb in struct sk_buff and are stomping on
> _skb_refdest.
>
> If you are going to go crazy and pass things is there a reason you do
> not add a patch to pass the bsd SCM_CREDS? That information seems more
> relevant in a security context and for making security decisions than
> about half the information you are passing.

You could have lost all the other paragraphs and just responded with
the above. I don't think we can extend an existing struct but maybe
how information is packed can be adjusted. That said, the proposed
split makes sense to me.

Thanks.

--
tejun

2013-09-04 14:58:43

by Richard Guy Briggs

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Send audit/procinfo/cgroup data in socket-level control message

On Wed, Sep 04, 2013 at 12:42:26AM -0700, Eric W. Biederman wrote:
> Jan Kaluza <[email protected]> writes:
> > Hi,
> >
> > this patchset against net-next (applies also to linux-next) adds 3 new types
> > of "Socket"-level control message (SCM_AUDIT, SCM_PROCINFO and SCM_CGROUP).
> >
> > Server-like processes in many cases need credentials and other
> > metadata of the peer, to decide if the calling process is allowed to
> > request a specific action, or the server just wants to log away this
> > type of information for auditing tasks.
> >
> > The current practice to retrieve such process metadata is to look that
> > information up in procfs with the $PID received over SCM_CREDENTIALS.
> > This is sufficient for long-running tasks, but introduces a race which
> > cannot be worked around for short-living processes; the calling
> > process and all the information in /proc/$PID/ is gone before the
> > receiver of the socket message can look it up.
>
> > Changes introduced in this patchset can also increase performance
> > of such server-like processes, because current way of opening and
> > parsing /proc/$PID/* files is much more expensive than receiving these
> > metadata using SCM.
>
> Can I just say ick, blech, barf, gag.

/me hands ebiederman an air sickness bag.

> You don't require this information to be passed. You are asking people
> to suport a lot of new code for the forseeable future. The only advantage
> appears to be for short lived racy processes that don't even bother to
> make certain their message was acknowleged before exiting.
>
> You sent this during the merge window which is the time for code
> integration and testing not new code.

This is an RFC. How is this important?

> By my count you have overflowed cb in struct sk_buff and are stomping on
> _skb_refdest.

For patch1/3 I count 56/48, then for patch3 I get 48/48. Jan, you might
do the conversion to a pointer in patch1/3 to avoid bisect breakage.

> If you are going to go crazy and pass things is there a reason you do
> not add a patch to pass the bsd SCM_CREDS? That information seems more
> relevant in a security context and for making security decisions than
> about half the information you are passing.
>
> Eric

- RGB

--
Richard Guy Briggs <[email protected]>
Senior Software Engineer
Kernel Security
AMER ENG Base Operating Systems
Remote, Ottawa, Canada
Voice: +1.647.777.2635
Internal: (81) 32635
Alt: +1.613.693.0684x3545

2013-09-04 15:04:12

by Jan Kaluža

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Send audit/procinfo/cgroup data in socket-level control message

On 09/04/2013 04:58 PM, Richard Guy Briggs wrote:
> On Wed, Sep 04, 2013 at 12:42:26AM -0700, Eric W. Biederman wrote:
>> Jan Kaluza <[email protected]> writes:
>>> Hi,
>>>
>>> this patchset against net-next (applies also to linux-next) adds 3 new types
>>> of "Socket"-level control message (SCM_AUDIT, SCM_PROCINFO and SCM_CGROUP).
>>>
>>> Server-like processes in many cases need credentials and other
>>> metadata of the peer, to decide if the calling process is allowed to
>>> request a specific action, or the server just wants to log away this
>>> type of information for auditing tasks.
>>>
>>> The current practice to retrieve such process metadata is to look that
>>> information up in procfs with the $PID received over SCM_CREDENTIALS.
>>> This is sufficient for long-running tasks, but introduces a race which
>>> cannot be worked around for short-living processes; the calling
>>> process and all the information in /proc/$PID/ is gone before the
>>> receiver of the socket message can look it up.
>>
>>> Changes introduced in this patchset can also increase performance
>>> of such server-like processes, because current way of opening and
>>> parsing /proc/$PID/* files is much more expensive than receiving these
>>> metadata using SCM.
>>
>> Can I just say ick, blech, barf, gag.
>
> /me hands ebiederman an air sickness bag.
>
>> You don't require this information to be passed. You are asking people
>> to suport a lot of new code for the forseeable future. The only advantage
>> appears to be for short lived racy processes that don't even bother to
>> make certain their message was acknowleged before exiting.
>>
>> You sent this during the merge window which is the time for code
>> integration and testing not new code.
>
> This is an RFC. How is this important?
>
>> By my count you have overflowed cb in struct sk_buff and are stomping on
>> _skb_refdest.
>
> For patch1/3 I count 56/48, then for patch3 I get 48/48. Jan, you might
> do the conversion to a pointer in patch1/3 to avoid bisect breakage.

Yes, this is valid point. I will do the conversion in patch1. Thanks all
for reviewing and pointing that out.

Jan Kaluza

>> If you are going to go crazy and pass things is there a reason you do
>> not add a patch to pass the bsd SCM_CREDS? That information seems more
>> relevant in a security context and for making security decisions than
>> about half the information you are passing.
>>
>> Eric
>
> - RGB
>
> --
> Richard Guy Briggs <[email protected]>
> Senior Software Engineer
> Kernel Security
> AMER ENG Base Operating Systems
> Remote, Ottawa, Canada
> Voice: +1.647.777.2635
> Internal: (81) 32635
> Alt: +1.613.693.0684x3545
>

2013-09-04 15:20:35

by Richard Guy Briggs

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Send audit/procinfo/cgroup data in socket-level control message

On Wed, Sep 04, 2013 at 10:58:30AM -0400, Richard Guy Briggs wrote:
> On Wed, Sep 04, 2013 at 12:42:26AM -0700, Eric W. Biederman wrote:
> > Jan Kaluza <[email protected]> writes:
> > > this patchset against net-next (applies also to linux-next) adds 3 new types
> > > of "Socket"-level control message (SCM_AUDIT, SCM_PROCINFO and SCM_CGROUP).
>
> > By my count you have overflowed cb in struct sk_buff and are stomping on
> > _skb_refdest.
>
> For patch1/3 I count 56/48, then for patch3 I get 48/48. Jan, you might
> do the conversion to a pointer in patch1/3 to avoid bisect breakage.

Wait, that __aligned(8) is for cb[48], not for the contents.

For patch1/3 I count 28/48 on 32-bit, 36/48 on 64-bit (or would that be
56 by default on 64-bit arches without aligned specified?), then for
patch3 I get 24/48 on 32 and 40/48 on 64 (or again 48/48 by default?).

> > Eric
>
> - RGB

- RGB

--
Richard Guy Briggs <[email protected]>
Senior Software Engineer
Kernel Security
AMER ENG Base Operating Systems
Remote, Ottawa, Canada
Voice: +1.647.777.2635
Internal: (81) 32635
Alt: +1.613.693.0684x3545

2013-09-04 15:30:30

by Eric Dumazet

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Send audit/procinfo/cgroup data in socket-level control message

On Wed, 2013-09-04 at 11:20 -0400, Richard Guy Briggs wrote:
> On Wed, Sep 04, 2013 at 10:58:30AM -0400, Richard Guy Briggs wrote:
> > On Wed, Sep 04, 2013 at 12:42:26AM -0700, Eric W. Biederman wrote:
> > > Jan Kaluza <[email protected]> writes:
> > > > this patchset against net-next (applies also to linux-next) adds 3 new types
> > > > of "Socket"-level control message (SCM_AUDIT, SCM_PROCINFO and SCM_CGROUP).
> >
> > > By my count you have overflowed cb in struct sk_buff and are stomping on
> > > _skb_refdest.
> >
> > For patch1/3 I count 56/48, then for patch3 I get 48/48. Jan, you might
> > do the conversion to a pointer in patch1/3 to avoid bisect breakage.
>
> Wait, that __aligned(8) is for cb[48], not for the contents.
>
> For patch1/3 I count 28/48 on 32-bit, 36/48 on 64-bit (or would that be
> 56 by default on 64-bit arches without aligned specified?), then for
> patch3 I get 24/48 on 32 and 40/48 on 64 (or again 48/48 by default?).

Do not count, just add this :

diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 86de99a..5b61320 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1329,6 +1329,7 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
{
int i;

+ BUILD_BUG_ON(sizeof(struct unix_skb_parms) > sizeof(skb->cb));
scm->fp = UNIXCB(skb).fp;
UNIXCB(skb).fp = NULL;


2013-09-04 15:40:35

by Jan Kaluža

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Send audit/procinfo/cgroup data in socket-level control message

On 09/04/2013 05:30 PM, Eric Dumazet wrote:
> On Wed, 2013-09-04 at 11:20 -0400, Richard Guy Briggs wrote:
>> On Wed, Sep 04, 2013 at 10:58:30AM -0400, Richard Guy Briggs wrote:
>>> On Wed, Sep 04, 2013 at 12:42:26AM -0700, Eric W. Biederman wrote:
>>>> Jan Kaluza <[email protected]> writes:
>>>>> this patchset against net-next (applies also to linux-next) adds 3 new types
>>>>> of "Socket"-level control message (SCM_AUDIT, SCM_PROCINFO and SCM_CGROUP).
>>>
>>>> By my count you have overflowed cb in struct sk_buff and are stomping on
>>>> _skb_refdest.
>>>
>>> For patch1/3 I count 56/48, then for patch3 I get 48/48. Jan, you might
>>> do the conversion to a pointer in patch1/3 to avoid bisect breakage.
>>
>> Wait, that __aligned(8) is for cb[48], not for the contents.
>>
>> For patch1/3 I count 28/48 on 32-bit, 36/48 on 64-bit (or would that be
>> 56 by default on 64-bit arches without aligned specified?), then for
>> patch3 I get 24/48 on 32 and 40/48 on 64 (or again 48/48 by default?).
>
> Do not count, just add this :
>
> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index 86de99a..5b61320 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -1329,6 +1329,7 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
> {
> int i;
>
> + BUILD_BUG_ON(sizeof(struct unix_skb_parms) > sizeof(skb->cb));
> scm->fp = UNIXCB(skb).fp;
> UNIXCB(skb).fp = NULL;
>

That's already in af_unix.c:

BUILD_BUG_ON(sizeof(struct unix_skb_parms) > FIELD_SIZEOF(struct
sk_buff, cb));

This test is passing for me even with only patch1/3 applied when
building 64bit kernel.

Jan Kaluza

2013-09-09 06:52:53

by Eric W. Biederman

[permalink] [raw]
Subject: Re: [PATCH 2/3] Send comm and cmdline in SCM_PROCINFO

Jan Kaluza <[email protected]> writes:

Nacked-by: "Eric W. Biederman" <[email protected]>

Whatever the benefits of the other pieces of information sending the
process command line is absolutely wrong. It is a just a random string
from user space and there is absolutely no benefit in sending it in a
kernel verified way. The process can just as easily pass the
information in userspace directly.

Furthermore the implementation of scm_get_current_procinfo is so far
from idiomatic for reading information about the current process that I
think it is fair to call it broken.

Eric

2014-01-13 08:03:22

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH v4 0/3] Send audit/procinfo/cgroup data in socket-level control message

Hi,

this patchset against net-next (applies also to linux-next) adds 3 new types
of "Socket"-level control message (SCM_AUDIT, SCM_PROCINFO and SCM_CGROUP).

Server-like processes in many cases need credentials and other
metadata of the peer, to decide if the calling process is allowed to
request a specific action, or the server just wants to log away this
type of information for auditing tasks.

The current practice to retrieve such process metadata is to look that
information up in procfs with the $PID received over SCM_CREDENTIALS.
This is sufficient for long-running tasks, but introduces a race which
cannot be worked around for short-living processes; the calling
process and all the information in /proc/$PID/ is gone before the
receiver of the socket message can look it up.

Changes introduced in this patchset can also increase performance
of such server-like processes, because current way of opening and
parsing /proc/$PID/* files is much more expensive than receiving these
metadata using SCM.

Changes in v4:
- Rebased to work with the latest net-next tree

Changes in v3:
- Better description of patches (Thanks to Kay Sievers)

Changes in v2:
- use PATH_MAX instead of PAGE_SIZE in SCM_CGROUP patch
- describe each patch individually

Jan Kaluza (3):
Send loginuid and sessionid in SCM_AUDIT
Send comm and cmdline in SCM_PROCINFO
Send cgroup_path in SCM_CGROUP

include/linux/socket.h | 9 ++++++
include/net/af_unix.h | 10 ++++++
include/net/scm.h | 67 ++++++++++++++++++++++++++++++++++++++--
net/core/scm.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++
net/unix/af_unix.c | 70 ++++++++++++++++++++++++++++++++++++++++++
5 files changed, 237 insertions(+), 2 deletions(-)

--
1.8.3.1

2014-01-13 08:03:27

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH v4 1/3] Send loginuid and sessionid in SCM_AUDIT

Server-like processes in many cases need credentials and other
metadata of the peer, to decide if the calling process is allowed to
request a specific action, or the server just wants to log away this
type of information for auditing tasks.

The current practice to retrieve such process metadata is to look that
information up in procfs with the $PID received over SCM_CREDENTIALS.
This is sufficient for long-running tasks, but introduces a race which
cannot be worked around for short-living processes; the calling
process and all the information in /proc/$PID/ is gone before the
receiver of the socket message can look it up.

This introduces a new SCM type called SCM_AUDIT to allow the direct
attaching of "loginuid" and "sessionid" to SCM, which is significantly more
efficient and will reliably avoid the race with the round-trip over
procfs.

Signed-off-by: Jan Kaluza <[email protected]>
---
include/linux/socket.h | 6 ++++++
include/net/af_unix.h | 2 ++
include/net/scm.h | 28 ++++++++++++++++++++++++++--
net/unix/af_unix.c | 7 +++++++
4 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index 5d488a6..eeac565 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -130,6 +130,7 @@ 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_AUDIT 0x04 /* rw: struct uaudit */

struct ucred {
__u32 pid;
@@ -137,6 +138,11 @@ struct ucred {
__u32 gid;
};

+struct uaudit {
+ __u32 loginuid;
+ __u32 sessionid;
+};
+
/* Supported address families. */
#define AF_UNSPEC 0
#define AF_UNIX 1 /* Unix domain sockets */
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index a175ba4..3b9d22a 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -36,6 +36,8 @@ struct unix_skb_parms {
u32 secid; /* Security ID */
#endif
u32 consumed;
+ kuid_t loginuid;
+ unsigned int sessionid;
};

#define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb))
diff --git a/include/net/scm.h b/include/net/scm.h
index 262532d..67de64f 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -6,6 +6,7 @@
#include <linux/security.h>
#include <linux/pid.h>
#include <linux/nsproxy.h>
+#include <linux/audit.h>

/* Well, we should have at least one descriptor open
* to accept passed FDs 8)
@@ -18,6 +19,11 @@ struct scm_creds {
kgid_t gid;
};

+struct scm_audit {
+ kuid_t loginuid;
+ unsigned int sessionid;
+};
+
struct scm_fp_list {
short count;
short max;
@@ -28,6 +34,7 @@ struct scm_cookie {
struct pid *pid; /* Skb credentials */
struct scm_fp_list *fp; /* Passed files */
struct scm_creds creds; /* Skb credentials */
+ struct scm_audit audit; /* Skb audit */
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
@@ -58,6 +65,13 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm,
scm->creds.gid = gid;
}

+static inline void scm_set_audit(struct scm_cookie *scm,
+ kuid_t loginuid, unsigned int sessionid)
+{
+ scm->audit.loginuid = loginuid;
+ scm->audit.sessionid = sessionid;
+}
+
static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
{
put_pid(scm->pid);
@@ -77,8 +91,12 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
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 (forcecreds) {
+ scm_set_cred(scm, task_tgid(current), current_uid(),
+ current_gid());
+ scm_set_audit(scm, audit_get_loginuid(current),
+ audit_get_sessionid(current));
+ }
unix_get_peersec_dgram(sock, scm);
if (msg->msg_controllen <= 0)
return 0;
@@ -123,7 +141,13 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
.uid = from_kuid_munged(current_ns, scm->creds.uid),
.gid = from_kgid_munged(current_ns, scm->creds.gid),
};
+ struct uaudit uaudits = {
+ .loginuid = from_kuid_munged(current_ns,
+ scm->audit.loginuid),
+ .sessionid = scm->audit.sessionid,
+ };
put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
+ put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
}

scm_destroy_cred(scm);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 800ca61..bc02a25 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1413,6 +1413,8 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
UNIXCB(skb).pid = get_pid(scm->pid);
UNIXCB(skb).uid = scm->creds.uid;
UNIXCB(skb).gid = scm->creds.gid;
+ UNIXCB(skb).loginuid = scm->audit.loginuid;
+ UNIXCB(skb).sessionid = scm->audit.sessionid;
UNIXCB(skb).fp = NULL;
if (scm->fp && send_fds)
err = unix_attach_fds(scm, skb);
@@ -1436,6 +1438,8 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
UNIXCB(skb).pid = get_pid(task_tgid(current));
current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
+ UNIXCB(skb).loginuid = audit_get_loginuid(current);
+ UNIXCB(skb).sessionid = audit_get_sessionid(current);
}
}

@@ -1829,6 +1833,7 @@ 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);
+ scm_set_audit(siocb->scm, UNIXCB(skb).loginuid, UNIXCB(skb).sessionid);
unix_set_secdata(siocb->scm, skb);

if (!(flags & MSG_PEEK)) {
@@ -2008,6 +2013,8 @@ again:
} else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
/* Copy credentials */
scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
+ scm_set_audit(siocb->scm, UNIXCB(skb).loginuid,
+ UNIXCB(skb).sessionid);
check_creds = 1;
}

--
1.8.3.1

2014-01-13 08:03:36

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH v4 3/3] Send cgroup_path in SCM_CGROUP

Server-like processes in many cases need credentials and other
metadata of the peer, to decide if the calling process is allowed to
request a specific action, or the server just wants to log away this
type of information for auditing tasks.

The current practice to retrieve such process metadata is to look that
information up in procfs with the $PID received over SCM_CREDENTIALS.
This is sufficient for long-running tasks, but introduces a race which
cannot be worked around for short-living processes; the calling
process and all the information in /proc/$PID/ is gone before the
receiver of the socket message can look it up.

This introduces a new SCM type called SCM_CGROUP to allow the direct
attaching of "cgroup_path" to SCM, which is significantly more
efficient and will reliably avoid the race with the round-trip over
procfs.

Signed-off-by: Jan Kaluza <[email protected]>
---
include/linux/socket.h | 1 +
include/net/af_unix.h | 1 +
include/net/scm.h | 15 +++++++++++++++
net/core/scm.c | 18 ++++++++++++++++++
net/unix/af_unix.c | 20 ++++++++++++++++++++
5 files changed, 55 insertions(+)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index 5a41f35..b015ed4 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -133,6 +133,7 @@ static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr
#define SCM_AUDIT 0x04 /* rw: struct uaudit */
#define SCM_PROCINFO 0x05 /* rw: comm + cmdline (NULL terminated
array of char *) */
+#define SCM_CGROUP 0x06 /* rw: cgroup path */

struct ucred {
__u32 pid;
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 05c7678..c49bf35 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -32,6 +32,7 @@ struct unix_skb_parms_scm {
unsigned int sessionid;
char *procinfo;
int procinfo_len;
+ char *cgroup_path;
};

struct unix_skb_parms {
diff --git a/include/net/scm.h b/include/net/scm.h
index f084e19..359048d 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -41,6 +41,7 @@ struct scm_cookie {
struct scm_creds creds; /* Skb credentials */
struct scm_audit audit; /* Skb audit */
struct scm_procinfo procinfo; /* Skb procinfo */
+ char *cgroup_path;
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
@@ -52,6 +53,7 @@ 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);
+int scm_get_current_cgroup_path(char **cgroup_path);

#ifdef CONFIG_SECURITY_NETWORK
static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm)
@@ -86,6 +88,12 @@ static inline void scm_set_procinfo(struct scm_cookie *scm,
scm->procinfo.len = len;
}

+static inline void scm_set_cgroup_path(struct scm_cookie *scm,
+ char *cgroup_path)
+{
+ scm->cgroup_path = cgroup_path;
+}
+
static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
{
put_pid(scm->pid);
@@ -140,6 +148,9 @@ static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct sc
security_release_secctx(secdata, seclen);
}
}
+
+ kfree(scm->cgroup_path);
+ scm->cgroup_path = NULL;
}
#else
static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
@@ -172,6 +183,10 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
put_cmsg(msg, SOL_SOCKET, SCM_PROCINFO, scm->procinfo.len,
scm->procinfo.procinfo);
+ if (scm->cgroup_path) {
+ put_cmsg(msg, SOL_SOCKET, SCM_CGROUP,
+ strlen(scm->cgroup_path), scm->cgroup_path);
+ }
}

scm_destroy_cred(scm);
diff --git a/net/core/scm.c b/net/core/scm.c
index 4accb07..78e206a 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -404,3 +404,21 @@ out:
return res;
}
EXPORT_SYMBOL(scm_get_current_procinfo);
+
+int scm_get_current_cgroup_path(char **cgroup_path)
+{
+ int ret = 0;
+
+ *cgroup_path = kmalloc(PATH_MAX, GFP_KERNEL);
+ if (!(*cgroup_path))
+ return -ENOMEM;
+
+ ret = task_cgroup_path(current, *cgroup_path, PATH_MAX);
+ if (ret < 0) {
+ kfree(*cgroup_path);
+ *cgroup_path = NULL;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(scm_get_current_cgroup_path);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 35ab97f0..b04f55e 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1364,6 +1364,7 @@ static void unix_destruct_scm(struct sk_buff *skb)
if (UNIXCB(skb).scm) {
scm.procinfo.procinfo = UNIXSCM(skb).procinfo;
scm.procinfo.len = UNIXSCM(skb).procinfo_len;
+ scm.cgroup_path = UNIXSCM(skb).cgroup_path;
}
if (UNIXCB(skb).fp)
unix_detach_fds(&scm, skb);
@@ -1440,6 +1441,14 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
return -ENOMEM;
}

+ UNIXSCM(skb).cgroup_path = NULL;
+ if (scm->cgroup_path) {
+ UNIXSCM(skb).cgroup_path = kstrdup(scm->cgroup_path,
+ GFP_KERNEL);
+ if (!UNIXSCM(skb).cgroup_path)
+ return -ENOMEM;
+ }
+
skb->destructor = unix_destruct_scm;
return err;
}
@@ -1463,6 +1472,7 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
UNIXSCM(skb).sessionid = audit_get_sessionid(current);
UNIXSCM(skb).procinfo_len = scm_get_current_procinfo(
&UNIXSCM(skb).procinfo);
+ scm_get_current_cgroup_path(&UNIXSCM(skb).cgroup_path);
}
}

@@ -1866,6 +1876,11 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
GFP_KERNEL),
UNIXSCM(skb).procinfo_len);
}
+ if (UNIXSCM(skb).cgroup_path) {
+ scm_set_cgroup_path(siocb->scm,
+ kstrdup(UNIXSCM(skb).cgroup_path,
+ GFP_KERNEL));
+ }
}
unix_set_secdata(siocb->scm, skb);

@@ -2057,6 +2072,11 @@ again:
GFP_KERNEL),
UNIXSCM(skb).procinfo_len);
}
+ if (UNIXSCM(skb).cgroup_path) {
+ scm_set_cgroup_path(siocb->scm,
+ kstrdup(UNIXSCM(skb).cgroup_path,
+ GFP_KERNEL));
+ }
}
check_creds = 1;
}
--
1.8.3.1

2014-01-13 08:03:57

by Jan Kaluža

[permalink] [raw]
Subject: [PATCH v4 2/3] Send comm and cmdline in SCM_PROCINFO

Server-like processes in many cases need credentials and other
metadata of the peer, to decide if the calling process is allowed to
request a specific action, or the server just wants to log away this
type of information for auditing tasks.

The current practice to retrieve such process metadata is to look that
information up in procfs with the $PID received over SCM_CREDENTIALS.
This is sufficient for long-running tasks, but introduces a race which
cannot be worked around for short-living processes; the calling
process and all the information in /proc/$PID/ is gone before the
receiver of the socket message can look it up.

This introduces a new SCM type called SCM_PROCINFO to allow the direct
attaching of "comm" and "cmdline" to SCM, which is significantly more
efficient and will reliably avoid the race with the round-trip over
procfs.

To achieve that, new struct called unix_skb_parms_scm had to be created,
because otherwise unix_skb_parms would be too big.

scm_get_current_procinfo is inspired by ./fs/proc/base.c.

Signed-off-by: Jan Kaluza <[email protected]>
---
include/linux/socket.h | 2 ++
include/net/af_unix.h | 11 +++++++--
include/net/scm.h | 24 +++++++++++++++++++
net/core/scm.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
net/unix/af_unix.c | 57 +++++++++++++++++++++++++++++++++++++------
5 files changed, 150 insertions(+), 9 deletions(-)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index eeac565..5a41f35 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -131,6 +131,8 @@ static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr
#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */
#define SCM_SECURITY 0x03 /* rw: security label */
#define SCM_AUDIT 0x04 /* rw: struct uaudit */
+#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 3b9d22a..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,12 +43,12 @@ struct unix_skb_parms {
u32 secid; /* Security ID */
#endif
u32 consumed;
- kuid_t loginuid;
- unsigned int sessionid;
+ 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 67de64f..f084e19 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -30,11 +30,17 @@ 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 */
struct scm_creds creds; /* Skb credentials */
struct scm_audit audit; /* Skb audit */
+ struct scm_procinfo procinfo; /* Skb procinfo */
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */
#endif
@@ -45,6 +51,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)
@@ -72,10 +79,20 @@ static inline void scm_set_audit(struct scm_cookie *scm,
scm->audit.sessionid = sessionid;
}

+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_destroy_cred(struct scm_cookie *scm)
{
put_pid(scm->pid);
scm->pid = NULL;
+ kfree(scm->procinfo.procinfo);
+ scm->procinfo.procinfo = NULL;
+ scm->procinfo.len = 0;
}

static __inline__ void scm_destroy(struct scm_cookie *scm)
@@ -88,6 +105,8 @@ 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;
@@ -96,6 +115,9 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
current_gid());
scm_set_audit(scm, audit_get_loginuid(current),
audit_get_sessionid(current));
+ 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)
@@ -148,6 +170,8 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
};
put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
+ put_cmsg(msg, SOL_SOCKET, SCM_PROCINFO, scm->procinfo.len,
+ scm->procinfo.procinfo);
}

scm_destroy_cred(scm);
diff --git a/net/core/scm.c b/net/core/scm.c
index b442e7e..4accb07 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -339,3 +339,68 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
return new_fpl;
}
EXPORT_SYMBOL(scm_fp_dup);
+
+int scm_get_current_procinfo(char **procinfo)
+{
+ int res = 0;
+ unsigned int len;
+ char *buffer = NULL;
+ struct mm_struct *mm;
+ int comm_len = strlen(current->comm);
+
+ *procinfo = NULL;
+
+ buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ mm = get_task_mm(current);
+ if (!mm)
+ goto out;
+ if (!mm->arg_end)
+ goto out_mm; /* Shh! No looking before we're done */
+
+ 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);
+ }
+ }
+
+ /* strlen(comm) + \0 + len of cmdline */
+ len = comm_len + 1 + res;
+ *procinfo = kmalloc(len, GFP_KERNEL);
+ if (!*procinfo) {
+ res = -ENOMEM;
+ goto out_mm;
+ }
+
+ memcpy(*procinfo, current->comm, comm_len + 1); /* include \0 */
+ if (res > 0)
+ memcpy(*procinfo + comm_len + 1, buffer, res);
+ res = len;
+
+out_mm:
+ mmput(mm);
+out:
+ kfree(buffer);
+ return res;
+}
+EXPORT_SYMBOL(scm_get_current_procinfo);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index bc02a25..35ab97f0 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1361,9 +1361,14 @@ 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);
@@ -1410,15 +1415,31 @@ 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;
- UNIXCB(skb).loginuid = scm->audit.loginuid;
- UNIXCB(skb).sessionid = scm->audit.sessionid;
+ UNIXSCM(skb).loginuid = scm->audit.loginuid;
+ UNIXSCM(skb).sessionid = scm->audit.sessionid;
UNIXCB(skb).fp = NULL;
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,8 +1459,10 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
UNIXCB(skb).pid = get_pid(task_tgid(current));
current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
- UNIXCB(skb).loginuid = audit_get_loginuid(current);
- UNIXCB(skb).sessionid = audit_get_sessionid(current);
+ UNIXSCM(skb).loginuid = audit_get_loginuid(current);
+ UNIXSCM(skb).sessionid = audit_get_sessionid(current);
+ UNIXSCM(skb).procinfo_len = scm_get_current_procinfo(
+ &UNIXSCM(skb).procinfo);
}
}

@@ -1833,7 +1856,17 @@ 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);
- scm_set_audit(siocb->scm, UNIXCB(skb).loginuid, UNIXCB(skb).sessionid);
+ if (UNIXCB(skb).scm) {
+ scm_set_audit(siocb->scm, UNIXSCM(skb).loginuid,
+ UNIXSCM(skb).sessionid);
+ if (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)) {
@@ -2013,8 +2046,18 @@ again:
} else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
/* Copy credentials */
scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
- scm_set_audit(siocb->scm, UNIXCB(skb).loginuid,
- UNIXCB(skb).sessionid);
+ if (UNIXCB(skb).scm) {
+ scm_set_audit(siocb->scm,
+ UNIXSCM(skb).loginuid,
+ UNIXSCM(skb).sessionid);
+ if (UNIXSCM(skb).procinfo) {
+ scm_set_procinfo(siocb->scm,
+ kmemdup(UNIXSCM(skb).procinfo,
+ UNIXSCM(skb).procinfo_len,
+ GFP_KERNEL),
+ UNIXSCM(skb).procinfo_len);
+ }
+ }
check_creds = 1;
}

--
1.8.3.1

2014-01-13 16:53:46

by Tejun Heo

[permalink] [raw]
Subject: Re: [PATCH v4 3/3] Send cgroup_path in SCM_CGROUP

On Mon, Jan 13, 2014 at 09:01:49AM +0100, Jan Kaluza wrote:
> Server-like processes in many cases need credentials and other
> metadata of the peer, to decide if the calling process is allowed to
> request a specific action, or the server just wants to log away this
> type of information for auditing tasks.
>
> The current practice to retrieve such process metadata is to look that
> information up in procfs with the $PID received over SCM_CREDENTIALS.
> This is sufficient for long-running tasks, but introduces a race which
> cannot be worked around for short-living processes; the calling
> process and all the information in /proc/$PID/ is gone before the
> receiver of the socket message can look it up.
>
> This introduces a new SCM type called SCM_CGROUP to allow the direct
> attaching of "cgroup_path" to SCM, which is significantly more
> efficient and will reliably avoid the race with the round-trip over
> procfs.
>
> Signed-off-by: Jan Kaluza <[email protected]>

For cgroup related part:

Acked-by: Tejun Heo <[email protected]>

Thanks.

--
tejun

2014-01-13 16:57:15

by Tejun Heo

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] Send audit/procinfo/cgroup data in socket-level control message

Hello,

On Mon, Jan 13, 2014 at 09:01:46AM +0100, Jan Kaluza wrote:
> this patchset against net-next (applies also to linux-next) adds 3 new types
> of "Socket"-level control message (SCM_AUDIT, SCM_PROCINFO and SCM_CGROUP).
>
> Server-like processes in many cases need credentials and other
> metadata of the peer, to decide if the calling process is allowed to
> request a specific action, or the server just wants to log away this
> type of information for auditing tasks.
>
> The current practice to retrieve such process metadata is to look that
> information up in procfs with the $PID received over SCM_CREDENTIALS.
> This is sufficient for long-running tasks, but introduces a race which
> cannot be worked around for short-living processes; the calling
> process and all the information in /proc/$PID/ is gone before the
> receiver of the socket message can look it up.
>
> Changes introduced in this patchset can also increase performance
> of such server-like processes, because current way of opening and
> parsing /proc/$PID/* files is much more expensive than receiving these
> metadata using SCM.

Closing the race sounds like a good idea to me. What do net people
think?

Thanks.

--
tejun

2014-01-13 19:44:17

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] Send audit/procinfo/cgroup data in socket-level control message

On 1/13/2014 12:01 AM, Jan Kaluza wrote:
> Hi,
>
> this patchset against net-next (applies also to linux-next) adds 3 new types
> of "Socket"-level control message (SCM_AUDIT, SCM_PROCINFO and SCM_CGROUP).

How about the group list, while you're at it?

>
> Server-like processes in many cases need credentials and other
> metadata of the peer, to decide if the calling process is allowed to
> request a specific action, or the server just wants to log away this
> type of information for auditing tasks.
>
> The current practice to retrieve such process metadata is to look that
> information up in procfs with the $PID received over SCM_CREDENTIALS.
> This is sufficient for long-running tasks, but introduces a race which
> cannot be worked around for short-living processes; the calling
> process and all the information in /proc/$PID/ is gone before the
> receiver of the socket message can look it up.
>
> Changes introduced in this patchset can also increase performance
> of such server-like processes, because current way of opening and
> parsing /proc/$PID/* files is much more expensive than receiving these
> metadata using SCM.
>
> Changes in v4:
> - Rebased to work with the latest net-next tree
>
> Changes in v3:
> - Better description of patches (Thanks to Kay Sievers)
>
> Changes in v2:
> - use PATH_MAX instead of PAGE_SIZE in SCM_CGROUP patch
> - describe each patch individually
>
> Jan Kaluza (3):
> Send loginuid and sessionid in SCM_AUDIT
> Send comm and cmdline in SCM_PROCINFO
> Send cgroup_path in SCM_CGROUP
>
> include/linux/socket.h | 9 ++++++
> include/net/af_unix.h | 10 ++++++
> include/net/scm.h | 67 ++++++++++++++++++++++++++++++++++++++--
> net/core/scm.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++
> net/unix/af_unix.c | 70 ++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 237 insertions(+), 2 deletions(-)
>

2014-01-14 08:25:39

by Jan Kaluža

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] Send audit/procinfo/cgroup data in socket-level control message

On 01/13/2014 08:44 PM, Casey Schaufler wrote:
> On 1/13/2014 12:01 AM, Jan Kaluza wrote:
>> Hi,
>>
>> this patchset against net-next (applies also to linux-next) adds 3 new types
>> of "Socket"-level control message (SCM_AUDIT, SCM_PROCINFO and SCM_CGROUP).
>
> How about the group list, while you're at it?

That would be of course possible, but I would rather start with these
three patches at the beginning before adding more features, because I'm
not sure if there is consensus on accepting them. But I have no problem
with introducing group list later.

>>
>> Server-like processes in many cases need credentials and other
>> metadata of the peer, to decide if the calling process is allowed to
>> request a specific action, or the server just wants to log away this
>> type of information for auditing tasks.
>>
>> The current practice to retrieve such process metadata is to look that
>> information up in procfs with the $PID received over SCM_CREDENTIALS.
>> This is sufficient for long-running tasks, but introduces a race which
>> cannot be worked around for short-living processes; the calling
>> process and all the information in /proc/$PID/ is gone before the
>> receiver of the socket message can look it up.
>>
>> Changes introduced in this patchset can also increase performance
>> of such server-like processes, because current way of opening and
>> parsing /proc/$PID/* files is much more expensive than receiving these
>> metadata using SCM.
>>
>> Changes in v4:
>> - Rebased to work with the latest net-next tree
>>
>> Changes in v3:
>> - Better description of patches (Thanks to Kay Sievers)
>>
>> Changes in v2:
>> - use PATH_MAX instead of PAGE_SIZE in SCM_CGROUP patch
>> - describe each patch individually
>>
>> Jan Kaluza (3):
>> Send loginuid and sessionid in SCM_AUDIT
>> Send comm and cmdline in SCM_PROCINFO
>> Send cgroup_path in SCM_CGROUP
>>
>> include/linux/socket.h | 9 ++++++
>> include/net/af_unix.h | 10 ++++++
>> include/net/scm.h | 67 ++++++++++++++++++++++++++++++++++++++--
>> net/core/scm.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++
>> net/unix/af_unix.c | 70 ++++++++++++++++++++++++++++++++++++++++++
>> 5 files changed, 237 insertions(+), 2 deletions(-)
>>
>

2014-01-15 04:03:20

by Richard Guy Briggs

[permalink] [raw]
Subject: Re: [PATCH v4 2/3] Send comm and cmdline in SCM_PROCINFO

On 14/01/13, Jan Kaluza wrote:
> Server-like processes in many cases need credentials and other
> metadata of the peer, to decide if the calling process is allowed to
> request a specific action, or the server just wants to log away this
> type of information for auditing tasks.
>
> The current practice to retrieve such process metadata is to look that
> information up in procfs with the $PID received over SCM_CREDENTIALS.
> This is sufficient for long-running tasks, but introduces a race which
> cannot be worked around for short-living processes; the calling
> process and all the information in /proc/$PID/ is gone before the
> receiver of the socket message can look it up.
>
> This introduces a new SCM type called SCM_PROCINFO to allow the direct
> attaching of "comm" and "cmdline" to SCM, which is significantly more
> efficient and will reliably avoid the race with the round-trip over
> procfs.
>
> To achieve that, new struct called unix_skb_parms_scm had to be created,
> because otherwise unix_skb_parms would be too big.
>
> scm_get_current_procinfo is inspired by ./fs/proc/base.c.
>
> Signed-off-by: Jan Kaluza <[email protected]>

Acked-by: Richard Guy Briggs <[email protected]>

> ---
> include/linux/socket.h | 2 ++
> include/net/af_unix.h | 11 +++++++--
> include/net/scm.h | 24 +++++++++++++++++++
> net/core/scm.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
> net/unix/af_unix.c | 57 +++++++++++++++++++++++++++++++++++++------
> 5 files changed, 150 insertions(+), 9 deletions(-)
>
> diff --git a/include/linux/socket.h b/include/linux/socket.h
> index eeac565..5a41f35 100644
> --- a/include/linux/socket.h
> +++ b/include/linux/socket.h
> @@ -131,6 +131,8 @@ static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr
> #define SCM_CREDENTIALS 0x02 /* rw: struct ucred */
> #define SCM_SECURITY 0x03 /* rw: security label */
> #define SCM_AUDIT 0x04 /* rw: struct uaudit */
> +#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 3b9d22a..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,12 +43,12 @@ struct unix_skb_parms {
> u32 secid; /* Security ID */
> #endif
> u32 consumed;
> - kuid_t loginuid;
> - unsigned int sessionid;
> + 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 67de64f..f084e19 100644
> --- a/include/net/scm.h
> +++ b/include/net/scm.h
> @@ -30,11 +30,17 @@ 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 */
> struct scm_creds creds; /* Skb credentials */
> struct scm_audit audit; /* Skb audit */
> + struct scm_procinfo procinfo; /* Skb procinfo */
> #ifdef CONFIG_SECURITY_NETWORK
> u32 secid; /* Passed security ID */
> #endif
> @@ -45,6 +51,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)
> @@ -72,10 +79,20 @@ static inline void scm_set_audit(struct scm_cookie *scm,
> scm->audit.sessionid = sessionid;
> }
>
> +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_destroy_cred(struct scm_cookie *scm)
> {
> put_pid(scm->pid);
> scm->pid = NULL;
> + kfree(scm->procinfo.procinfo);
> + scm->procinfo.procinfo = NULL;
> + scm->procinfo.len = 0;
> }
>
> static __inline__ void scm_destroy(struct scm_cookie *scm)
> @@ -88,6 +105,8 @@ 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;
> @@ -96,6 +115,9 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
> current_gid());
> scm_set_audit(scm, audit_get_loginuid(current),
> audit_get_sessionid(current));
> + 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)
> @@ -148,6 +170,8 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
> };
> put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
> put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
> + put_cmsg(msg, SOL_SOCKET, SCM_PROCINFO, scm->procinfo.len,
> + scm->procinfo.procinfo);
> }
>
> scm_destroy_cred(scm);
> diff --git a/net/core/scm.c b/net/core/scm.c
> index b442e7e..4accb07 100644
> --- a/net/core/scm.c
> +++ b/net/core/scm.c
> @@ -339,3 +339,68 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
> return new_fpl;
> }
> EXPORT_SYMBOL(scm_fp_dup);
> +
> +int scm_get_current_procinfo(char **procinfo)
> +{
> + int res = 0;
> + unsigned int len;
> + char *buffer = NULL;
> + struct mm_struct *mm;
> + int comm_len = strlen(current->comm);
> +
> + *procinfo = NULL;
> +
> + buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
> + if (!buffer)
> + return -ENOMEM;
> +
> + mm = get_task_mm(current);
> + if (!mm)
> + goto out;
> + if (!mm->arg_end)
> + goto out_mm; /* Shh! No looking before we're done */
> +
> + 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);
> + }
> + }
> +
> + /* strlen(comm) + \0 + len of cmdline */
> + len = comm_len + 1 + res;
> + *procinfo = kmalloc(len, GFP_KERNEL);
> + if (!*procinfo) {
> + res = -ENOMEM;
> + goto out_mm;
> + }
> +
> + memcpy(*procinfo, current->comm, comm_len + 1); /* include \0 */
> + if (res > 0)
> + memcpy(*procinfo + comm_len + 1, buffer, res);
> + res = len;
> +
> +out_mm:
> + mmput(mm);
> +out:
> + kfree(buffer);
> + return res;
> +}
> +EXPORT_SYMBOL(scm_get_current_procinfo);
> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index bc02a25..35ab97f0 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -1361,9 +1361,14 @@ 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);
> @@ -1410,15 +1415,31 @@ 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;
> - UNIXCB(skb).loginuid = scm->audit.loginuid;
> - UNIXCB(skb).sessionid = scm->audit.sessionid;
> + UNIXSCM(skb).loginuid = scm->audit.loginuid;
> + UNIXSCM(skb).sessionid = scm->audit.sessionid;
> UNIXCB(skb).fp = NULL;
> 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,8 +1459,10 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
> test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
> UNIXCB(skb).pid = get_pid(task_tgid(current));
> current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
> - UNIXCB(skb).loginuid = audit_get_loginuid(current);
> - UNIXCB(skb).sessionid = audit_get_sessionid(current);
> + UNIXSCM(skb).loginuid = audit_get_loginuid(current);
> + UNIXSCM(skb).sessionid = audit_get_sessionid(current);
> + UNIXSCM(skb).procinfo_len = scm_get_current_procinfo(
> + &UNIXSCM(skb).procinfo);
> }
> }
>
> @@ -1833,7 +1856,17 @@ 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);
> - scm_set_audit(siocb->scm, UNIXCB(skb).loginuid, UNIXCB(skb).sessionid);
> + if (UNIXCB(skb).scm) {
> + scm_set_audit(siocb->scm, UNIXSCM(skb).loginuid,
> + UNIXSCM(skb).sessionid);
> + if (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)) {
> @@ -2013,8 +2046,18 @@ again:
> } else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
> /* Copy credentials */
> scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
> - scm_set_audit(siocb->scm, UNIXCB(skb).loginuid,
> - UNIXCB(skb).sessionid);
> + if (UNIXCB(skb).scm) {
> + scm_set_audit(siocb->scm,
> + UNIXSCM(skb).loginuid,
> + UNIXSCM(skb).sessionid);
> + if (UNIXSCM(skb).procinfo) {
> + scm_set_procinfo(siocb->scm,
> + kmemdup(UNIXSCM(skb).procinfo,
> + UNIXSCM(skb).procinfo_len,
> + GFP_KERNEL),
> + UNIXSCM(skb).procinfo_len);
> + }
> + }
> check_creds = 1;
> }
>
> --
> 1.8.3.1
>

- RGB

--
Richard Guy Briggs <[email protected]>
Senior Software Engineer, Kernel Security, AMER ENG Base Operating Systems, Red Hat
Remote, Ottawa, Canada
Voice: +1.647.777.2635, Internal: (81) 32635, Alt: +1.613.693.0684x3545

2014-01-15 04:07:41

by Richard Guy Briggs

[permalink] [raw]
Subject: Re: [PATCH v4 1/3] Send loginuid and sessionid in SCM_AUDIT

On 14/01/13, Jan Kaluza wrote:
> Server-like processes in many cases need credentials and other
> metadata of the peer, to decide if the calling process is allowed to
> request a specific action, or the server just wants to log away this
> type of information for auditing tasks.
>
> The current practice to retrieve such process metadata is to look that
> information up in procfs with the $PID received over SCM_CREDENTIALS.
> This is sufficient for long-running tasks, but introduces a race which
> cannot be worked around for short-living processes; the calling
> process and all the information in /proc/$PID/ is gone before the
> receiver of the socket message can look it up.
>
> This introduces a new SCM type called SCM_AUDIT to allow the direct
> attaching of "loginuid" and "sessionid" to SCM, which is significantly more
> efficient and will reliably avoid the race with the round-trip over
> procfs.
>
> Signed-off-by: Jan Kaluza <[email protected]>

Acked-by: Richard Guy Briggs <[email protected]>

> ---
> include/linux/socket.h | 6 ++++++
> include/net/af_unix.h | 2 ++
> include/net/scm.h | 28 ++++++++++++++++++++++++++--
> net/unix/af_unix.c | 7 +++++++
> 4 files changed, 41 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/socket.h b/include/linux/socket.h
> index 5d488a6..eeac565 100644
> --- a/include/linux/socket.h
> +++ b/include/linux/socket.h
> @@ -130,6 +130,7 @@ 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_AUDIT 0x04 /* rw: struct uaudit */
>
> struct ucred {
> __u32 pid;
> @@ -137,6 +138,11 @@ struct ucred {
> __u32 gid;
> };
>
> +struct uaudit {
> + __u32 loginuid;
> + __u32 sessionid;
> +};
> +
> /* Supported address families. */
> #define AF_UNSPEC 0
> #define AF_UNIX 1 /* Unix domain sockets */
> diff --git a/include/net/af_unix.h b/include/net/af_unix.h
> index a175ba4..3b9d22a 100644
> --- a/include/net/af_unix.h
> +++ b/include/net/af_unix.h
> @@ -36,6 +36,8 @@ struct unix_skb_parms {
> u32 secid; /* Security ID */
> #endif
> u32 consumed;
> + kuid_t loginuid;
> + unsigned int sessionid;
> };
>
> #define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb))
> diff --git a/include/net/scm.h b/include/net/scm.h
> index 262532d..67de64f 100644
> --- a/include/net/scm.h
> +++ b/include/net/scm.h
> @@ -6,6 +6,7 @@
> #include <linux/security.h>
> #include <linux/pid.h>
> #include <linux/nsproxy.h>
> +#include <linux/audit.h>
>
> /* Well, we should have at least one descriptor open
> * to accept passed FDs 8)
> @@ -18,6 +19,11 @@ struct scm_creds {
> kgid_t gid;
> };
>
> +struct scm_audit {
> + kuid_t loginuid;
> + unsigned int sessionid;
> +};
> +
> struct scm_fp_list {
> short count;
> short max;
> @@ -28,6 +34,7 @@ struct scm_cookie {
> struct pid *pid; /* Skb credentials */
> struct scm_fp_list *fp; /* Passed files */
> struct scm_creds creds; /* Skb credentials */
> + struct scm_audit audit; /* Skb audit */
> #ifdef CONFIG_SECURITY_NETWORK
> u32 secid; /* Passed security ID */
> #endif
> @@ -58,6 +65,13 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm,
> scm->creds.gid = gid;
> }
>
> +static inline void scm_set_audit(struct scm_cookie *scm,
> + kuid_t loginuid, unsigned int sessionid)
> +{
> + scm->audit.loginuid = loginuid;
> + scm->audit.sessionid = sessionid;
> +}
> +
> static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
> {
> put_pid(scm->pid);
> @@ -77,8 +91,12 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
> 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 (forcecreds) {
> + scm_set_cred(scm, task_tgid(current), current_uid(),
> + current_gid());
> + scm_set_audit(scm, audit_get_loginuid(current),
> + audit_get_sessionid(current));
> + }
> unix_get_peersec_dgram(sock, scm);
> if (msg->msg_controllen <= 0)
> return 0;
> @@ -123,7 +141,13 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
> .uid = from_kuid_munged(current_ns, scm->creds.uid),
> .gid = from_kgid_munged(current_ns, scm->creds.gid),
> };
> + struct uaudit uaudits = {
> + .loginuid = from_kuid_munged(current_ns,
> + scm->audit.loginuid),
> + .sessionid = scm->audit.sessionid,
> + };
> put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
> + put_cmsg(msg, SOL_SOCKET, SCM_AUDIT, sizeof(uaudits), &uaudits);
> }
>
> scm_destroy_cred(scm);
> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index 800ca61..bc02a25 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -1413,6 +1413,8 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
> UNIXCB(skb).pid = get_pid(scm->pid);
> UNIXCB(skb).uid = scm->creds.uid;
> UNIXCB(skb).gid = scm->creds.gid;
> + UNIXCB(skb).loginuid = scm->audit.loginuid;
> + UNIXCB(skb).sessionid = scm->audit.sessionid;
> UNIXCB(skb).fp = NULL;
> if (scm->fp && send_fds)
> err = unix_attach_fds(scm, skb);
> @@ -1436,6 +1438,8 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
> test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
> UNIXCB(skb).pid = get_pid(task_tgid(current));
> current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
> + UNIXCB(skb).loginuid = audit_get_loginuid(current);
> + UNIXCB(skb).sessionid = audit_get_sessionid(current);
> }
> }
>
> @@ -1829,6 +1833,7 @@ 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);
> + scm_set_audit(siocb->scm, UNIXCB(skb).loginuid, UNIXCB(skb).sessionid);
> unix_set_secdata(siocb->scm, skb);
>
> if (!(flags & MSG_PEEK)) {
> @@ -2008,6 +2013,8 @@ again:
> } else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
> /* Copy credentials */
> scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
> + scm_set_audit(siocb->scm, UNIXCB(skb).loginuid,
> + UNIXCB(skb).sessionid);
> check_creds = 1;
> }
>
> --
> 1.8.3.1
>

- RGB

--
Richard Guy Briggs <[email protected]>
Senior Software Engineer, Kernel Security, AMER ENG Base Operating Systems, Red Hat
Remote, Ottawa, Canada
Voice: +1.647.777.2635, Internal: (81) 32635, Alt: +1.613.693.0684x3545

2014-01-15 20:17:33

by David Miller

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] Send audit/procinfo/cgroup data in socket-level control message

From: Jan Kaluza <[email protected]>
Date: Mon, 13 Jan 2014 09:01:46 +0100

> Changes introduced in this patchset can also increase performance
> of such server-like processes, because current way of opening and
> parsing /proc/$PID/* files is much more expensive than receiving these
> metadata using SCM.

The problem with this line of reasoning is that these changes will
hurt everyone else, because these new control messages are sent
unconditionally, whether the application is interested in them or not.

I really don't like this cost tradeoff, it's terrible, and therefore
I'm really not inclined to apply these patches, sorry.

2014-01-15 23:21:57

by Eric Paris

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] Send audit/procinfo/cgroup data in socket-level control message

On Wed, 2014-01-15 at 12:17 -0800, David Miller wrote:
> From: Jan Kaluza <[email protected]>
> Date: Mon, 13 Jan 2014 09:01:46 +0100
>
> > Changes introduced in this patchset can also increase performance
> > of such server-like processes, because current way of opening and
> > parsing /proc/$PID/* files is much more expensive than receiving these
> > metadata using SCM.
>
> The problem with this line of reasoning is that these changes will
> hurt everyone else, because these new control messages are sent
> unconditionally, whether the application is interested in them or not.
>
> I really don't like this cost tradeoff, it's terrible, and therefore
> I'm really not inclined to apply these patches, sorry.

Agreed. Although you seem to be ignoring the part of the logic where is
solves a problem that can not be solved today.

> The current practice to retrieve such process metadata is to look that
> information up in procfs with the $PID received over SCM_CREDENTIALS.
> This is sufficient for long-running tasks, but introduces a race which
> cannot be worked around for short-living processes; the calling
> process and all the information in /proc/$PID/ is gone before the
> receiver of the socket message can look it up.

Reliably being able to audit what process requested an action is
extremely useful. And I like the audit patch, as it is a couple of ints
we are storing.

procinfo and cgroup can both be up to 4k of data.

Is there an alternative he should consider? Some way to grab a
reference on task_struct and just attach that to the message?

2014-01-15 23:23:51

by Tejun Heo

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] Send audit/procinfo/cgroup data in socket-level control message

On Wed, Jan 15, 2014 at 06:21:43PM -0500, Eric Paris wrote:
> Reliably being able to audit what process requested an action is
> extremely useful. And I like the audit patch, as it is a couple of ints
> we are storing.
>
> procinfo and cgroup can both be up to 4k of data.
>
> Is there an alternative he should consider? Some way to grab a
> reference on task_struct and just attach that to the message?

Or maybe it can be made separately optional instead of tagging along
on an existing option so that it doesn't tax use cases which don't
care about the new stuff?

Thanks.

--
tejun

2014-01-16 09:30:09

by Jan Kaluža

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] Send audit/procinfo/cgroup data in socket-level control message

On 01/16/2014 12:23 AM, Tejun Heo wrote:
> On Wed, Jan 15, 2014 at 06:21:43PM -0500, Eric Paris wrote:
>> Reliably being able to audit what process requested an action is
>> extremely useful. And I like the audit patch, as it is a couple of ints
>> we are storing.
>>
>> procinfo and cgroup can both be up to 4k of data.
>>
>> Is there an alternative he should consider? Some way to grab a
>> reference on task_struct and just attach that to the message?
>
> Or maybe it can be made separately optional instead of tagging along
> on an existing option so that it doesn't tax use cases which don't
> care about the new stuff?

Right, I could add new option next to SOCK_PASSCRED which could be used
to send newly added stuff. Would this be acceptable?

I would still vote for SCM_AUDIT to be part of SOCK_PASSCRED and move
SCM_CGROUP and SCM_PROCINFO into new option.

> Thanks.
>

Regards,
Jan Kaluza

2014-01-23 19:31:47

by Kay Sievers

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] Send audit/procinfo/cgroup data in socket-level control message

On Thu, Jan 16, 2014 at 10:29 AM, Jan Kaluža <[email protected]> wrote:
> On 01/16/2014 12:23 AM, Tejun Heo wrote:
>> On Wed, Jan 15, 2014 at 06:21:43PM -0500, Eric Paris wrote:
>>>
>>> Reliably being able to audit what process requested an action is
>>> extremely useful. And I like the audit patch, as it is a couple of ints
>>> we are storing.
>>>
>>> procinfo and cgroup can both be up to 4k of data.
>>>
>>> Is there an alternative he should consider? Some way to grab a
>>> reference on task_struct and just attach that to the message?
>>
>> Or maybe it can be made separately optional instead of tagging along
>> on an existing option so that it doesn't tax use cases which don't
>> care about the new stuff?
>
> Right, I could add new option next to SOCK_PASSCRED which could be used to
> send newly added stuff. Would this be acceptable?
>
> I would still vote for SCM_AUDIT to be part of SOCK_PASSCRED and move
> SCM_CGROUP and SCM_PROCINFO into new option.

Maybe we could just add a new SOCK_PASS_TASKINFO bit to set in
socket->flags. Set that bit with a new SO_PASS_TASKINFO sockoption.

The SOCK_PASS_TASKINFO can carry all sorts of "struct task" related
stuff, also include the audit data. It is all fully conditional, so
users which do not explicitly subscribe to TASKINFO will never see the
data or needlessly pay for the overhead.

A TASKINFO sounds generic enough to be possibly extended with new data
in the future, without wasting extra bits in the socket flags.

Users which subscribe with SO_PASS_TASKINFO expect some overhead
anyway. In the end it's still a lot cheaper than parsing /proc for the
data; which is also racy and does therefore not work for any
short-living program.

Thanks,
Kay