if (reg->max_value != BPF_REGISTER_MAX_RANGE)
                        verbose(",max_value=%llu",
                                (unsigned long long)reg->max_value);
+               if (reg->min_align)
+                       verbose(",min_align=%u", reg->min_align);
+               if (reg->aux_off)
+                       verbose(",aux_off=%u", reg->aux_off);
+               if (reg->aux_off_align)
+                       verbose(",aux_off_align=%u", reg->aux_off_align);
        }
        for (i = 0; i < MAX_BPF_STACK; i += BPF_REG_SIZE) {
                if (state->stack_slot_type[i] == STACK_SPILL)
                regs[i].imm = 0;
                regs[i].min_value = BPF_REGISTER_MIN_RANGE;
                regs[i].max_value = BPF_REGISTER_MAX_RANGE;
+               regs[i].min_align = 0;
+               regs[i].aux_off = 0;
+               regs[i].aux_off_align = 0;
        }
 
        /* frame pointer */
 {
        regs[regno].min_value = BPF_REGISTER_MIN_RANGE;
        regs[regno].max_value = BPF_REGISTER_MAX_RANGE;
+       regs[regno].min_align = 0;
 }
 
 static void mark_reg_unknown_value_and_range(struct bpf_reg_state *regs,
 }
 
 static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg,
-                                  int off, int size)
+                                  int off, int size, bool strict)
 {
-       if (reg->id && size != 1) {
-               verbose("Unknown alignment. Only byte-sized access allowed in packet access.\n");
-               return -EACCES;
+       int reg_off;
+
+       /* Byte size accesses are always allowed. */
+       if (!strict || size == 1)
+               return 0;
+
+       reg_off = reg->off;
+       if (reg->id) {
+               if (reg->aux_off_align % size) {
+                       verbose("Packet access is only %u byte aligned, %d byte access not allowed\n",
+                               reg->aux_off_align, size);
+                       return -EACCES;
+               }
+               reg_off += reg->aux_off;
        }
 
        /* skb->data is NET_IP_ALIGN-ed */
-       if ((NET_IP_ALIGN + reg->off + off) % size != 0) {
+       if ((NET_IP_ALIGN + reg_off + off) % size != 0) {
                verbose("misaligned packet access off %d+%d+%d size %d\n",
-                       NET_IP_ALIGN, reg->off, off, size);
+                       NET_IP_ALIGN, reg_off, off, size);
                return -EACCES;
        }
 
 }
 
 static int check_val_ptr_alignment(const struct bpf_reg_state *reg,
-                                  int size)
+                                  int size, bool strict)
 {
-       if (size != 1) {
+       if (strict && size != 1) {
                verbose("Unknown alignment. Only byte-sized access allowed in value access.\n");
                return -EACCES;
        }
 static int check_ptr_alignment(const struct bpf_reg_state *reg,
                               int off, int size)
 {
+       bool strict = false;
+
+       if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
+               strict = true;
+
        switch (reg->type) {
        case PTR_TO_PACKET:
-               return IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ? 0 :
-                      check_pkt_ptr_alignment(reg, off, size);
+               return check_pkt_ptr_alignment(reg, off, size, strict);
        case PTR_TO_MAP_VALUE_ADJ:
-               return IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ? 0 :
-                      check_val_ptr_alignment(reg, size);
+               return check_val_ptr_alignment(reg, size, strict);
        default:
                if (off % size != 0) {
                        verbose("misaligned access off %d size %d\n",
                                                         value_regno);
                        /* note that reg.[id|off|range] == 0 */
                        state->regs[value_regno].type = reg_type;
+                       state->regs[value_regno].aux_off = 0;
+                       state->regs[value_regno].aux_off_align = 0;
                }
 
        } else if (reg->type == FRAME_PTR || reg->type == PTR_TO_STACK) {
                 */
                dst_reg->off += imm;
        } else {
+               bool had_id;
+
                if (src_reg->type == PTR_TO_PACKET) {
                        /* R6=pkt(id=0,off=0,r=62) R7=imm22; r7 += r6 */
                        tmp_reg = *dst_reg;  /* save r7 state */
                                src_reg->imm);
                        return -EACCES;
                }
+
+               had_id = (dst_reg->id != 0);
+
                /* dst_reg stays as pkt_ptr type and since some positive
                 * integer value was added to the pointer, increment its 'id'
                 */
                dst_reg->id = ++env->id_gen;
 
-               /* something was added to pkt_ptr, set range and off to zero */
+               /* something was added to pkt_ptr, set range to zero */
+               dst_reg->aux_off = dst_reg->off;
                dst_reg->off = 0;
                dst_reg->range = 0;
+               if (had_id)
+                       dst_reg->aux_off_align = min(dst_reg->aux_off_align,
+                                                    src_reg->min_align);
+               else
+                       dst_reg->aux_off_align = src_reg->min_align;
        }
        return 0;
 }
                reg->min_value = BPF_REGISTER_MIN_RANGE;
 }
 
+static u32 calc_align(u32 imm)
+{
+       if (!imm)
+               return 1U << 31;
+       return imm - ((imm - 1) & imm);
+}
+
 static void adjust_reg_min_max_vals(struct bpf_verifier_env *env,
                                    struct bpf_insn *insn)
 {
        s64 min_val = BPF_REGISTER_MIN_RANGE;
        u64 max_val = BPF_REGISTER_MAX_RANGE;
        u8 opcode = BPF_OP(insn->code);
+       u32 dst_align, src_align;
 
        dst_reg = ®s[insn->dst_reg];
+       src_align = 0;
        if (BPF_SRC(insn->code) == BPF_X) {
                check_reg_overflow(®s[insn->src_reg]);
                min_val = regs[insn->src_reg].min_value;
                    regs[insn->src_reg].type != UNKNOWN_VALUE) {
                        min_val = BPF_REGISTER_MIN_RANGE;
                        max_val = BPF_REGISTER_MAX_RANGE;
+                       src_align = 0;
+               } else {
+                       src_align = regs[insn->src_reg].min_align;
                }
        } else if (insn->imm < BPF_REGISTER_MAX_RANGE &&
                   (s64)insn->imm > BPF_REGISTER_MIN_RANGE) {
                min_val = max_val = insn->imm;
+               src_align = calc_align(insn->imm);
        }
 
+       dst_align = dst_reg->min_align;
+
        /* We don't know anything about what was done to this register, mark it
         * as unknown.
         */
                        dst_reg->min_value += min_val;
                if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
                        dst_reg->max_value += max_val;
+               dst_reg->min_align = min(src_align, dst_align);
                break;
        case BPF_SUB:
                if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
                        dst_reg->min_value -= min_val;
                if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
                        dst_reg->max_value -= max_val;
+               dst_reg->min_align = min(src_align, dst_align);
                break;
        case BPF_MUL:
                if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
                        dst_reg->min_value *= min_val;
                if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
                        dst_reg->max_value *= max_val;
+               dst_reg->min_align = max(src_align, dst_align);
                break;
        case BPF_AND:
                /* Disallow AND'ing of negative numbers, ain't nobody got time
                else
                        dst_reg->min_value = 0;
                dst_reg->max_value = max_val;
+               dst_reg->min_align = max(src_align, dst_align);
                break;
        case BPF_LSH:
                /* Gotta have special overflow logic here, if we're shifting
                 * more than MAX_RANGE then just assume we have an invalid
                 * range.
                 */
-               if (min_val > ilog2(BPF_REGISTER_MAX_RANGE))
+               if (min_val > ilog2(BPF_REGISTER_MAX_RANGE)) {
                        dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
-               else if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
-                       dst_reg->min_value <<= min_val;
-
+                       dst_reg->min_align = 1;
+               } else {
+                       if (dst_reg->min_value != BPF_REGISTER_MIN_RANGE)
+                               dst_reg->min_value <<= min_val;
+                       if (!dst_reg->min_align)
+                               dst_reg->min_align = 1;
+                       dst_reg->min_align <<= min_val;
+               }
                if (max_val > ilog2(BPF_REGISTER_MAX_RANGE))
                        dst_reg->max_value = BPF_REGISTER_MAX_RANGE;
                else if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
                /* RSH by a negative number is undefined, and the BPF_RSH is an
                 * unsigned shift, so make the appropriate casts.
                 */
-               if (min_val < 0 || dst_reg->min_value < 0)
+               if (min_val < 0 || dst_reg->min_value < 0) {
                        dst_reg->min_value = BPF_REGISTER_MIN_RANGE;
-               else
+               } else {
                        dst_reg->min_value =
                                (u64)(dst_reg->min_value) >> min_val;
+               }
+               if (min_val < 0) {
+                       dst_reg->min_align = 1;
+               } else {
+                       dst_reg->min_align >>= (u64) min_val;
+                       if (!dst_reg->min_align)
+                               dst_reg->min_align = 1;
+               }
                if (dst_reg->max_value != BPF_REGISTER_MAX_RANGE)
                        dst_reg->max_value >>= max_val;
                break;
                        regs[insn->dst_reg].imm = insn->imm;
                        regs[insn->dst_reg].max_value = insn->imm;
                        regs[insn->dst_reg].min_value = insn->imm;
+                       regs[insn->dst_reg].min_align = calc_align(insn->imm);
                }
 
        } else if (opcode > BPF_END) {