static int rst_sock_attr_skfilter(loff_t *pos_p, struct sock *sk, cpt_context_t *ctx) { int err; struct sk_filter *fp, *old_fp; loff_t pos = *pos_p; struct cpt_obj_bits v; err = rst_get_object(CPT_OBJ_SKFILTER, pos, &v, ctx); if (err) return err; *pos_p += v.cpt_next; if (v.cpt_size % sizeof(struct sock_filter)) return -EINVAL; fp = sock_kmalloc(sk, v.cpt_size+sizeof(*fp), GFP_KERNEL_UBC); if (fp == NULL) return -ENOMEM; atomic_set(&fp->refcnt, 1); fp->len = v.cpt_size/sizeof(struct sock_filter); err = ctx->pread(fp->insns, v.cpt_size, ctx, pos+v.cpt_hdrlen); if (err) { sk_filter_uncharge(sk, fp); return err; } old_fp = sk->sk_filter; sk->sk_filter = fp; if (old_fp) sk_filter_uncharge(sk, old_fp); return 0; }
/** * sk_attach_filter - attach a socket filter * @fprog: the filter program * @sk: the socket to use * * Attach the user's filter code. We first run some sanity checks on * it to make sure it does not explode on us later. If an error * occurs or there is insufficient memory for the filter a negative * errno code is returned. On success the return is zero. */ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) { struct sk_filter *fp, *old_fp; unsigned int fsize = sizeof(struct sock_filter) * fprog->len; int err; /* Make sure new filter is there and in the right amounts. */ if (fprog->filter == NULL) return -EINVAL; fp = sock_kmalloc(sk, fsize+sizeof(*fp), GFP_KERNEL); if (!fp) return -ENOMEM; if (copy_from_user(fp->insns, fprog->filter, fsize)) { sock_kfree_s(sk, fp, fsize+sizeof(*fp)); return -EFAULT; } atomic_set(&fp->refcnt, 1); fp->len = fprog->len; err = sk_chk_filter(fp->insns, fp->len); if (err) { sk_filter_uncharge(sk, fp); return err; } old_fp = rcu_dereference_protected(sk->sk_filter, sock_owned_by_user(sk)); rcu_assign_pointer(sk->sk_filter, fp); if (old_fp) sk_filter_uncharge(sk, old_fp); return 0; }
int sk_detach_filter(struct sock *sk) { int ret = -ENOENT; struct sk_filter *filter; filter = rcu_dereference_protected(sk->sk_filter, sock_owned_by_user(sk)); if (filter) { rcu_assign_pointer(sk->sk_filter, NULL); sk_filter_uncharge(sk, filter); ret = 0; } return ret; }
int sk_detach_filter(struct sock *sk) { int ret = -ENOENT; struct sk_filter *filter; rcu_read_lock_bh(); filter = rcu_dereference_bh(sk->sk_filter); if (filter) { rcu_assign_pointer(sk->sk_filter, NULL); sk_filter_uncharge(sk, filter); ret = 0; } rcu_read_unlock_bh(); return ret; }