struct verifier_state_list **explored_states; /* search pruning optimization */
        struct bpf_map *used_maps[MAX_USED_MAPS]; /* array of map's used by eBPF program */
        u32 used_map_cnt;               /* number of used maps */
+       bool allow_ptr_leaks;
 };
 
 /* verbose verifier prints what it's seeing
                return -EINVAL;
 }
 
+static bool is_spillable_regtype(enum bpf_reg_type type)
+{
+       switch (type) {
+       case PTR_TO_MAP_VALUE:
+       case PTR_TO_MAP_VALUE_OR_NULL:
+       case PTR_TO_STACK:
+       case PTR_TO_CTX:
+       case FRAME_PTR:
+       case CONST_PTR_TO_MAP:
+               return true;
+       default:
+               return false;
+       }
+}
+
 /* check_stack_read/write functions track spill/fill of registers,
  * stack boundary and alignment are checked in check_mem_access()
  */
         */
 
        if (value_regno >= 0 &&
-           (state->regs[value_regno].type == PTR_TO_MAP_VALUE ||
-            state->regs[value_regno].type == PTR_TO_STACK ||
-            state->regs[value_regno].type == PTR_TO_CTX)) {
+           is_spillable_regtype(state->regs[value_regno].type)) {
 
                /* register containing pointer is being spilled into stack */
                if (size != BPF_REG_SIZE) {
        return -EACCES;
 }
 
+static bool is_pointer_value(struct verifier_env *env, int regno)
+{
+       if (env->allow_ptr_leaks)
+               return false;
+
+       switch (env->cur_state.regs[regno].type) {
+       case UNKNOWN_VALUE:
+       case CONST_IMM:
+               return false;
+       default:
+               return true;
+       }
+}
+
 /* check whether memory at (regno + off) is accessible for t = (read | write)
  * if t==write, value_regno is a register which value is stored into memory
  * if t==read, value_regno is a register which will receive the value from memory
        }
 
        if (state->regs[regno].type == PTR_TO_MAP_VALUE) {
+               if (t == BPF_WRITE && value_regno >= 0 &&
+                   is_pointer_value(env, value_regno)) {
+                       verbose("R%d leaks addr into map\n", value_regno);
+                       return -EACCES;
+               }
                err = check_map_access(env, regno, off, size);
                if (!err && t == BPF_READ && value_regno >= 0)
                        mark_reg_unknown_value(state->regs, value_regno);
 
        } else if (state->regs[regno].type == PTR_TO_CTX) {
+               if (t == BPF_WRITE && value_regno >= 0 &&
+                   is_pointer_value(env, value_regno)) {
+                       verbose("R%d leaks addr into ctx\n", value_regno);
+                       return -EACCES;
+               }
                err = check_ctx_access(env, off, size, t);
                if (!err && t == BPF_READ && value_regno >= 0)
                        mark_reg_unknown_value(state->regs, value_regno);
                        verbose("invalid stack off=%d size=%d\n", off, size);
                        return -EACCES;
                }
-               if (t == BPF_WRITE)
+               if (t == BPF_WRITE) {
+                       if (!env->allow_ptr_leaks &&
+                           state->stack_slot_type[MAX_BPF_STACK + off] == STACK_SPILL &&
+                           size != BPF_REG_SIZE) {
+                               verbose("attempt to corrupt spilled pointer on stack\n");
+                               return -EACCES;
+                       }
                        err = check_stack_write(state, off, size, value_regno);
-               else
+               } else {
                        err = check_stack_read(state, off, size, value_regno);
+               }
        } else {
                verbose("R%d invalid mem access '%s'\n",
                        regno, reg_type_str[state->regs[regno].type]);
                return -EACCES;
        }
 
-       if (arg_type == ARG_ANYTHING)
+       if (arg_type == ARG_ANYTHING) {
+               if (is_pointer_value(env, regno)) {
+                       verbose("R%d leaks addr into helper function\n", regno);
+                       return -EACCES;
+               }
                return 0;
+       }
 
        if (arg_type == ARG_PTR_TO_STACK || arg_type == ARG_PTR_TO_MAP_KEY ||
            arg_type == ARG_PTR_TO_MAP_VALUE) {
 }
 
 /* check validity of 32-bit and 64-bit arithmetic operations */
-static int check_alu_op(struct reg_state *regs, struct bpf_insn *insn)
+static int check_alu_op(struct verifier_env *env, struct bpf_insn *insn)
 {
+       struct reg_state *regs = env->cur_state.regs;
        u8 opcode = BPF_OP(insn->code);
        int err;
 
                if (err)
                        return err;
 
+               if (is_pointer_value(env, insn->dst_reg)) {
+                       verbose("R%d pointer arithmetic prohibited\n",
+                               insn->dst_reg);
+                       return -EACCES;
+               }
+
                /* check dest operand */
                err = check_reg_arg(regs, insn->dst_reg, DST_OP);
                if (err)
                                 */
                                regs[insn->dst_reg] = regs[insn->src_reg];
                        } else {
+                               if (is_pointer_value(env, insn->src_reg)) {
+                                       verbose("R%d partial copy of pointer\n",
+                                               insn->src_reg);
+                                       return -EACCES;
+                               }
                                regs[insn->dst_reg].type = UNKNOWN_VALUE;
                                regs[insn->dst_reg].map_ptr = NULL;
                        }
                /* pattern match 'bpf_add Rx, imm' instruction */
                if (opcode == BPF_ADD && BPF_CLASS(insn->code) == BPF_ALU64 &&
                    regs[insn->dst_reg].type == FRAME_PTR &&
-                   BPF_SRC(insn->code) == BPF_K)
+                   BPF_SRC(insn->code) == BPF_K) {
                        stack_relative = true;
+               } else if (is_pointer_value(env, insn->dst_reg)) {
+                       verbose("R%d pointer arithmetic prohibited\n",
+                               insn->dst_reg);
+                       return -EACCES;
+               } else if (BPF_SRC(insn->code) == BPF_X &&
+                          is_pointer_value(env, insn->src_reg)) {
+                       verbose("R%d pointer arithmetic prohibited\n",
+                               insn->src_reg);
+                       return -EACCES;
+               }
 
                /* check dest operand */
                err = check_reg_arg(regs, insn->dst_reg, DST_OP);
                err = check_reg_arg(regs, insn->src_reg, SRC_OP);
                if (err)
                        return err;
+
+               if (is_pointer_value(env, insn->src_reg)) {
+                       verbose("R%d pointer comparison prohibited\n",
+                               insn->src_reg);
+                       return -EACCES;
+               }
        } else {
                if (insn->src_reg != BPF_REG_0) {
                        verbose("BPF_JMP uses reserved fields\n");
                        regs[insn->dst_reg].type = CONST_IMM;
                        regs[insn->dst_reg].imm = 0;
                }
+       } else if (is_pointer_value(env, insn->dst_reg)) {
+               verbose("R%d pointer comparison prohibited\n", insn->dst_reg);
+               return -EACCES;
        } else if (BPF_SRC(insn->code) == BPF_K &&
                   (opcode == BPF_JEQ || opcode == BPF_JNE)) {
 
                }
 
                if (class == BPF_ALU || class == BPF_ALU64) {
-                       err = check_alu_op(regs, insn);
+                       err = check_alu_op(env, insn);
                        if (err)
                                return err;
 
                                if (err)
                                        return err;
 
+                               if (is_pointer_value(env, BPF_REG_0)) {
+                                       verbose("R0 leaks addr as return value\n");
+                                       return -EACCES;
+                               }
+
 process_bpf_exit:
                                insn_idx = pop_stack(env, &prev_insn_idx);
                                if (insn_idx < 0) {
        if (ret < 0)
                goto skip_full_check;
 
+       env->allow_ptr_leaks = capable(CAP_SYS_ADMIN);
+
        ret = do_check(env);
 
 skip_full_check: