*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
@@ -2938,7 +2964,8 @@ union bpf_attr {
FN(probe_read_user), \
FN(probe_read_kernel), \
FN(probe_read_user_str), \
- FN(probe_read_kernel_str),
+ FN(probe_read_kernel_str), \
+ FN(get_fd_path),
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index e5ef4ae9edb5..43a6aa6ad967 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -762,6 +762,71 @@ static const struct bpf_func_proto bpf_send_signal_proto = {
.arg1_type = ARG_ANYTHING,
};
+BPF_CALL_3(bpf_get_fd_path, char *, dst, u32, size, int, fd)
+{
+ int ret = -EBADF;
+ struct file *f;
+ char *p;
+
+ /* Ensure we're in user context which is safe for the helper to
+ * run. This helper has no business in a kthread.
+ */
+ if (unlikely(in_interrupt() ||
+ current->flags & (PF_KTHREAD | PF_EXITING))) {
+ ret = -EPERM;
+ goto error;
+ }
+
+ /* Use fget_raw instead of fget to support O_PATH, and it doesn't
+ * have any sleepable code, so it's ok to be here.
+ */
+ f = fget_raw(fd);
+ if (!f)
+ goto error;
+
+ /* For unmountable pseudo filesystem, it seems to have no meaning
+ * to get their fake paths as they don't have path, and to be no
+ * way to validate this function pointer can be always safe to call
+ * in the current context.
+ */
+ if (f->f_path.dentry->d_op && f->f_path.dentry->d_op->d_dname) {
+ ret = -EINVAL;
+ fput(f);
+ goto error;
+ }
+
+ /* After filter unmountable pseudo filesytem, d_path won't call
+ * dentry->d_op->d_name(), the normally path doesn't have any
+ * sleepable code, and despite it uses the current macro to get
+ * fs_struct (current->fs), we've already ensured we're in user
+ * context, so it's ok to be here.
+ */
+ p = d_path(&f->f_path, dst, size);
+ if (IS_ERR(p)) {
+ ret = PTR_ERR(p);
+ fput(f);
+ goto error;
+ }
+
+ ret = strlen(p) + 1;
+ memmove(dst, p, ret);
+ fput(f);
+ return ret;
+
+error:
+ memset(dst, '0', size);