BPF_WRITE = 2
 };
 
+struct bpf_prog;
+
 struct bpf_verifier_ops {
        /* return eBPF function prototype for verification */
        const struct bpf_func_proto *(*get_func_proto)(enum bpf_func_id func_id);
 
        u32 (*convert_ctx_access)(enum bpf_access_type type, int dst_reg,
                                  int src_reg, int ctx_off,
-                                 struct bpf_insn *insn);
+                                 struct bpf_insn *insn, struct bpf_prog *prog);
 };
 
 struct bpf_prog_type_list {
        enum bpf_prog_type type;
 };
 
-struct bpf_prog;
-
 struct bpf_prog_aux {
        atomic_t refcnt;
        u32 used_map_cnt;
 
 #include <linux/printk.h>
 #include <linux/workqueue.h>
 #include <linux/sched.h>
+#include <net/sch_generic.h>
 
 #include <asm/cacheflush.h>
 
        bpf_size;                                               \
 })
 
-/* Macro to invoke filter function. */
-#define SK_RUN_FILTER(filter, ctx) \
-       (*filter->prog->bpf_func)(ctx, filter->prog->insnsi)
-
 #ifdef CONFIG_COMPAT
 /* A struct sock_filter is architecture independent. */
 struct compat_sock_fprog {
        kmemcheck_bitfield_begin(meta);
        u16                     jited:1,        /* Is our filter JIT'ed? */
                                gpl_compatible:1, /* Is filter GPL compatible? */
+                               cb_access:1,    /* Is control block accessed? */
                                dst_needed:1;   /* Do we need dst entry? */
        kmemcheck_bitfield_end(meta);
        u32                     len;            /* Number of filter blocks */
 
 #define BPF_PROG_RUN(filter, ctx)  (*filter->bpf_func)(ctx, filter->insnsi)
 
+static inline u32 bpf_prog_run_save_cb(const struct bpf_prog *prog,
+                                      struct sk_buff *skb)
+{
+       u8 *cb_data = qdisc_skb_cb(skb)->data;
+       u8 saved_cb[QDISC_CB_PRIV_LEN];
+       u32 res;
+
+       BUILD_BUG_ON(FIELD_SIZEOF(struct __sk_buff, cb) !=
+                    QDISC_CB_PRIV_LEN);
+
+       if (unlikely(prog->cb_access)) {
+               memcpy(saved_cb, cb_data, sizeof(saved_cb));
+               memset(cb_data, 0, sizeof(saved_cb));
+       }
+
+       res = BPF_PROG_RUN(prog, skb);
+
+       if (unlikely(prog->cb_access))
+               memcpy(cb_data, saved_cb, sizeof(saved_cb));
+
+       return res;
+}
+
+static inline u32 bpf_prog_run_clear_cb(const struct bpf_prog *prog,
+                                       struct sk_buff *skb)
+{
+       u8 *cb_data = qdisc_skb_cb(skb)->data;
+
+       if (unlikely(prog->cb_access))
+               memset(cb_data, 0, QDISC_CB_PRIV_LEN);
+       return BPF_PROG_RUN(prog, skb);
+}
+
 static inline unsigned int bpf_prog_size(unsigned int proglen)
 {
        return max(sizeof(struct bpf_prog),
 
 
                cnt = env->prog->aux->ops->
                        convert_ctx_access(type, insn->dst_reg, insn->src_reg,
-                                          insn->off, insn_buf);
+                                          insn->off, insn_buf, env->prog);
                if (cnt == 0 || cnt >= ARRAY_SIZE(insn_buf)) {
                        verbose("bpf verifier is misconfigured\n");
                        return -EINVAL;
 
  *     @sk: sock associated with &sk_buff
  *     @skb: buffer to filter
  *
- * Run the filter code and then cut skb->data to correct size returned by
- * SK_RUN_FILTER. If pkt_len is 0 we toss packet. If skb->len is smaller
+ * Run the eBPF program and then cut skb->data to correct size returned by
+ * the program. If pkt_len is 0 we toss packet. If skb->len is smaller
  * than pkt_len we keep whole skb->data. This is the socket level
- * wrapper to SK_RUN_FILTER. It returns 0 if the packet should
+ * wrapper to BPF_PROG_RUN. It returns 0 if the packet should
  * be accepted or -EPERM if the packet should be tossed.
  *
  */
        rcu_read_lock();
        filter = rcu_dereference(sk->sk_filter);
        if (filter) {
-               unsigned int pkt_len = SK_RUN_FILTER(filter, skb);
+               unsigned int pkt_len = bpf_prog_run_save_cb(filter->prog, skb);
 
                err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM;
        }
 
 static u32 bpf_net_convert_ctx_access(enum bpf_access_type type, int dst_reg,
                                      int src_reg, int ctx_off,
-                                     struct bpf_insn *insn_buf)
+                                     struct bpf_insn *insn_buf,
+                                     struct bpf_prog *prog)
 {
        struct bpf_insn *insn = insn_buf;
 
                offsetof(struct __sk_buff, cb[4]):
                BUILD_BUG_ON(FIELD_SIZEOF(struct qdisc_skb_cb, data) < 20);
 
+               prog->cb_access = 1;
                ctx_off -= offsetof(struct __sk_buff, cb[0]);
                ctx_off += offsetof(struct sk_buff, cb);
                ctx_off += offsetof(struct qdisc_skb_cb, data);
 
        rcu_read_lock();
        prog = rcu_dereference(f->bpf_prog);
        if (prog)
-               ret = BPF_PROG_RUN(prog, skb) % num;
+               ret = bpf_prog_run_clear_cb(prog, skb) % num;
        rcu_read_unlock();
 
        return ret;
        return err;
 }
 
-static unsigned int run_filter(const struct sk_buff *skb,
-                                     const struct sock *sk,
-                                     unsigned int res)
+static unsigned int run_filter(struct sk_buff *skb,
+                              const struct sock *sk,
+                              unsigned int res)
 {
        struct sk_filter *filter;
 
        rcu_read_lock();
        filter = rcu_dereference(sk->sk_filter);
        if (filter != NULL)
-               res = SK_RUN_FILTER(filter, skb);
+               res = bpf_prog_run_clear_cb(filter->prog, skb);
        rcu_read_unlock();
 
        return res;