lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Thu, 29 May 2014 13:13:36 +0200 From: Piotr Wilczek <p.wilczek@...sung.com> To: David Miller <davem@...emloft.net> Cc: netdev@...r.kernel.org, Kyungmin Park <kyungmin.park@...sung.com>, Juho Son <juho80.son@...sung.com>, Bartlomiej Zolnierkiewicz <b.zolnierkie@...sung.com>, Piotr Wilczek <p.wilczek@...sung.com>, Jan Kaluza <jkaluza@...hat.com> Subject: [PATCH RFC] Send process status in SCM_PROCINFO This introduces a new SCM type called SCM_PROCINFO to allow the direct attaching of process status to SCM, which is significantly more efficient and will reliably avoid the race with the round-trip over procfs. This is optional and can be turned on by setting SO_PASSPROC. To achieve that, new struct called unix_skb_parms_scm had to be created, because otherwise unix_skb_parms would be too big. scm_get_current_procinfo is inspired by ./fs/proc/base.c and array.c This patch is reworked version of: https://lkml.org/lkml/2014/1/13/40 Signed-off-by: Jan Kaluza <jkaluza@...hat.com> Signed-off-by: Piotr Wilczek <p.wilczek@...sung.com> --- arch/alpha/include/uapi/asm/socket.h | 2 + arch/avr32/include/uapi/asm/socket.h | 2 + arch/cris/include/uapi/asm/socket.h | 2 + arch/frv/include/uapi/asm/socket.h | 2 + arch/ia64/include/uapi/asm/socket.h | 2 + arch/m32r/include/uapi/asm/socket.h | 2 + arch/mips/include/uapi/asm/socket.h | 2 + arch/mn10300/include/uapi/asm/socket.h | 2 + arch/parisc/include/uapi/asm/socket.h | 2 + arch/powerpc/include/uapi/asm/socket.h | 2 + arch/s390/include/uapi/asm/socket.h | 2 + arch/sparc/include/uapi/asm/socket.h | 2 + include/linux/net.h | 1 + include/linux/socket.h | 2 + include/net/af_unix.h | 9 + include/net/scm.h | 28 +++ include/uapi/asm-generic/socket.h | 2 + net/core/scm.c | 429 +++++++++++++++++++++++++++++++++ net/core/sock.c | 11 + net/unix/af_unix.c | 70 ++++++ 20 files changed, 576 insertions(+) diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h index 3de1394..29608f2 100644 --- a/arch/alpha/include/uapi/asm/socket.h +++ b/arch/alpha/include/uapi/asm/socket.h @@ -87,4 +87,6 @@ #define SO_BPF_EXTENSIONS 48 +#define SO_PASSPROC 49 + #endif /* _UAPI_ASM_SOCKET_H */ diff --git a/arch/avr32/include/uapi/asm/socket.h b/arch/avr32/include/uapi/asm/socket.h index 6e6cd15..a9bbc63 100644 --- a/arch/avr32/include/uapi/asm/socket.h +++ b/arch/avr32/include/uapi/asm/socket.h @@ -80,4 +80,6 @@ #define SO_BPF_EXTENSIONS 48 +#define SO_PASSPROC 49 + #endif /* _UAPI__ASM_AVR32_SOCKET_H */ diff --git a/arch/cris/include/uapi/asm/socket.h b/arch/cris/include/uapi/asm/socket.h index ed94e5e..df0c641 100644 --- a/arch/cris/include/uapi/asm/socket.h +++ b/arch/cris/include/uapi/asm/socket.h @@ -82,6 +82,8 @@ #define SO_BPF_EXTENSIONS 48 +#define SO_PASSPROC 49 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/frv/include/uapi/asm/socket.h b/arch/frv/include/uapi/asm/socket.h index ca2c6e6..3cd9cb1 100644 --- a/arch/frv/include/uapi/asm/socket.h +++ b/arch/frv/include/uapi/asm/socket.h @@ -80,5 +80,7 @@ #define SO_BPF_EXTENSIONS 48 +#define SO_PASSPROC 49 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/ia64/include/uapi/asm/socket.h b/arch/ia64/include/uapi/asm/socket.h index a1b49ba..656ba43 100644 --- a/arch/ia64/include/uapi/asm/socket.h +++ b/arch/ia64/include/uapi/asm/socket.h @@ -89,4 +89,6 @@ #define SO_BPF_EXTENSIONS 48 +#define SO_PASSPROC 49 + #endif /* _ASM_IA64_SOCKET_H */ diff --git a/arch/m32r/include/uapi/asm/socket.h b/arch/m32r/include/uapi/asm/socket.h index 6c9a24b..758ce55 100644 --- a/arch/m32r/include/uapi/asm/socket.h +++ b/arch/m32r/include/uapi/asm/socket.h @@ -80,4 +80,6 @@ #define SO_BPF_EXTENSIONS 48 +#define SO_PASSPROC 49 + #endif /* _ASM_M32R_SOCKET_H */ diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h index a14baa2..cc7b8f5 100644 --- a/arch/mips/include/uapi/asm/socket.h +++ b/arch/mips/include/uapi/asm/socket.h @@ -98,4 +98,6 @@ #define SO_BPF_EXTENSIONS 48 +#define SO_PASSPROC 49 + #endif /* _UAPI_ASM_SOCKET_H */ diff --git a/arch/mn10300/include/uapi/asm/socket.h b/arch/mn10300/include/uapi/asm/socket.h index 6aa3ce1..b49368f2 100644 --- a/arch/mn10300/include/uapi/asm/socket.h +++ b/arch/mn10300/include/uapi/asm/socket.h @@ -80,4 +80,6 @@ #define SO_BPF_EXTENSIONS 48 +#define SO_PASSPROC 49 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h index fe35cea..b3facfa 100644 --- a/arch/parisc/include/uapi/asm/socket.h +++ b/arch/parisc/include/uapi/asm/socket.h @@ -79,4 +79,6 @@ #define SO_BPF_EXTENSIONS 0x4029 +#define SO_PASSPROC 0x402a + #endif /* _UAPI_ASM_SOCKET_H */ diff --git a/arch/powerpc/include/uapi/asm/socket.h b/arch/powerpc/include/uapi/asm/socket.h index a9c3e2e..b582047 100644 --- a/arch/powerpc/include/uapi/asm/socket.h +++ b/arch/powerpc/include/uapi/asm/socket.h @@ -87,4 +87,6 @@ #define SO_BPF_EXTENSIONS 48 +#define SO_PASSPROC 49 + #endif /* _ASM_POWERPC_SOCKET_H */ diff --git a/arch/s390/include/uapi/asm/socket.h b/arch/s390/include/uapi/asm/socket.h index e031332..ffd6fa5 100644 --- a/arch/s390/include/uapi/asm/socket.h +++ b/arch/s390/include/uapi/asm/socket.h @@ -86,4 +86,6 @@ #define SO_BPF_EXTENSIONS 48 +#define SO_PASSPROC 49 + #endif /* _ASM_SOCKET_H */ diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h index 54d9608..875353f 100644 --- a/arch/sparc/include/uapi/asm/socket.h +++ b/arch/sparc/include/uapi/asm/socket.h @@ -76,6 +76,8 @@ #define SO_BPF_EXTENSIONS 0x0032 +#define SO_PASSPROC 0x0033 + /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001 #define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 diff --git a/include/linux/net.h b/include/linux/net.h index 17d8339..38ad416 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -39,6 +39,7 @@ struct net; #define SOCK_PASSCRED 3 #define SOCK_PASSSEC 4 #define SOCK_EXTERNALLY_ALLOCATED 5 +#define SOCK_PASSPROC 6 #ifndef ARCH_HAS_SOCKET_TYPES /** diff --git a/include/linux/socket.h b/include/linux/socket.h index 8e98297..a5ebf79 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -130,6 +130,8 @@ static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr #define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */ #define SCM_CREDENTIALS 0x02 /* rw: struct ucred */ #define SCM_SECURITY 0x03 /* rw: security label */ +#define SCM_PROCINFO 0x05 /* rw: comm + cmdline (NULL terminated + array of char *) */ struct ucred { __u32 pid; diff --git a/include/net/af_unix.h b/include/net/af_unix.h index a175ba4..05c7678 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -27,6 +27,13 @@ struct unix_address { struct sockaddr_un name[0]; }; +struct unix_skb_parms_scm { + kuid_t loginuid; + unsigned int sessionid; + char *procinfo; + int procinfo_len; +}; + struct unix_skb_parms { struct pid *pid; /* Skb credentials */ kuid_t uid; @@ -36,10 +43,12 @@ struct unix_skb_parms { u32 secid; /* Security ID */ #endif u32 consumed; + struct unix_skb_parms_scm *scm; }; #define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb)) #define UNIXSID(skb) (&UNIXCB((skb)).secid) +#define UNIXSCM(skb) (*(UNIXCB((skb)).scm)) #define unix_state_lock(s) spin_lock(&unix_sk(s)->lock) #define unix_state_unlock(s) spin_unlock(&unix_sk(s)->lock) diff --git a/include/net/scm.h b/include/net/scm.h index 262532d..cc28cd4 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -24,6 +24,11 @@ struct scm_fp_list { struct file *fp[SCM_MAX_FD]; }; +struct scm_procinfo { + char *procinfo; + int len; +}; + struct scm_cookie { struct pid *pid; /* Skb credentials */ struct scm_fp_list *fp; /* Passed files */ @@ -31,6 +36,7 @@ struct scm_cookie { #ifdef CONFIG_SECURITY_NETWORK u32 secid; /* Passed security ID */ #endif + struct scm_procinfo procinfo; /* Skb procinfo */ }; void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm); @@ -38,6 +44,8 @@ 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); +extern int scm_get_current_procinfo(char **procinfo); +extern void task_mem(struct seq_file *, struct mm_struct *); #ifdef CONFIG_SECURITY_NETWORK static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm) @@ -49,6 +57,13 @@ static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_co { } #endif /* CONFIG_SECURITY_NETWORK */ +static inline void scm_set_procinfo(struct scm_cookie *scm, + char *procinfo, int len) +{ + scm->procinfo.procinfo = procinfo; + scm->procinfo.len = len; +} + static __inline__ void scm_set_cred(struct scm_cookie *scm, struct pid *pid, kuid_t uid, kgid_t gid) { @@ -62,6 +77,9 @@ 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) @@ -74,11 +92,18 @@ static __inline__ void scm_destroy(struct scm_cookie *scm) static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm, bool forcecreds) { + char *procinfo; + int len; memset(scm, 0, sizeof(*scm)); scm->creds.uid = INVALID_UID; scm->creds.gid = INVALID_GID; if (forcecreds) scm_set_cred(scm, task_tgid(current), current_uid(), current_gid()); + if (test_bit(SOCK_PASSPROC, &sock->flags)) { + len = scm_get_current_procinfo(&procinfo); + if (len > 0) + scm_set_procinfo(scm, procinfo, len); + } unix_get_peersec_dgram(sock, scm); if (msg->msg_controllen <= 0) return 0; @@ -125,6 +150,9 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, }; put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds); } + if (test_bit(SOCK_PASSPROC, &sock->flags)) + put_cmsg(msg, SOL_SOCKET, SCM_PROCINFO, scm->procinfo.len, + scm->procinfo.procinfo); scm_destroy_cred(scm); diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h index ea0796b..8ce4e94 100644 --- a/include/uapi/asm-generic/socket.h +++ b/include/uapi/asm-generic/socket.h @@ -82,4 +82,6 @@ #define SO_BPF_EXTENSIONS 48 +#define SO_PASSPROC 49 + #endif /* __ASM_GENERIC_SOCKET_H */ diff --git a/net/core/scm.c b/net/core/scm.c index b442e7e..ec6a741 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -28,6 +28,9 @@ #include <linux/pid.h> #include <linux/nsproxy.h> #include <linux/slab.h> +#include <linux/ptrace.h> +#include <linux/fdtable.h> +#include <linux/cpuset.h> #include <asm/uaccess.h> @@ -339,3 +342,429 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl) return new_fpl; } EXPORT_SYMBOL(scm_fp_dup); + +static inline void task_name(struct seq_file *m, struct task_struct *p) +{ + int i; + char *buf, *end; + char *name; + char tcomm[sizeof(p->comm)]; + + get_task_comm(tcomm, p); + + seq_puts(m, "Name:\t"); + end = m->buf + m->size; + buf = m->buf + m->count; + name = tcomm; + i = sizeof(tcomm); + while (i && (buf < end)) { + unsigned char c = *name; + + name++; + i--; + *buf = c; + if (!c) + break; + if (c == '\\') { + buf++; + if (buf < end) + *buf++ = c; + continue; + } + if (c == '\n') { + *buf++ = '\\'; + if (buf < end) + *buf++ = 'n'; + continue; + } + buf++; + } + m->count = buf - m->buf; + seq_putc(m, '\n'); +} + +/* The task state array is a strange "bitmap" of + * reasons to sleep. Thus "running" is zero, and + * you can test for combinations of others with + * simple bit tests. + */ +static const char * const task_state_array[] = { + "R (running)", /* 0 */ + "S (sleeping)", /* 1 */ + "D (disk sleep)", /* 2 */ + "T (stopped)", /* 4 */ + "t (tracing stop)", /* 8 */ + "Z (zombie)", /* 16 */ + "X (dead)", /* 32 */ + "x (dead)", /* 64 */ + "K (wakekill)", /* 128 */ + "W (waking)", /* 256 */ + "P (parked)", /* 512 */ +}; + +static inline const char *get_task_state(struct task_struct *tsk) +{ + unsigned int state = (tsk->state & TASK_REPORT) | tsk->exit_state; + const char * const *p = &task_state_array[0]; + + BUILD_BUG_ON(1 + ilog2(TASK_STATE_MAX) != ARRAY_SIZE(task_state_array)); + + while (state) { + p++; + state >>= 1; + } + return *p; +} + +static inline void task_state(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *p) +{ + struct user_namespace *user_ns = seq_user_ns(m); + struct group_info *group_info; + int g; + struct fdtable *fdt = NULL; + const struct cred *cred; + pid_t ppid, tpid; + + rcu_read_lock(); + ppid = pid_alive(p) ? + task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0; + tpid = 0; + if (pid_alive(p)) { + struct task_struct *tracer = ptrace_parent(p); + if (tracer) + tpid = task_pid_nr_ns(tracer, ns); + } + + cred = get_task_cred(p); + if (cred == NULL || user_ns == NULL) + return; + seq_printf(m, + "State:\t%s\n" + "Tgid:\t%d\n" + "Pid:\t%d\n" + "PPid:\t%d\n" + "TracerPid:\t%d\n" + "Uid:\t%d\t%d\t%d\t%d\n" + "Gid:\t%d\t%d\t%d\t%d\n", + get_task_state(p), + task_tgid_nr_ns(p, ns), + pid_nr_ns(pid, ns), + ppid, tpid, + from_kuid_munged(user_ns, cred->uid), + from_kuid_munged(user_ns, cred->euid), + from_kuid_munged(user_ns, cred->suid), + from_kuid_munged(user_ns, cred->fsuid), + from_kgid_munged(user_ns, cred->gid), + from_kgid_munged(user_ns, cred->egid), + from_kgid_munged(user_ns, cred->sgid), + from_kgid_munged(user_ns, cred->fsgid)); + + task_lock(p); + if (p->files) + fdt = files_fdtable(p->files); + seq_printf(m, + "FDSize:\t%d\n" + "Groups:\t", + fdt ? fdt->max_fds : 0); + rcu_read_unlock(); + + group_info = cred->group_info; + task_unlock(p); + + for (g = 0; g < group_info->ngroups; g++) + seq_printf(m, "%d ", + from_kgid_munged(user_ns, GROUP_AT(group_info, g))); + put_cred(cred); + + seq_putc(m, '\n'); +} + +static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign, + sigset_t *catch) +{ + struct k_sigaction *k; + int i; + + k = p->sighand->action; + for (i = 1; i <= _NSIG; ++i, ++k) { + if (k->sa.sa_handler == SIG_IGN) + sigaddset(ign, i); + else if (k->sa.sa_handler != SIG_DFL) + sigaddset(catch, i); + } +} + +static inline void task_sig(struct seq_file *m, struct task_struct *p) +{ + unsigned long flags; + sigset_t pending, shpending, blocked, ignored, caught; + int num_threads = 0; + unsigned long qsize = 0; + unsigned long qlim = 0; + + sigemptyset(&pending); + sigemptyset(&shpending); + sigemptyset(&blocked); + sigemptyset(&ignored); + sigemptyset(&caught); + + if (lock_task_sighand(p, &flags)) { + pending = p->pending.signal; + shpending = p->signal->shared_pending.signal; + blocked = p->blocked; + collect_sigign_sigcatch(p, &ignored, &caught); + num_threads = get_nr_threads(p); + rcu_read_lock(); /* FIXME: is this correct? */ + qsize = atomic_read(&__task_cred(p)->user->sigpending); + rcu_read_unlock(); + qlim = task_rlimit(p, RLIMIT_SIGPENDING); + unlock_task_sighand(p, &flags); + } + + seq_printf(m, "Threads:\t%d\n", num_threads); + seq_printf(m, "SigQ:\t%lu/%lu\n", qsize, qlim); + + /* render them all */ + render_sigset_t(m, "SigPnd:\t", &pending); + render_sigset_t(m, "ShdPnd:\t", &shpending); + render_sigset_t(m, "SigBlk:\t", &blocked); + render_sigset_t(m, "SigIgn:\t", &ignored); + render_sigset_t(m, "SigCgt:\t", &caught); +} + +static void render_cap_t(struct seq_file *m, const char *header, + kernel_cap_t *a) +{ + unsigned __capi; + + seq_puts(m, header); + CAP_FOR_EACH_U32(__capi) { + seq_printf(m, "%08x", + a->cap[(_KERNEL_CAPABILITY_U32S-1) - __capi]); + } + seq_putc(m, '\n'); +} + +/* Remove non-existent capabilities */ +#define NORM_CAPS(v) (v.cap[CAP_TO_INDEX(CAP_LAST_CAP)] &= \ + CAP_TO_MASK(CAP_LAST_CAP + 1) - 1) + +static inline void task_cap(struct seq_file *m, struct task_struct *p) +{ + const struct cred *cred; + kernel_cap_t cap_inheritable, cap_permitted, cap_effective, cap_bset; + + rcu_read_lock(); + cred = __task_cred(p); + cap_inheritable = cred->cap_inheritable; + cap_permitted = cred->cap_permitted; + cap_effective = cred->cap_effective; + cap_bset = cred->cap_bset; + rcu_read_unlock(); + + NORM_CAPS(cap_inheritable); + NORM_CAPS(cap_permitted); + NORM_CAPS(cap_effective); + NORM_CAPS(cap_bset); + + render_cap_t(m, "CapInh:\t", &cap_inheritable); + render_cap_t(m, "CapPrm:\t", &cap_permitted); + render_cap_t(m, "CapEff:\t", &cap_effective); + render_cap_t(m, "CapBnd:\t", &cap_bset); +} + +static inline void task_seccomp(struct seq_file *m, struct task_struct *p) +{ +#ifdef CONFIG_SECCOMP + seq_printf(m, "Seccomp:\t%d\n", p->seccomp.mode); +#endif +} + +static inline void task_context_switch_counts(struct seq_file *m, + struct task_struct *p) +{ + seq_printf(m, "voluntary_ctxt_switches:\t%lu\n" + "nonvoluntary_ctxt_switches:\t%lu\n", + p->nvcsw, + p->nivcsw); +} + +static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) +{ + seq_puts(m, "Cpus_allowed:\t"); + seq_cpumask(m, &task->cpus_allowed); + seq_putc(m, '\n'); + seq_puts(m, "Cpus_allowed_list:\t"); + seq_cpumask_list(m, &task->cpus_allowed); + seq_putc(m, '\n'); +} + +static int get_proc_cmdline(struct mm_struct *mm, char *buffer) +{ + int res, i; + unsigned int len; + + len = mm->arg_end - mm->arg_start; + + if (len > PAGE_SIZE) + len = PAGE_SIZE; + + res = access_process_vm(current, mm->arg_start, buffer, len, 0); + + /* If the nul at the end of args has been overwritten, then + * assume application is using setproctitle(3). + */ + if (res > 0 && buffer[res-1] != '\0' && len < PAGE_SIZE) { + len = strnlen(buffer, res); + if (len < res) { + res = len; + } else { + len = mm->env_end - mm->env_start; + if (len > PAGE_SIZE - res) + len = PAGE_SIZE - res; + res += access_process_vm(current, mm->env_start, + buffer+res, len, 0); + res = strnlen(buffer, res); + } + } + + for (i = 0; i < res - 1; i++) + if (buffer[i] == '\0') + buffer[i] = ' '; + + return res; +} + +static char *get_proc_exe(struct mm_struct *mm) +{ + struct file *exe_file; + struct path exe_path; + char tmp[80], *exepathname; + + exe_file = get_mm_exe_file(mm); + if (!exe_file) + return NULL; + + exe_path = exe_file->f_path; + path_get(&exe_file->f_path); + fput(exe_file); + + exepathname = d_path(&exe_path, tmp, sizeof(tmp)); + path_put(&exe_path); + + return exepathname; +} + +static void get_task_status(struct mm_struct *mm, struct task_struct *task, + char *buf, int size) +{ + struct seq_file m; + struct pid_namespace *ns = task_active_pid_ns(task); + struct pid *pid = get_pid(task_tgid(task)); + + memset(&m, 0, sizeof(m)); + m.buf = buf; + m.size = size; + + task_name(&m, task); + task_state(&m, ns, pid, task); + + if (mm) + task_mem(&m, mm); + + task_sig(&m, task); + task_cap(&m, task); + task_seccomp(&m, task); + task_cpus_allowed(&m, task); + cpuset_task_status_allowed(&m, task); + task_context_switch_counts(&m, task); +} + +int scm_get_current_procinfo(char **procinfo) +{ + int res = 0; + unsigned int len; + char *pos; + char *buf_cmdline = NULL; + char *buf_status = NULL; + struct mm_struct *mm; + int comm_len = strlen(current->comm); + static char *str_comm = "COMM="; + static char *str_cmdline = "CMDLINE="; + static char *str_exe = "EXE="; + static char *str_status = "STATUS="; + char *exepathname; + + *procinfo = NULL; + + buf_cmdline = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf_cmdline) + return -ENOMEM; + + buf_status = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf_status) { + res = -ENOMEM; + goto out; + } + memset(buf_status, 0, PAGE_SIZE); + + mm = get_task_mm(current); + if (!mm) + goto out; + if (!mm->arg_end) + goto out_mm; /* Shh! No looking before we're done */ + + res = get_proc_cmdline(mm, buf_cmdline); + + exepathname = get_proc_exe(mm); + if (exepathname == NULL) + goto out_mm; + + get_task_status(mm, current, buf_status, PAGE_SIZE); + + /* strlen(comm) + \0 + len of cmdline */ + len = strlen(str_comm) + comm_len + 1; + if (res) + len += strlen(str_cmdline) + res + 1; + if (!IS_ERR(exepathname)) + len += strlen(str_exe) + strlen(exepathname) + 1; + if (strlen(buf_status) > 0) + len += strlen(str_status) + strlen(buf_status); + + *procinfo = kmalloc(len, GFP_KERNEL); + if (!*procinfo) { + res = -ENOMEM; + goto out_mm; + } + + pos = *procinfo; + pos = strcpy(*procinfo, str_comm) + strlen(str_comm); + pos = memcpy(pos, current->comm, comm_len + 1) + comm_len + 1; + + if (res > 0) { + pos = strcpy(pos, str_cmdline) + strlen(str_cmdline); + pos = memcpy(pos, buf_cmdline, res) + res; + } + + if (!IS_ERR(exepathname)) { + pos = strcpy(pos, str_exe) + strlen(str_exe); + pos = strcpy(pos, exepathname) + strlen(exepathname); + pos = strcpy(pos + 1, "") /*+ 1*/; + } + + if (strlen(buf_status) > 0) { + pos = strcpy(pos, str_status) + strlen(str_status); + pos = strcpy(pos, buf_status) + strlen(buf_status); + } + + res = len; + +out_mm: + mmput(mm); +out: + kfree(buf_cmdline); + kfree(buf_status); + return res; +} +EXPORT_SYMBOL(scm_get_current_procinfo); diff --git a/net/core/sock.c b/net/core/sock.c index 026e01f..1099e19 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -828,6 +828,13 @@ set_rcvbuf: clear_bit(SOCK_PASSCRED, &sock->flags); break; + case SO_PASSPROC: + if (valbool) + set_bit(SOCK_PASSPROC, &sock->flags); + else + clear_bit(SOCK_PASSPROC, &sock->flags); + break; + case SO_TIMESTAMP: case SO_TIMESTAMPNS: if (valbool) { @@ -1142,6 +1149,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val = !!test_bit(SOCK_PASSCRED, &sock->flags); break; + case SO_PASSPROC: + v.val = !!test_bit(SOCK_PASSPROC, &sock->flags); + break; + case SO_PEERCRED: { struct ucred peercred; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 7b9114e..d524ab0 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1360,9 +1360,15 @@ static void unix_destruct_scm(struct sk_buff *skb) struct scm_cookie scm; memset(&scm, 0, sizeof(scm)); scm.pid = UNIXCB(skb).pid; + if (UNIXCB(skb).scm) { + scm.procinfo.procinfo = UNIXSCM(skb).procinfo; + scm.procinfo.len = UNIXSCM(skb).procinfo_len; + } if (UNIXCB(skb).fp) unix_detach_fds(&scm, skb); + kfree(UNIXCB(skb).scm); + /* Alas, it calls VFS */ /* So fscking what? fput() had been SMP-safe since the last Summer */ scm_destroy(&scm); @@ -1409,6 +1415,13 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen { int err = 0; + if (!UNIXCB(skb).scm) { + UNIXCB(skb).scm = kmalloc(sizeof(struct unix_skb_parms_scm), + GFP_KERNEL); + if (!UNIXCB(skb).scm) + return -ENOMEM; + } + UNIXCB(skb).pid = get_pid(scm->pid); UNIXCB(skb).uid = scm->creds.uid; UNIXCB(skb).gid = scm->creds.gid; @@ -1416,6 +1429,15 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen if (scm->fp && send_fds) err = unix_attach_fds(scm, skb); + UNIXSCM(skb).procinfo = NULL; + if (scm->procinfo.procinfo) { + UNIXSCM(skb).procinfo_len = scm->procinfo.len; + UNIXSCM(skb).procinfo = kmemdup(scm->procinfo.procinfo, + scm->procinfo.len, GFP_KERNEL); + if (!UNIXSCM(skb).procinfo) + return -ENOMEM; + } + skb->destructor = unix_destruct_scm; return err; } @@ -1438,6 +1460,22 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock, } } + +/* Include procinfo if source or destination socket + * asserted SOCK_PASSPROC. + */ +static void maybe_add_procinfo(struct sk_buff *skb, const struct socket *sock, + const struct sock *other, int len, + char *procinfo) +{ + if (test_bit(SOCK_PASSPROC, &sock->flags) || + !other->sk_socket || + test_bit(SOCK_PASSPROC, &other->sk_socket->flags)) { + UNIXSCM(skb).procinfo_len = len; + UNIXSCM(skb).procinfo = procinfo; + } +} + /* * Send AF_UNIX data. */ @@ -1459,6 +1497,8 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, struct scm_cookie tmp_scm; int max_level; int data_len = 0; + char *procinfo = NULL; + int procinfo_len = 0; if (NULL == siocb->scm) siocb->scm = &tmp_scm; @@ -1540,6 +1580,12 @@ restart: goto out_free; } + if (test_bit(SOCK_PASSPROC, &sock->flags) || + !other->sk_socket || + test_bit(SOCK_PASSPROC, &other->sk_socket->flags)) { + procinfo_len = scm_get_current_procinfo(&procinfo); + } + unix_state_lock(other); err = -EPERM; if (!unix_may_send(sk, other)) @@ -1600,6 +1646,7 @@ restart: if (sock_flag(other, SOCK_RCVTSTAMP)) __net_timestamp(skb); maybe_add_creds(skb, sock, other); + maybe_add_procinfo(skb, sock, other, procinfo_len, procinfo); skb_queue_tail(&other->sk_receive_queue, skb); if (max_level > unix_sk(other)->recursion_level) unix_sk(other)->recursion_level = max_level; @@ -1638,6 +1685,8 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, bool fds_sent = false; int max_level; int data_len; + char *procinfo = NULL; + int procinfo_len = 0; if (NULL == siocb->scm) siocb->scm = &tmp_scm; @@ -1701,6 +1750,12 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, goto out_err; } + if (test_bit(SOCK_PASSPROC, &sock->flags) || + !other->sk_socket || + test_bit(SOCK_PASSPROC, &other->sk_socket->flags)) { + procinfo_len = scm_get_current_procinfo(&procinfo); + } + unix_state_lock(other); if (sock_flag(other, SOCK_DEAD) || @@ -1708,6 +1763,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, goto pipe_err_free; maybe_add_creds(skb, sock, other); + maybe_add_procinfo(skb, sock, other, procinfo_len, procinfo); skb_queue_tail(&other->sk_receive_queue, skb); if (max_level > unix_sk(other)->recursion_level) unix_sk(other)->recursion_level = max_level; @@ -1837,6 +1893,12 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, memset(&tmp_scm, 0, sizeof(tmp_scm)); } scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid); + if (UNIXCB(skb).scm && UNIXSCM(skb).procinfo) + scm_set_procinfo(siocb->scm, + kmemdup(UNIXSCM(skb).procinfo, + UNIXSCM(skb).procinfo_len, + GFP_KERNEL), + UNIXSCM(skb).procinfo_len); unix_set_secdata(siocb->scm, skb); if (!(flags & MSG_PEEK)) { @@ -2023,6 +2085,14 @@ again: check_creds = 1; } + if (UNIXCB(skb).scm && UNIXSCM(skb).procinfo) { + scm_set_procinfo(siocb->scm, + kmemdup(UNIXSCM(skb).procinfo, + UNIXSCM(skb).procinfo_len, + GFP_KERNEL), + UNIXSCM(skb).procinfo_len); + } + /* Copy address just once */ if (sunaddr) { unix_copy_addr(msg, skb->sk); -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists