diff options
author | chunx <chunx@nvidia.com> | 2013-07-05 11:42:05 +0800 |
---|---|---|
committer | Gabby Lee <galee@nvidia.com> | 2013-07-30 03:20:49 -0700 |
commit | 5dcfe4f561bd8d1767e0938dfd7565b2b7718478 (patch) | |
tree | 4b6e7776a488e4f132a8bd8a105b7111d6ca9ad8 /net | |
parent | 61129a28e27bd4c5f794aa9af6903fd8ba68c746 (diff) |
arm: tegra: tegratab: active-standby: add cmdline informatioin
into /proc/net/{tcp udp tcp6 udp6} files.
Get process's cmdline from a sock's corresponding inode pointer,
so that cmdline can't be used by Android active-standby app
to find the corresponding package name.
Bug 1185001
Change-Id: Idc8651e4bb85b8a152dfade9689a719f7d72687d
Signed-off-by: Chun Xu <chunx@nvidia.com>
Reviewed-on: http://git-master/r/253458
Tested-by: Jiukai Ma <jiukaim@nvidia.com>
Reviewed-by: Gabby Lee <galee@nvidia.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/sock.c | 133 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 19 | ||||
-rw-r--r-- | net/ipv4/udp.c | 15 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 13 | ||||
-rw-r--r-- | net/ipv6/udp.c | 13 | ||||
-rw-r--r-- | net/socket.c | 3 |
6 files changed, 181 insertions, 15 deletions
diff --git a/net/core/sock.c b/net/core/sock.c index 4b469e367923..29848fb3145f 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -87,6 +87,8 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. + * + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. */ #include <linux/capability.h> @@ -136,6 +138,8 @@ #include <net/tcp.h> #endif +#include <linux/eventpoll.h> + static DEFINE_MUTEX(proto_list_mutex); static LIST_HEAD(proto_list); @@ -2358,6 +2362,135 @@ void sk_common_release(struct sock *sk) } EXPORT_SYMBOL(sk_common_release); +char *sk_get_waiting_task_cmdline(struct sock *sk, char *cmdline) +{ + bool softirq_enabled = false; + int res = 0; + unsigned int len; + char *program_name = cmdline; + struct task_struct *task = NULL; + struct mm_struct *mm = NULL; + static char *apk_path_prefix = "/data/data"; + wait_queue_t *wq = NULL; + struct list_head *lh = NULL; + struct socket_wq *sk_wq = NULL; + wait_queue_func_t wait_func; + enum pid_type type; + struct pid *pid = NULL; + struct fown_struct *fown = NULL; + struct file *file; + + *program_name = '\0'; + + if (!sk || !sk->sk_wq) + goto out; + lh = sk->sk_wq->wait.task_list.next; + if (!wq_has_sleeper(sk->sk_wq)) { + sk_wq = sk->sk_wq; + if (sk_wq->fasync_list && sk_wq->fasync_list->fa_file) { + fown = &sk_wq->fasync_list->fa_file->f_owner; + pid = fown->pid; + type = fown->pid_type; + do_each_pid_task(pid, type, task) { + if (task) + break; + } while_each_pid_task(pid, type, task); + printk(KERN_DEBUG "Async wakeup process:%p\n", task); + } + } else { + lh = sk->sk_wq->wait.task_list.next; + wq = list_entry(lh, wait_queue_t, task_list); + + wait_func = wq->func; + printk(KERN_DEBUG "Wakeup function:%p\n", wait_func); + if (wait_func == pollwake) + task = ((struct poll_wqueues *) + (wq->private))->polling_task; + else if (wait_func == default_wake_function) + task = (struct task_struct *)(wq->private); + else if (wait_func == ep_poll_callback) + task = (struct task_struct *)(wq->private); + else if (wait_func == autoremove_wake_function) + task = (struct task_struct *)(wq->private); + else + printk(KERN_ERR "Unhandled wakeup:%p\n", wait_func); + + if (task) + task = get_thread_process(task); + } + +#ifdef CONFIG_EPOLL + if (!task) { + file = sk->sk_socket->file; + if (file) + task = get_epoll_file_task(file); + } +#endif + + if (!task && sk && sk->sk_socket) + task = SOCK_INODE(sk->sk_socket)->i_private; + + if (!task) { + printk(KERN_WARNING "Can't find a process for this sock.\n"); + goto out; + } + + mm = get_task_mm(task); + if (mm && mm->arg_end) { + len = mm->arg_end - mm->arg_start; + + if (len > PAGE_SIZE) + len = PAGE_SIZE; + + if (softirq_count()) { + softirq_enabled = true; + local_bh_enable(); + } + res = access_process_vm(task, mm->arg_start, cmdline, len, 0); + + if (res > 0 && cmdline[res-1] != '\0' && len < PAGE_SIZE) { + len = strnlen(cmdline, 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(task, + mm->env_start, cmdline+res, len, 0); + res = strnlen(cmdline, res); + } + } + if (softirq_enabled) + local_bh_disable(); + + if (res > PAGE_SIZE) + cmdline[PAGE_SIZE-1] = '\0'; + + len = strlen(apk_path_prefix); + if (!strncmp(apk_path_prefix, program_name, len)) + program_name += len; + else + program_name = strrchr(cmdline, '/'); + + if (program_name == NULL) + program_name = cmdline; + else + program_name++; + } + + if (mm) + mmput(mm); + + len = strlen(program_name); + snprintf(program_name + len, PAGE_SIZE-(program_name-cmdline)-len, + " %d %s", task->pid, task->comm); +out: + return program_name; +} +EXPORT_SYMBOL(sk_get_waiting_task_cmdline); + + #ifdef CONFIG_PROC_FS #define PROTO_INUSE_NR 64 /* should be enough for the first time */ struct prot_inuse { diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 76f50e1b53af..7883001feef0 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -48,6 +48,8 @@ * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind * a single port at the same time. + * + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. */ #define pr_fmt(fmt) "TCP: " fmt @@ -2434,6 +2436,9 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len) __u16 destp = ntohs(inet->inet_dport); __u16 srcp = ntohs(inet->inet_sport); int rx_queue; + unsigned long cmdline = __get_free_page(GFP_TEMPORARY); + if (cmdline == NULL) + return; if (icsk->icsk_pending == ICSK_TIME_RETRANS) { timer_active = 1; @@ -2458,7 +2463,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len) rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0); seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX " - "%08X %5d %8d %lu %d %pK %lu %lu %u %u %d%n", + "%08X %5d %8d %lu %d %pK %lu %lu %u %u %d %s%n", i, src, srcp, dest, destp, sk->sk_state, tp->write_seq - tp->snd_una, rx_queue, @@ -2474,7 +2479,10 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len) (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong, tp->snd_cwnd, tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh, + sk_get_waiting_task_cmdline(sk, cmdline), len); + + free_page(cmdline); } static void get_timewait4_sock(const struct inet_timewait_sock *tw, @@ -2508,9 +2516,10 @@ static int tcp4_seq_show(struct seq_file *seq, void *v) if (v == SEQ_START_TOKEN) { seq_printf(seq, "%-*s\n", TMPSZ - 1, - " sl local_address rem_address st tx_queue " - "rx_queue tr tm->when retrnsmt uid timeout " - "inode"); + " sl local_address rem_address st tx_queue " + "rx_queue tr tm->when retrnsmt uid timeout " + "inode " + "cmdline"); goto out; } st = seq->private; @@ -2527,7 +2536,7 @@ static int tcp4_seq_show(struct seq_file *seq, void *v) get_timewait4_sock(v, seq, st->num, &len); break; } - seq_printf(seq, "%*s\n", TMPSZ - 1 - len, ""); + seq_printf(seq, "\n"); out: return 0; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index fe141052a1be..b934e4d4baf3 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -75,6 +75,8 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. + * + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. */ #define pr_fmt(fmt) "UDP: " fmt @@ -2087,15 +2089,20 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f, __be32 src = inet->inet_rcv_saddr; __u16 destp = ntohs(inet->inet_dport); __u16 srcp = ntohs(inet->inet_sport); + unsigned long cmdline = __get_free_page(GFP_TEMPORARY); + if (cmdline == NULL) + return; seq_printf(f, "%5d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d%n", + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d %s%n", bucket, src, srcp, dest, destp, sp->sk_state, sk_wmem_alloc_get(sp), sk_rmem_alloc_get(sp), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), atomic_read(&sp->sk_refcnt), sp, - atomic_read(&sp->sk_drops), len); + atomic_read(&sp->sk_drops), + sk_get_waiting_task_cmdline(sp, cmdline), len); + free_page(cmdline); } int udp4_seq_show(struct seq_file *seq, void *v) @@ -2104,13 +2111,13 @@ int udp4_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "%-127s\n", " sl local_address rem_address st tx_queue " "rx_queue tr tm->when retrnsmt uid timeout " - "inode ref pointer drops"); + "inode ref pointer drops cmdline"); else { struct udp_iter_state *state = seq->private; int len; udp4_format_sock(v, seq, state->bucket, &len); - seq_printf(seq, "%*s\n", 127 - len, ""); + seq_printf(seq, "\n"); } return 0; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3889e0204183..ca25ad6ac69b 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -21,6 +21,8 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. + * + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. */ #include <linux/bottom_half.h> @@ -1945,6 +1947,9 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) const struct tcp_sock *tp = tcp_sk(sp); const struct inet_connection_sock *icsk = inet_csk(sp); const struct ipv6_pinfo *np = inet6_sk(sp); + unsigned long cmdline = __get_free_page(GFP_TEMPORARY); + if (cmdline == NULL) + return; dest = &np->daddr; src = &np->rcv_saddr; @@ -1967,7 +1972,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) seq_printf(seq, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %lu %lu %u %u %d\n", + "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %lu %lu %u %u %d %s\n", i, src->s6_addr32[0], src->s6_addr32[1], src->s6_addr32[2], src->s6_addr32[3], srcp, @@ -1987,8 +1992,10 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) jiffies_to_clock_t(icsk->icsk_ack.ato), (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong, tp->snd_cwnd, - tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh + tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh, + sk_get_waiting_task_cmdline(sp, cmdline) ); + free_page(cmdline); } static void get_timewait6_sock(struct seq_file *seq, @@ -2030,7 +2037,7 @@ static int tcp6_seq_show(struct seq_file *seq, void *v) "local_address " "remote_address " "st tx_queue rx_queue tr tm->when retrnsmt" - " uid timeout inode\n"); + " uid timeout inode cmdline\n"); goto out; } st = seq->private; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 37b0699e95e5..30a7d9aead8f 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -19,6 +19,8 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. + * + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. */ #include <linux/errno.h> @@ -1392,6 +1394,9 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket struct ipv6_pinfo *np = inet6_sk(sp); const struct in6_addr *dest, *src; __u16 destp, srcp; + unsigned long cmdline = __get_free_page(GFP_TEMPORARY); + if (cmdline == NULL) + return; dest = &np->daddr; src = &np->rcv_saddr; @@ -1399,7 +1404,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket srcp = ntohs(inet->inet_sport); seq_printf(seq, "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d\n", + "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d %s\n", bucket, src->s6_addr32[0], src->s6_addr32[1], src->s6_addr32[2], src->s6_addr32[3], srcp, @@ -1412,7 +1417,9 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket sock_i_uid(sp), 0, sock_i_ino(sp), atomic_read(&sp->sk_refcnt), sp, - atomic_read(&sp->sk_drops)); + atomic_read(&sp->sk_drops), + sk_get_waiting_task_cmdline(sp, cmdline)); + free_page(cmdline); } int udp6_seq_show(struct seq_file *seq, void *v) @@ -1423,7 +1430,7 @@ int udp6_seq_show(struct seq_file *seq, void *v) "local_address " "remote_address " "st tx_queue rx_queue tr tm->when retrnsmt" - " uid timeout inode ref pointer drops\n"); + " uid timeout inode ref pointer drops cmdline\n"); else udp6_sock_seq_show(seq, v, ((struct udp_iter_state *)seq->private)->bucket); return 0; diff --git a/net/socket.c b/net/socket.c index dab317686ad3..7ad9fd7d137f 100644 --- a/net/socket.c +++ b/net/socket.c @@ -868,6 +868,7 @@ static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb, msg->msg_iov = (struct iovec *)iov; msg->msg_iovlen = nr_segs; msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; + SOCK_INODE(sock)->i_private = get_thread_process(current); return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags); } @@ -1103,6 +1104,7 @@ static unsigned int sock_poll(struct file *file, poll_table *wait) * We can't return errors to poll, so it's either yes or no. */ sock = file->private_data; + SOCK_INODE(sock)->i_private = get_thread_process(current); return sock->ops->poll(file, sock, wait); } @@ -1349,6 +1351,7 @@ SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); if (retval < 0) goto out_release; + SOCK_INODE(sock)->i_private = get_thread_process(current); out: /* It may be already another descriptor 8) Not kernel problem. */ |