aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Zapolskiy <vzapolskiy@gmail.com>2011-07-15 13:45:18 -0400
committerOleg Nesterov <oleg@redhat.com>2011-07-18 15:38:33 -0400
commitf701e5b73a1a79ea62ffd45d9e2bed4c7d5c1fd2 (patch)
tree10940ea680a1c8c69cbd9f9aa9aca23a1199aa0e
parentd184d6eb1dc3c9869e25a8e422be5c55ab0db4ac (diff)
connector: add an event for monitoring process tracers
This change adds a procfs connector event, which is emitted on every successful process tracer attach or detach. If some process connects to other one, kernelspace connector reports process id and thread group id of both these involved processes. On disconnection null process id is returned. Such an event allows to create a simple automated userspace mechanism to be aware about processes connecting to others, therefore predefined process policies can be applied to them if needed. Note, a detach signal is emitted only in case, if a tracer process explicitly executes PTRACE_DETACH request. In other cases like tracee or tracer exit detach event from proc connector is not reported. Signed-off-by: Vladimir Zapolskiy <vzapolskiy@gmail.com> Acked-by: Evgeniy Polyakov <zbr@ioremap.net> Cc: David S. Miller <davem@davemloft.net> Signed-off-by: Oleg Nesterov <oleg@redhat.com>
-rw-r--r--drivers/connector/cn_proc.c35
-rw-r--r--include/linux/cn_proc.h13
-rw-r--r--kernel/ptrace.c7
3 files changed, 54 insertions, 1 deletions
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index 2b46a7efa0ac..281902d3f7ec 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -28,6 +28,7 @@
28#include <linux/init.h> 28#include <linux/init.h>
29#include <linux/connector.h> 29#include <linux/connector.h>
30#include <linux/gfp.h> 30#include <linux/gfp.h>
31#include <linux/ptrace.h>
31#include <asm/atomic.h> 32#include <asm/atomic.h>
32#include <asm/unaligned.h> 33#include <asm/unaligned.h>
33 34
@@ -166,6 +167,40 @@ void proc_sid_connector(struct task_struct *task)
166 cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); 167 cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
167} 168}
168 169
170void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
171{
172 struct cn_msg *msg;
173 struct proc_event *ev;
174 struct timespec ts;
175 __u8 buffer[CN_PROC_MSG_SIZE];
176 struct task_struct *tracer;
177
178 if (atomic_read(&proc_event_num_listeners) < 1)
179 return;
180
181 msg = (struct cn_msg *)buffer;
182 ev = (struct proc_event *)msg->data;
183 get_seq(&msg->seq, &ev->cpu);
184 ktime_get_ts(&ts); /* get high res monotonic timestamp */
185 put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
186 ev->what = PROC_EVENT_PTRACE;
187 ev->event_data.ptrace.process_pid = task->pid;
188 ev->event_data.ptrace.process_tgid = task->tgid;
189 if (ptrace_id == PTRACE_ATTACH) {
190 ev->event_data.ptrace.tracer_pid = current->pid;
191 ev->event_data.ptrace.tracer_tgid = current->tgid;
192 } else if (ptrace_id == PTRACE_DETACH) {
193 ev->event_data.ptrace.tracer_pid = 0;
194 ev->event_data.ptrace.tracer_tgid = 0;
195 } else
196 return;
197
198 memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
199 msg->ack = 0; /* not used */
200 msg->len = sizeof(*ev);
201 cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
202}
203
169void proc_exit_connector(struct task_struct *task) 204void proc_exit_connector(struct task_struct *task)
170{ 205{
171 struct cn_msg *msg; 206 struct cn_msg *msg;
diff --git a/include/linux/cn_proc.h b/include/linux/cn_proc.h
index 47dac5ea8d3a..12c517b51ca2 100644
--- a/include/linux/cn_proc.h
+++ b/include/linux/cn_proc.h
@@ -53,6 +53,7 @@ struct proc_event {
53 PROC_EVENT_UID = 0x00000004, 53 PROC_EVENT_UID = 0x00000004,
54 PROC_EVENT_GID = 0x00000040, 54 PROC_EVENT_GID = 0x00000040,
55 PROC_EVENT_SID = 0x00000080, 55 PROC_EVENT_SID = 0x00000080,
56 PROC_EVENT_PTRACE = 0x00000100,
56 /* "next" should be 0x00000400 */ 57 /* "next" should be 0x00000400 */
57 /* "last" is the last process event: exit */ 58 /* "last" is the last process event: exit */
58 PROC_EVENT_EXIT = 0x80000000 59 PROC_EVENT_EXIT = 0x80000000
@@ -95,6 +96,13 @@ struct proc_event {
95 __kernel_pid_t process_tgid; 96 __kernel_pid_t process_tgid;
96 } sid; 97 } sid;
97 98
99 struct ptrace_proc_event {
100 __kernel_pid_t process_pid;
101 __kernel_pid_t process_tgid;
102 __kernel_pid_t tracer_pid;
103 __kernel_pid_t tracer_tgid;
104 } ptrace;
105
98 struct exit_proc_event { 106 struct exit_proc_event {
99 __kernel_pid_t process_pid; 107 __kernel_pid_t process_pid;
100 __kernel_pid_t process_tgid; 108 __kernel_pid_t process_tgid;
@@ -109,6 +117,7 @@ void proc_fork_connector(struct task_struct *task);
109void proc_exec_connector(struct task_struct *task); 117void proc_exec_connector(struct task_struct *task);
110void proc_id_connector(struct task_struct *task, int which_id); 118void proc_id_connector(struct task_struct *task, int which_id);
111void proc_sid_connector(struct task_struct *task); 119void proc_sid_connector(struct task_struct *task);
120void proc_ptrace_connector(struct task_struct *task, int which_id);
112void proc_exit_connector(struct task_struct *task); 121void proc_exit_connector(struct task_struct *task);
113#else 122#else
114static inline void proc_fork_connector(struct task_struct *task) 123static inline void proc_fork_connector(struct task_struct *task)
@@ -124,6 +133,10 @@ static inline void proc_id_connector(struct task_struct *task,
124static inline void proc_sid_connector(struct task_struct *task) 133static inline void proc_sid_connector(struct task_struct *task)
125{} 134{}
126 135
136static inline void proc_ptrace_connector(struct task_struct *task,
137 int ptrace_id)
138{}
139
127static inline void proc_exit_connector(struct task_struct *task) 140static inline void proc_exit_connector(struct task_struct *task)
128{} 141{}
129#endif /* CONFIG_PROC_EVENTS */ 142#endif /* CONFIG_PROC_EVENTS */
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index d7ccc79454f5..9de3ecfd20f9 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -23,6 +23,7 @@
23#include <linux/uaccess.h> 23#include <linux/uaccess.h>
24#include <linux/regset.h> 24#include <linux/regset.h>
25#include <linux/hw_breakpoint.h> 25#include <linux/hw_breakpoint.h>
26#include <linux/cn_proc.h>
26 27
27 28
28static int ptrace_trapping_sleep_fn(void *flags) 29static int ptrace_trapping_sleep_fn(void *flags)
@@ -305,9 +306,12 @@ unlock_tasklist:
305unlock_creds: 306unlock_creds:
306 mutex_unlock(&task->signal->cred_guard_mutex); 307 mutex_unlock(&task->signal->cred_guard_mutex);
307out: 308out:
308 if (!retval) 309 if (!retval) {
309 wait_on_bit(&task->jobctl, JOBCTL_TRAPPING_BIT, 310 wait_on_bit(&task->jobctl, JOBCTL_TRAPPING_BIT,
310 ptrace_trapping_sleep_fn, TASK_UNINTERRUPTIBLE); 311 ptrace_trapping_sleep_fn, TASK_UNINTERRUPTIBLE);
312 proc_ptrace_connector(task, PTRACE_ATTACH);
313 }
314
311 return retval; 315 return retval;
312} 316}
313 317
@@ -415,6 +419,7 @@ static int ptrace_detach(struct task_struct *child, unsigned int data)
415 } 419 }
416 write_unlock_irq(&tasklist_lock); 420 write_unlock_irq(&tasklist_lock);
417 421
422 proc_ptrace_connector(child, PTRACE_DETACH);
418 if (unlikely(dead)) 423 if (unlikely(dead))
419 release_task(child); 424 release_task(child);
420 425