|
@@ -644,4 +644,50 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
|
+
|
|
|
+#ifdef __ARCH_WANT_COMPAT_SYS_PTRACE
|
|
|
+asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
|
|
|
+ compat_long_t addr, compat_long_t data)
|
|
|
+{
|
|
|
+ struct task_struct *child;
|
|
|
+ long ret;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * This lock_kernel fixes a subtle race with suid exec
|
|
|
+ */
|
|
|
+ lock_kernel();
|
|
|
+ if (request == PTRACE_TRACEME) {
|
|
|
+ ret = ptrace_traceme();
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ child = ptrace_get_task_struct(pid);
|
|
|
+ if (IS_ERR(child)) {
|
|
|
+ ret = PTR_ERR(child);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (request == PTRACE_ATTACH) {
|
|
|
+ ret = ptrace_attach(child);
|
|
|
+ /*
|
|
|
+ * Some architectures need to do book-keeping after
|
|
|
+ * a ptrace attach.
|
|
|
+ */
|
|
|
+ if (!ret)
|
|
|
+ arch_ptrace_attach(child);
|
|
|
+ goto out_put_task_struct;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = ptrace_check_attach(child, request == PTRACE_KILL);
|
|
|
+ if (!ret)
|
|
|
+ ret = compat_arch_ptrace(child, request, addr, data);
|
|
|
+
|
|
|
+ out_put_task_struct:
|
|
|
+ put_task_struct(child);
|
|
|
+ out:
|
|
|
+ unlock_kernel();
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#endif /* __ARCH_WANT_COMPAT_SYS_PTRACE */
|
|
|
+
|
|
|
#endif /* CONFIG_COMPAT */
|