Merge branch 'bpf-robustify'
Daniel Borkmann says: ==================== Further robustify putting BPF progs This series addresses a potential issue reported to us by Jann Horn with regards to putting progs. First patch moves progs generally under RCU destruction and second patch refactors getting of progs to simplify code a bit. For details, please see individual patches. Note, we think that addressing this one in net-next should be sufficient. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
6bd3847bdc
|
@ -218,9 +218,9 @@ void bpf_register_prog_type(struct bpf_prog_type_list *tl);
|
||||||
void bpf_register_map_type(struct bpf_map_type_list *tl);
|
void bpf_register_map_type(struct bpf_map_type_list *tl);
|
||||||
|
|
||||||
struct bpf_prog *bpf_prog_get(u32 ufd);
|
struct bpf_prog *bpf_prog_get(u32 ufd);
|
||||||
|
struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type);
|
||||||
struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog);
|
struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog);
|
||||||
void bpf_prog_put(struct bpf_prog *prog);
|
void bpf_prog_put(struct bpf_prog *prog);
|
||||||
void bpf_prog_put_rcu(struct bpf_prog *prog);
|
|
||||||
|
|
||||||
struct bpf_map *bpf_map_get_with_uref(u32 ufd);
|
struct bpf_map *bpf_map_get_with_uref(u32 ufd);
|
||||||
struct bpf_map *__bpf_map_get(struct fd f);
|
struct bpf_map *__bpf_map_get(struct fd f);
|
||||||
|
@ -278,11 +278,13 @@ static inline struct bpf_prog *bpf_prog_get(u32 ufd)
|
||||||
return ERR_PTR(-EOPNOTSUPP);
|
return ERR_PTR(-EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void bpf_prog_put(struct bpf_prog *prog)
|
static inline struct bpf_prog *bpf_prog_get_type(u32 ufd,
|
||||||
|
enum bpf_prog_type type)
|
||||||
{
|
{
|
||||||
|
return ERR_PTR(-EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void bpf_prog_put_rcu(struct bpf_prog *prog)
|
static inline void bpf_prog_put(struct bpf_prog *prog)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_BPF_SYSCALL */
|
#endif /* CONFIG_BPF_SYSCALL */
|
||||||
|
|
|
@ -390,9 +390,7 @@ static void *prog_fd_array_get_ptr(struct bpf_map *map,
|
||||||
|
|
||||||
static void prog_fd_array_put_ptr(void *ptr)
|
static void prog_fd_array_put_ptr(void *ptr)
|
||||||
{
|
{
|
||||||
struct bpf_prog *prog = ptr;
|
bpf_prog_put(ptr);
|
||||||
|
|
||||||
bpf_prog_put_rcu(prog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* decrement refcnt of all bpf_progs that are stored in this map */
|
/* decrement refcnt of all bpf_progs that are stored in this map */
|
||||||
|
|
|
@ -623,7 +623,7 @@ static void bpf_prog_uncharge_memlock(struct bpf_prog *prog)
|
||||||
free_uid(user);
|
free_uid(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __prog_put_common(struct rcu_head *rcu)
|
static void __bpf_prog_put_rcu(struct rcu_head *rcu)
|
||||||
{
|
{
|
||||||
struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
|
struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
|
||||||
|
|
||||||
|
@ -632,17 +632,10 @@ static void __prog_put_common(struct rcu_head *rcu)
|
||||||
bpf_prog_free(aux->prog);
|
bpf_prog_free(aux->prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* version of bpf_prog_put() that is called after a grace period */
|
|
||||||
void bpf_prog_put_rcu(struct bpf_prog *prog)
|
|
||||||
{
|
|
||||||
if (atomic_dec_and_test(&prog->aux->refcnt))
|
|
||||||
call_rcu(&prog->aux->rcu, __prog_put_common);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bpf_prog_put(struct bpf_prog *prog)
|
void bpf_prog_put(struct bpf_prog *prog)
|
||||||
{
|
{
|
||||||
if (atomic_dec_and_test(&prog->aux->refcnt))
|
if (atomic_dec_and_test(&prog->aux->refcnt))
|
||||||
__prog_put_common(&prog->aux->rcu);
|
call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(bpf_prog_put);
|
EXPORT_SYMBOL_GPL(bpf_prog_put);
|
||||||
|
|
||||||
|
@ -650,7 +643,7 @@ static int bpf_prog_release(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
struct bpf_prog *prog = filp->private_data;
|
struct bpf_prog *prog = filp->private_data;
|
||||||
|
|
||||||
bpf_prog_put_rcu(prog);
|
bpf_prog_put(prog);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,7 +657,7 @@ int bpf_prog_new_fd(struct bpf_prog *prog)
|
||||||
O_RDWR | O_CLOEXEC);
|
O_RDWR | O_CLOEXEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bpf_prog *__bpf_prog_get(struct fd f)
|
static struct bpf_prog *____bpf_prog_get(struct fd f)
|
||||||
{
|
{
|
||||||
if (!f.file)
|
if (!f.file)
|
||||||
return ERR_PTR(-EBADF);
|
return ERR_PTR(-EBADF);
|
||||||
|
@ -685,24 +678,35 @@ struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog)
|
||||||
return prog;
|
return prog;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called by sockets/tracing/seccomp before attaching program to an event
|
static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *type)
|
||||||
* pairs with bpf_prog_put()
|
|
||||||
*/
|
|
||||||
struct bpf_prog *bpf_prog_get(u32 ufd)
|
|
||||||
{
|
{
|
||||||
struct fd f = fdget(ufd);
|
struct fd f = fdget(ufd);
|
||||||
struct bpf_prog *prog;
|
struct bpf_prog *prog;
|
||||||
|
|
||||||
prog = __bpf_prog_get(f);
|
prog = ____bpf_prog_get(f);
|
||||||
if (IS_ERR(prog))
|
if (IS_ERR(prog))
|
||||||
return prog;
|
return prog;
|
||||||
|
if (type && prog->type != *type) {
|
||||||
|
prog = ERR_PTR(-EINVAL);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
prog = bpf_prog_inc(prog);
|
prog = bpf_prog_inc(prog);
|
||||||
|
out:
|
||||||
fdput(f);
|
fdput(f);
|
||||||
|
|
||||||
return prog;
|
return prog;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(bpf_prog_get);
|
|
||||||
|
struct bpf_prog *bpf_prog_get(u32 ufd)
|
||||||
|
{
|
||||||
|
return __bpf_prog_get(ufd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type)
|
||||||
|
{
|
||||||
|
return __bpf_prog_get(ufd, &type);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(bpf_prog_get_type);
|
||||||
|
|
||||||
/* last field in 'union bpf_attr' used by this command */
|
/* last field in 'union bpf_attr' used by this command */
|
||||||
#define BPF_PROG_LOAD_LAST_FIELD kern_version
|
#define BPF_PROG_LOAD_LAST_FIELD kern_version
|
||||||
|
|
|
@ -7529,7 +7529,7 @@ static void perf_event_free_bpf_prog(struct perf_event *event)
|
||||||
prog = event->tp_event->prog;
|
prog = event->tp_event->prog;
|
||||||
if (prog) {
|
if (prog) {
|
||||||
event->tp_event->prog = NULL;
|
event->tp_event->prog = NULL;
|
||||||
bpf_prog_put_rcu(prog);
|
bpf_prog_put(prog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1301,21 +1301,10 @@ int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk)
|
||||||
|
|
||||||
static struct bpf_prog *__get_bpf(u32 ufd, struct sock *sk)
|
static struct bpf_prog *__get_bpf(u32 ufd, struct sock *sk)
|
||||||
{
|
{
|
||||||
struct bpf_prog *prog;
|
|
||||||
|
|
||||||
if (sock_flag(sk, SOCK_FILTER_LOCKED))
|
if (sock_flag(sk, SOCK_FILTER_LOCKED))
|
||||||
return ERR_PTR(-EPERM);
|
return ERR_PTR(-EPERM);
|
||||||
|
|
||||||
prog = bpf_prog_get(ufd);
|
return bpf_prog_get_type(ufd, BPF_PROG_TYPE_SOCKET_FILTER);
|
||||||
if (IS_ERR(prog))
|
|
||||||
return prog;
|
|
||||||
|
|
||||||
if (prog->type != BPF_PROG_TYPE_SOCKET_FILTER) {
|
|
||||||
bpf_prog_put(prog);
|
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return prog;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int sk_attach_bpf(u32 ufd, struct sock *sk)
|
int sk_attach_bpf(u32 ufd, struct sock *sk)
|
||||||
|
|
|
@ -1765,18 +1765,12 @@ static int kcm_attach_ioctl(struct socket *sock, struct kcm_attach *info)
|
||||||
if (!csock)
|
if (!csock)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
prog = bpf_prog_get(info->bpf_fd);
|
prog = bpf_prog_get_type(info->bpf_fd, BPF_PROG_TYPE_SOCKET_FILTER);
|
||||||
if (IS_ERR(prog)) {
|
if (IS_ERR(prog)) {
|
||||||
err = PTR_ERR(prog);
|
err = PTR_ERR(prog);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prog->type != BPF_PROG_TYPE_SOCKET_FILTER) {
|
|
||||||
bpf_prog_put(prog);
|
|
||||||
err = -EINVAL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = kcm_attach(sock, csock, prog);
|
err = kcm_attach(sock, csock, prog);
|
||||||
if (err) {
|
if (err) {
|
||||||
bpf_prog_put(prog);
|
bpf_prog_put(prog);
|
||||||
|
|
|
@ -1588,13 +1588,9 @@ static int fanout_set_data_ebpf(struct packet_sock *po, char __user *data,
|
||||||
if (copy_from_user(&fd, data, len))
|
if (copy_from_user(&fd, data, len))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
new = bpf_prog_get(fd);
|
new = bpf_prog_get_type(fd, BPF_PROG_TYPE_SOCKET_FILTER);
|
||||||
if (IS_ERR(new))
|
if (IS_ERR(new))
|
||||||
return PTR_ERR(new);
|
return PTR_ERR(new);
|
||||||
if (new->type != BPF_PROG_TYPE_SOCKET_FILTER) {
|
|
||||||
bpf_prog_put(new);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
__fanout_set_data_bpf(po->fanout, new);
|
__fanout_set_data_bpf(po->fanout, new);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -223,15 +223,10 @@ static int tcf_bpf_init_from_efd(struct nlattr **tb, struct tcf_bpf_cfg *cfg)
|
||||||
|
|
||||||
bpf_fd = nla_get_u32(tb[TCA_ACT_BPF_FD]);
|
bpf_fd = nla_get_u32(tb[TCA_ACT_BPF_FD]);
|
||||||
|
|
||||||
fp = bpf_prog_get(bpf_fd);
|
fp = bpf_prog_get_type(bpf_fd, BPF_PROG_TYPE_SCHED_ACT);
|
||||||
if (IS_ERR(fp))
|
if (IS_ERR(fp))
|
||||||
return PTR_ERR(fp);
|
return PTR_ERR(fp);
|
||||||
|
|
||||||
if (fp->type != BPF_PROG_TYPE_SCHED_ACT) {
|
|
||||||
bpf_prog_put(fp);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[TCA_ACT_BPF_NAME]) {
|
if (tb[TCA_ACT_BPF_NAME]) {
|
||||||
name = kmemdup(nla_data(tb[TCA_ACT_BPF_NAME]),
|
name = kmemdup(nla_data(tb[TCA_ACT_BPF_NAME]),
|
||||||
nla_len(tb[TCA_ACT_BPF_NAME]),
|
nla_len(tb[TCA_ACT_BPF_NAME]),
|
||||||
|
|
|
@ -272,15 +272,10 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
|
||||||
|
|
||||||
bpf_fd = nla_get_u32(tb[TCA_BPF_FD]);
|
bpf_fd = nla_get_u32(tb[TCA_BPF_FD]);
|
||||||
|
|
||||||
fp = bpf_prog_get(bpf_fd);
|
fp = bpf_prog_get_type(bpf_fd, BPF_PROG_TYPE_SCHED_CLS);
|
||||||
if (IS_ERR(fp))
|
if (IS_ERR(fp))
|
||||||
return PTR_ERR(fp);
|
return PTR_ERR(fp);
|
||||||
|
|
||||||
if (fp->type != BPF_PROG_TYPE_SCHED_CLS) {
|
|
||||||
bpf_prog_put(fp);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[TCA_BPF_NAME]) {
|
if (tb[TCA_BPF_NAME]) {
|
||||||
name = kmemdup(nla_data(tb[TCA_BPF_NAME]),
|
name = kmemdup(nla_data(tb[TCA_BPF_NAME]),
|
||||||
nla_len(tb[TCA_BPF_NAME]),
|
nla_len(tb[TCA_BPF_NAME]),
|
||||||
|
|
Loading…
Reference in New Issue