diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h
index a52a5688418e5db69f713e6e12e8a64a577f3b22..6319d0e4f15f40161fb5a2692ef1ed435fbca037 100644
--- a/include/linux/bpf_types.h
+++ b/include/linux/bpf_types.h
@@ -77,6 +77,9 @@ BPF_PROG_TYPE(BPF_PROG_TYPE_LSM, lsm,
 	       void *, void *)
 #endif /* CONFIG_BPF_LSM */
 #endif
+#ifdef CONFIG_BPFTASK_SYSCALL
+BPF_PROG_TYPE(BPF_PROG_TYPE_TASK, task, void *, void *) /* TODO: What are arg2..arg4? */
+#endif
 
 BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY, array_map_ops)
 BPF_MAP_TYPE(BPF_MAP_TYPE_PERCPU_ARRAY, percpu_array_map_ops)
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 14aa88fe7078e675d63a232edfc4e5064878aaee..55a84700d6f7dde920da6a12c0b17adc2567a488 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -970,7 +970,7 @@ asmlinkage long sys_getrandom(char __user *buf, size_t count,
 			      unsigned int flags);
 asmlinkage long sys_memfd_create(const char __user *uname_ptr, unsigned int flags);
 asmlinkage long sys_bpf(int cmd, union bpf_attr *attr, unsigned int size);
-asmlinkage long sys_bpftask(const char __user *pathname, const char __user *filename, int ofd, char __user *buf);
+asmlinkage long sys_bpftask(int prog_fd, void __user *arg);
 asmlinkage long sys_execveat(int dfd, const char __user *filename,
 			const char __user *const __user *argv,
 			const char __user *const __user *envp, int flags);
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index b6238b2209b71a3d9094b7eec1eb67130175ed62..aa4a630b9a995b41c8d3d16b7c6e28782c731774 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -197,6 +197,7 @@ enum bpf_prog_type {
 	BPF_PROG_TYPE_EXT,
 	BPF_PROG_TYPE_LSM,
 	BPF_PROG_TYPE_SK_LOOKUP,
+	BPF_PROG_TYPE_TASK,
 };
 
 enum bpf_attach_type {
diff --git a/kernel/bpf/task.c b/kernel/bpf/task.c
index 8d4180a462f30263ebf5e056e6e2982cdbb13b8d..75677bdc811f430e938dff8e302f50540f909b94 100644
--- a/kernel/bpf/task.c
+++ b/kernel/bpf/task.c
@@ -6,6 +6,7 @@
 #include <linux/errname.h>
 #include <linux/dirent.h>
 #include <linux/vmalloc.h>
+#include <linux/filter.h>
 
 #define BUF_SIZE 1024
 
@@ -199,15 +200,28 @@ static long find(const char __user *pathname_user, const char __user *filename_u
 	return err;
 }
 
-SYSCALL_DEFINE4(bpftask, const char __user *, pathname, const char __user *, filename, int, ofd, char __user *, buf_user)
+/* dummy _ops. The verifier will operate on target program's ops. */
+const struct bpf_verifier_ops task_verifier_ops = {
+};
+const struct bpf_prog_ops task_prog_ops = {
+};
+
+SYSCALL_DEFINE2(bpftask, int, prog_fd, void *, arg)
 {
-	void *vm = vmalloc(1);
-	void *vmuser = vmalloc_user(1);
-	printk("bpftask, %p ?= %p, buf_user = %p, vmalloc = %p, vmalloc_user = %p\n", compat_alloc_user_space(16), compat_alloc_user_space(16), buf_user, vm, vmuser);
+	int ret = 0;
 
 	/* The same check as in bpf/syscall.c */
 	if (sysctl_unprivileged_bpf_disabled && !bpf_capable())
 		return -EPERM;
 
-	return find(pathname, filename, ofd, buf_user);
+	struct bpf_prog *prog = bpf_prog_get(prog_fd);
+	if (IS_ERR(prog)) {
+		ret = PTR_ERR(prog);
+		goto out;
+	}
+	ret = BPF_PROG_RUN(prog, NULL);
+
+	bpf_prog_put(prog);
+out:
+	return ret;
 }
diff --git a/scripts/bpf_helpers_doc.py b/scripts/bpf_helpers_doc.py
index 5bfa448b4704bfd69683035f22d08180598119cf..535f81e93be642495a4e675d9ffc69f35de1b000 100755
--- a/scripts/bpf_helpers_doc.py
+++ b/scripts/bpf_helpers_doc.py
@@ -472,6 +472,8 @@ class PrinterHelpers(Printer):
             'struct tcp_request_sock',
             'struct udp6_sock',
             'struct task_struct',
+        # Added for bpftask:
+        'struct bpf_redir_neigh', 'struct linux_binprm', 'struct path', 'struct btf_ptr', 'struct inode', 'struct socket', 'struct file'
     }
     mapped_types = {
             'u8': '__u8',
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index b6238b2209b71a3d9094b7eec1eb67130175ed62..aa4a630b9a995b41c8d3d16b7c6e28782c731774 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -197,6 +197,7 @@ enum bpf_prog_type {
 	BPF_PROG_TYPE_EXT,
 	BPF_PROG_TYPE_LSM,
 	BPF_PROG_TYPE_SK_LOOKUP,
+	BPF_PROG_TYPE_TASK,
 };
 
 enum bpf_attach_type {
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index e493d6048143f0cc1ed3b7bef32ee6606b556974..51da2f64c67d3cf9aa4ad406a185f8159061c1e9 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -6995,6 +6995,7 @@ static const struct bpf_sec_def section_defs[] = {
 	BPF_PROG_SEC("struct_ops",		BPF_PROG_TYPE_STRUCT_OPS),
 	BPF_EAPROG_SEC("sk_lookup/",		BPF_PROG_TYPE_SK_LOOKUP,
 						BPF_SK_LOOKUP),
+	BPF_PROG_SEC("task", BPF_PROG_TYPE_TASK),
 };
 
 #undef BPF_PROG_SEC_IMPL
diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c
index 5a3d3f07840816597c4c8c35a767e77e79fa4609..2972055ecde80a3e2874382cc75330f685aa907f 100644
--- a/tools/lib/bpf/libbpf_probes.c
+++ b/tools/lib/bpf/libbpf_probes.c
@@ -112,6 +112,7 @@ probe_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns,
 	case BPF_PROG_TYPE_STRUCT_OPS:
 	case BPF_PROG_TYPE_EXT:
 	case BPF_PROG_TYPE_LSM:
+	case BPF_PROG_TYPE_TASK:
 	default:
 		break;
 	}