@@ -122,6 +122,18 @@ static inline long seccomp_get_metadata(struct task_struct *task,
return -EINVAL;
}
#endif /* CONFIG_SECCOMP_FILTER && CONFIG_CHECKPOINT_RESTORE */
+#if defined(CONFIG_SECCOMP_FILTER_EXTENDED) && defined(CONFIG_CHECKPOINT_RESTORE)
+extern long seccomp_get_filter_extended(struct task_struct *task,
+ unsigned long n,
+ void __user *data);
+#else
+static inline long seccomp_get_filter_extended(struct task_struct *task,
+ unsigned long n,
+ void __user *data)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_SECCOMP_FILTER_EXTENDED && CONFIG_CHECKPOINT_RESTORE */
#ifdef CONFIG_SECCOMP_CACHE_DEBUG
struct seq_file;
@@ -112,6 +112,8 @@ struct ptrace_rseq_configuration {
__u32 pad;
};
+#define PTRACE_SECCOMP_GET_FILTER_EXTENDED 0x4210
+
/*
* These values are stored in task->ptrace_message
* by tracehook_report_syscall_* to describe the current syscall-stop.
@@ -1247,6 +1247,10 @@ int ptrace_request(struct task_struct *child, long request,
break;
#endif
+ case PTRACE_SECCOMP_GET_FILTER_EXTENDED:
+ ret = seccomp_get_filter_extended(child, addr, datavp);
+ break;
+
default:
break;
}
@@ -2168,6 +2168,43 @@ long seccomp_get_metadata(struct task_struct *task,
}
#endif
+#if defined(CONFIG_SECCOMP_FILTER_EXTENDED) && defined(CONFIG_CHECKPOINT_RESTORE)
+long seccomp_get_filter_extended(struct task_struct *task,
+ unsigned long filter_off,
+ void __user *data)
+{
+ struct seccomp_filter *filter;
+ struct bpf_prog *prog;
+ long ret;
+
+ if (!capable(CAP_SYS_ADMIN) ||
+ current->seccomp.mode != SECCOMP_MODE_DISABLED) {
+ return -EACCES;
+ }
+
+ filter = get_nth_filter(task, filter_off);
+ if (IS_ERR(filter))
+ return PTR_ERR(filter);
+
+ if (bpf_prog_was_classic(filter->prog)) {
+ ret = -EMEDIUMTYPE;
+ goto out;
+ }
+ prog = bpf_prog_inc_not_zero(filter->prog);
+ if (IS_ERR(prog)) {
+ ret = PTR_ERR(prog);
+ goto out;
+ }
+
+ ret = bpf_prog_new_fd(filter->prog);
+ if (ret < 0)
+ bpf_prog_put(prog);
+out:
+ __put_seccomp_filter(filter);
+ return ret;
+}
+#endif
+
#ifdef CONFIG_SYSCTL
/* Human readable action names for friendly sysctl interaction */