summaryrefslogtreecommitdiff
path: root/kernel/bpf/syscall.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf/syscall.c')
-rw-r--r--kernel/bpf/syscall.c176
1 files changed, 138 insertions, 38 deletions
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index c7bc9ba9b331..90bc7230afa8 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -602,38 +602,45 @@ static bool can_alloc_pages(void)
!IS_ENABLED(CONFIG_PREEMPT_RT);
}
-static struct page *__bpf_alloc_page(int nid)
+struct page *bpf_alloc_page(int nid, bool sleepable)
{
- if (!can_alloc_pages())
+ if (!sleepable || !can_alloc_pages())
return alloc_pages_nolock(__GFP_ACCOUNT, nid, 0);
return alloc_pages_node(nid,
GFP_KERNEL | __GFP_ZERO | __GFP_ACCOUNT
- | __GFP_NOWARN,
+ | __GFP_NOWARN | __GFP_RETRY_MAYFAIL,
0);
}
-int bpf_map_alloc_pages(const struct bpf_map *map, int nid,
- unsigned long nr_pages, struct page **pages)
+void bpf_free_pages(struct llist_head *pages)
{
- unsigned long i, j;
+ struct llist_node *node;
+ struct page *page, *tmp;
+
+ node = llist_del_all(pages);
+ llist_for_each_entry_safe(page, tmp, node, pcp_llist)
+ free_pages_nolock(page, 0);
+}
+
+int bpf_alloc_pages(int nid, unsigned long nr_pages,
+ struct llist_head *pages, bool sleepable)
+{
+ unsigned long i;
struct page *pg;
- int ret = 0;
for (i = 0; i < nr_pages; i++) {
- pg = __bpf_alloc_page(nid);
-
- if (pg) {
- pages[i] = pg;
- continue;
- }
- for (j = 0; j < i; j++)
- free_pages_nolock(pages[j], 0);
- ret = -ENOMEM;
- break;
+ pg = bpf_alloc_page(nid, sleepable);
+ if (!pg)
+ goto free_pages;
+ llist_add(&pg->pcp_llist, pages);
}
- return ret;
+ return 0;
+
+free_pages:
+ bpf_free_pages(pages);
+ return -ENOMEM;
}
static int btf_field_cmp(const void *a, const void *b)
@@ -687,6 +694,7 @@ void btf_record_free(struct btf_record *rec)
case BPF_REFCOUNT:
case BPF_WORKQUEUE:
case BPF_TASK_WORK:
+ case BPF_RCU_HEAD:
/* Nothing to release */
break;
default:
@@ -741,6 +749,7 @@ struct btf_record *btf_record_dup(const struct btf_record *rec)
case BPF_REFCOUNT:
case BPF_WORKQUEUE:
case BPF_TASK_WORK:
+ case BPF_RCU_HEAD:
/* Nothing to acquire */
break;
default:
@@ -874,6 +883,7 @@ void bpf_obj_free_fields(const struct btf_record *rec, void *obj)
case BPF_LIST_NODE:
case BPF_RB_NODE:
case BPF_REFCOUNT:
+ case BPF_RCU_HEAD:
break;
default:
WARN_ON_ONCE(1);
@@ -954,6 +964,9 @@ void bpf_map_put(struct bpf_map *map)
/* bpf_map_free_id() must be called first */
bpf_map_free_id(map);
+ if (map->ops->map_free_pre_rcu)
+ map->ops->map_free_pre_rcu(map);
+
WARN_ON_ONCE(atomic64_read(&map->sleepable_refcnt));
/* RCU tasks trace grace period implies RCU grace period. */
if (READ_ONCE(map->free_after_mult_rcu_gp))
@@ -1277,7 +1290,7 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
map->record = btf_parse_fields(btf, value_type,
BPF_SPIN_LOCK | BPF_RES_SPIN_LOCK | BPF_TIMER | BPF_KPTR | BPF_LIST_HEAD |
BPF_RB_ROOT | BPF_REFCOUNT | BPF_WORKQUEUE | BPF_UPTR |
- BPF_TASK_WORK,
+ BPF_TASK_WORK | BPF_RCU_HEAD,
map->value_size);
if (!IS_ERR_OR_NULL(map->record)) {
int i;
@@ -1319,6 +1332,12 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
goto free_map_tab;
}
break;
+ case BPF_RCU_HEAD:
+ if (map->map_type != BPF_MAP_TYPE_ARRAY) {
+ ret = -EOPNOTSUPP;
+ goto free_map_tab;
+ }
+ break;
case BPF_KPTR_UNREF:
case BPF_KPTR_REF:
case BPF_KPTR_PERCPU:
@@ -2036,7 +2055,7 @@ int generic_map_delete_batch(struct bpf_map *map,
for (cp = 0; cp < max_count; cp++) {
err = -EFAULT;
- if (copy_from_user(key, keys + cp * map->key_size,
+ if (copy_from_user(key, keys + (size_t)cp * map->key_size,
map->key_size))
break;
@@ -2098,9 +2117,9 @@ int generic_map_update_batch(struct bpf_map *map, struct file *map_file,
for (cp = 0; cp < max_count; cp++) {
err = -EFAULT;
- if (copy_from_user(key, keys + cp * map->key_size,
+ if (copy_from_user(key, keys + (size_t)cp * map->key_size,
map->key_size) ||
- copy_from_user(value, values + cp * value_size, value_size))
+ copy_from_user(value, values + (size_t)cp * value_size, value_size))
break;
err = bpf_map_update_value(map, map_file, key, value,
@@ -2179,12 +2198,12 @@ int generic_map_lookup_batch(struct bpf_map *map,
if (err)
goto free_buf;
- if (copy_to_user(keys + cp * map->key_size, key,
+ if (copy_to_user(keys + (size_t)cp * map->key_size, key,
map->key_size)) {
err = -EFAULT;
goto free_buf;
}
- if (copy_to_user(values + cp * value_size, value, value_size)) {
+ if (copy_to_user(values + (size_t)cp * value_size, value, value_size)) {
err = -EFAULT;
goto free_buf;
}
@@ -2441,6 +2460,9 @@ static void __bpf_prog_put_rcu(struct rcu_head *rcu)
{
struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
+ btf_put(aux->btf);
+ kvfree(aux->jited_linfo);
+ kvfree(aux->linfo);
kvfree(aux->func_info);
kfree(aux->func_info_aux);
free_uid(aux->user);
@@ -2448,20 +2470,33 @@ static void __bpf_prog_put_rcu(struct rcu_head *rcu)
bpf_prog_free(aux->prog);
}
+/*
+ * Progs called from a trampoline can also be reached by a task that was
+ * preempted in the trampoline before the prog's enter helper took its RCU
+ * read lock, wait for those first.
+ */
+static void __bpf_prog_put_rcu_tasks(struct rcu_head *rcu)
+{
+ struct bpf_prog *prog = container_of(rcu, struct bpf_prog_aux, rcu)->prog;
+
+ if (bpf_prog_runs_sleepable(prog))
+ call_rcu_tasks_trace(rcu, __bpf_prog_put_rcu);
+ else
+ call_rcu(rcu, __bpf_prog_put_rcu);
+}
+
static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
{
- bpf_prog_kallsyms_del_all(prog);
- btf_put(prog->aux->btf);
module_put(prog->aux->mod);
- kvfree(prog->aux->jited_linfo);
- kvfree(prog->aux->linfo);
kfree(prog->aux->kfunc_tab);
kfree(prog->aux->ctx_arg_info);
if (prog->aux->attach_btf)
btf_put(prog->aux->attach_btf);
if (deferred) {
- if (prog->sleepable)
+ if (IS_ENABLED(CONFIG_TASKS_RCU) && prog->aux->tramp_linked)
+ call_rcu_tasks(&prog->aux->rcu, __bpf_prog_put_rcu_tasks);
+ else if (bpf_prog_runs_sleepable(prog))
call_rcu_tasks_trace(&prog->aux->rcu, __bpf_prog_put_rcu);
else
call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
@@ -2936,9 +2971,13 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, struct bpf_log_at
BPF_F_XDP_HAS_FRAGS |
BPF_F_XDP_DEV_BOUND_ONLY |
BPF_F_TEST_REG_INVARIANTS |
+ BPF_F_ARENA_SCALAR |
BPF_F_TOKEN_FD))
return -EINVAL;
+ if ((attr->prog_flags & BPF_F_ARENA_SCALAR) && !bpf_jit_supports_arena_scalar())
+ return -EOPNOTSUPP;
+
bpf_prog_load_fixup_attach_type(attr);
if (attr->prog_flags & BPF_F_TOKEN_FD) {
@@ -3068,6 +3107,10 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, struct bpf_log_at
prog->aux->user = get_current_user();
prog->len = attr->insn_cnt;
+ err = bpf_prog_stream_init(prog, GFP_USER);
+ if (err)
+ goto free_prog;
+
err = -EFAULT;
if (copy_from_bpfptr(prog->insns,
make_bpfptr(attr->insns, uattr.is_kernel),
@@ -3807,6 +3850,19 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
err = -EINVAL;
goto out_unlock;
}
+ /*
+ * The size of these contexts depends on what the program is attached
+ * to, or run with. That is compared with max_ctx_offset of the program,
+ * and nobody looks at the one of its extensions.
+ */
+ if (prog->type == BPF_PROG_TYPE_EXT &&
+ (tgt_prog->type == BPF_PROG_TYPE_RAW_TRACEPOINT ||
+ tgt_prog->type == BPF_PROG_TYPE_TRACEPOINT ||
+ tgt_prog->type == BPF_PROG_TYPE_SYSCALL) &&
+ prog->aux->max_ctx_offset > tgt_prog->aux->max_ctx_offset) {
+ err = -EINVAL;
+ goto out_unlock;
+ }
err = bpf_link_prime(&link->link.link, &link_primer);
if (err)
@@ -3976,19 +4032,19 @@ static int bpf_perf_link_fill_common(const struct perf_event *event,
*ulenp = 1;
}
if (!uname)
- return 0;
+ goto out;
if (buf) {
err = bpf_copy_to_user(uname, buf, ulen, len);
- if (err)
- return err;
} else {
char zero = '\0';
if (put_user(zero, uname))
- return -EFAULT;
+ err = -EFAULT;
}
- return 0;
+out:
+ kfree_const(buf);
+ return err;
}
#ifdef CONFIG_KPROBE_EVENTS
@@ -4045,6 +4101,7 @@ static void bpf_perf_link_fdinfo_kprobe(const struct perf_event *event,
name, offset, missed, addr,
type == BPF_FD_TYPE_KRETPROBE ? "kretprobe" : "kprobe",
event->bpf_cookie);
+ kfree_const(name);
}
#endif
@@ -4098,6 +4155,7 @@ static void bpf_perf_link_fdinfo_uprobe(const struct perf_event *event,
name, offset, ref_ctr_offset,
type == BPF_FD_TYPE_URETPROBE ? "uretprobe" : "uprobe",
event->bpf_cookie);
+ kfree_const(name);
}
#endif
@@ -4196,6 +4254,7 @@ static void bpf_tracepoint_link_show_fdinfo(const struct perf_event *event,
"event_type:\t%s\n"
"cookie:\t%llu\n",
name, "tracepoint", event->bpf_cookie);
+ kfree_const(name);
}
static void bpf_probe_link_show_fdinfo(const struct perf_event *event,
@@ -4755,6 +4814,7 @@ static int bpf_prog_query(const union bpf_attr *attr,
case BPF_CGROUP_GETSOCKOPT:
case BPF_CGROUP_SETSOCKOPT:
case BPF_LSM_CGROUP:
+ case BPF_STRUCT_OPS:
return cgroup_bpf_prog_query(attr, uattr, uattr_size);
case BPF_LIRC_MODE2:
return lirc_prog_query(attr, uattr);
@@ -5027,6 +5087,12 @@ static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog,
insns[i].imm = BPF_FUNC_tail_call;
/* fall-through */
}
+ /*
+ * BPF_JCOND is the same opcode as BPF_CALL_ARGS. The latter is for
+ * the interpreter, and a prog with unwind_goto is always JITed.
+ */
+ if (prog->jited && bpf_is_unwind_goto(&insns[i]))
+ continue;
if (code == (BPF_JMP | BPF_CALL) ||
code == (BPF_JMP | BPF_CALL_ARGS)) {
/* Restore the legacy xlated dump layout. */
@@ -5403,7 +5469,11 @@ static int bpf_map_get_info_by_fd(struct file *file,
info_len = min_t(u32, sizeof(info), info_len);
memset(&info, 0, sizeof(info));
- if (copy_from_user(&info, uinfo, info_len))
+ if (info_len >= offsetofend(struct bpf_map_info, hash) &&
+ get_user(info.hash, &uinfo->hash))
+ return -EFAULT;
+ if (info_len >= offsetofend(struct bpf_map_info, hash_size) &&
+ get_user(info.hash_size, &uinfo->hash_size))
return -EFAULT;
info.type = map->map_type;
@@ -5718,11 +5788,13 @@ static int bpf_task_fd_query(const union bpf_attr *attr,
err = bpf_get_perf_event_info(event, &prog_id, &fd_type,
&buf, &probe_offset,
&probe_addr, NULL);
- if (!err)
+ if (!err) {
err = bpf_task_fd_query_copy(attr, uattr, prog_id,
fd_type, buf,
probe_offset,
probe_addr);
+ kfree_const(buf);
+ }
goto put_file;
}
@@ -6042,7 +6114,10 @@ struct bpf_link *bpf_link_get_curr_or_next(u32 *id)
again:
link = idr_get_next(&link_idr, id);
if (link) {
- link = bpf_link_inc_not_zero(link);
+ if (link->id)
+ link = bpf_link_inc_not_zero(link);
+ else
+ link = ERR_PTR(-EAGAIN);
if (IS_ERR(link)) {
(*id)++;
goto again;
@@ -6200,7 +6275,7 @@ static int bpf_prog_bind_map(union bpf_attr *attr)
/* The bpf program will not access the bpf map, but for the sake of
* simplicity, increase sleepable_refcnt for sleepable program as well.
*/
- if (prog->sleepable)
+ if (bpf_prog_runs_sleepable(prog))
atomic64_inc(&map->sleepable_refcnt);
memcpy(used_maps_new, used_maps_old,
sizeof(used_maps_old[0]) * prog->aux->used_map_cnt);
@@ -6300,6 +6375,28 @@ put_prog:
return ret;
}
+#define BPF_PROG_STREAM_OPEN_LAST_FIELD prog_stream_open.flags
+
+static int prog_stream_open(union bpf_attr *attr)
+{
+ struct bpf_prog *prog;
+ u32 flags = attr->prog_stream_open.flags;
+ int ret;
+
+ if (CHECK_ATTR(BPF_PROG_STREAM_OPEN))
+ return -EINVAL;
+ if (flags & ~BPF_F_STREAM_NONBLOCK)
+ return -EINVAL;
+
+ prog = bpf_prog_get(attr->prog_stream_open.prog_fd);
+ if (IS_ERR(prog))
+ return PTR_ERR(prog);
+
+ ret = bpf_prog_stream_new_fd(prog, attr->prog_stream_open.stream_id, flags);
+ bpf_prog_put(prog);
+ return ret;
+}
+
static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, unsigned int size,
bpfptr_t uattr_common, unsigned int size_common)
{
@@ -6472,6 +6569,9 @@ static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, unsigned int size,
case BPF_PROG_ASSOC_STRUCT_OPS:
err = prog_assoc_struct_ops(&attr);
break;
+ case BPF_PROG_STREAM_OPEN:
+ err = prog_stream_open(&attr);
+ break;
default:
err = -EINVAL;
break;