[CRIU] [PATCH] [RFC] ptrace: peek and send siginfo

Andrey Vagin avagin at openvz.org
Mon Nov 26 16:41:40 EST 2012


This functionality is required for checkpointing and restoring
pending signals.

This patch adds two ptrace commands:
* to get siginfo for any signal with a specified sequence number
* to add a siginfo to a process

Could you comment this approach?

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 include/linux/signal.h      |  2 ++
 include/uapi/linux/ptrace.h |  3 +++
 kernel/ptrace.c             | 16 ++++++++++++++++
 kernel/signal.c             | 46 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 67 insertions(+)

diff --git a/include/linux/signal.h b/include/linux/signal.h
index e19a011..605f999 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -239,6 +239,8 @@ struct pt_regs;
 extern int next_signal(struct sigpending *pending, sigset_t *mask);
 extern int do_send_sig_info(int sig, struct siginfo *info,
 				struct task_struct *p, bool group);
+extern int do_peek_siginfo(int sig, siginfo_t *info,
+				struct task_struct *p, s16 nr);
 extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p);
 extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
 extern long do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig,
diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h
index 1ef6c05..47ff821 100644
--- a/include/uapi/linux/ptrace.h
+++ b/include/uapi/linux/ptrace.h
@@ -52,6 +52,9 @@
 #define PTRACE_INTERRUPT	0x4207
 #define PTRACE_LISTEN		0x4208
 
+#define PTRACE_PEEK_SIGINFO	0x4209
+#define PTRACE_SEND_SIGINFO	0x420a
+
 /* Wait extended result codes for the above trace options.  */
 #define PTRACE_EVENT_FORK	1
 #define PTRACE_EVENT_VFORK	2
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 1f5e55d..22111b6 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -707,6 +707,22 @@ int ptrace_request(struct task_struct *child, long request,
 			ret = ptrace_setsiginfo(child, &siginfo);
 		break;
 
+#ifdef CONFIG_CHECKPOINT_RESTORE
+	case PTRACE_PEEK_SIGINFO:
+		ret = do_peek_siginfo(addr & 0xffff, &siginfo, child, addr >> 16);
+		if (!ret)
+			ret = copy_siginfo_to_user(datavp, &siginfo);
+		break;
+
+	case PTRACE_SEND_SIGINFO:
+		if (copy_from_user(&siginfo, datavp, sizeof siginfo))
+			ret = -EFAULT;
+		else
+			ret = do_send_sig_info(siginfo.si_signo,
+						&siginfo, child, addr ? 1 : 0);
+		break;
+#endif
+
 	case PTRACE_INTERRUPT:
 		/*
 		 * Stop tracee without any side-effect on signal or job
diff --git a/kernel/signal.c b/kernel/signal.c
index 0af8868..172c269 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -535,6 +535,52 @@ unblock_all_signals(void)
 	spin_unlock_irqrestore(&current->sighand->siglock, flags);
 }
 
+/*
+ * Get siginfo with a sequence number nr.
+ *
+ * If nr is positive, a signal will be picked of a shared queue.
+ * If nr is negative, a signal will be picked of a local queue.
+ */
+int do_peek_siginfo(int sig, siginfo_t *info, struct task_struct *tsk, s16 nr)
+{
+	unsigned long flags;
+	struct sigqueue *q;
+	struct sigpending *p;
+	int i = 0, ret = -ESRCH;
+
+	if (nr == 0)
+		return -EINVAL;
+
+	if (!lock_task_sighand(tsk, &flags))
+		return ret;
+
+	if (nr > 0) {
+		p = &tsk->signal->shared_pending;
+	} else {
+		nr = -nr;
+		p  = &tsk->pending;
+	}
+
+	list_for_each_entry(q, &p->list, list) {
+		if (q->info.si_signo == sig) {
+			i++;
+			if (i == nr)
+				break;
+		}
+	}
+
+	if (i != nr)
+		goto unlock;
+
+	copy_siginfo(info, &q->info);
+	ret = 0;
+
+unlock:
+	unlock_task_sighand(tsk, &flags);
+
+	return ret;
+}
+
 static void collect_signal(int sig, struct sigpending *list, siginfo_t *info)
 {
 	struct sigqueue *q, *first = NULL;
-- 
1.7.11.7



More information about the CRIU mailing list