#define BITS_ROUNDUP_BYTES(bits) \
        (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))
 
-#define BTF_INFO_MASK 0x0f00ffff
+#define BTF_INFO_MASK 0x8f00ffff
 #define BTF_INT_MASK 0x0fffffff
 #define BTF_TYPE_ID_VALID(type_id) ((type_id) <= BTF_MAX_TYPE)
 #define BTF_STR_OFFSET_VALID(name_off) ((name_off) <= BTF_MAX_NAME_OFFSET)
                            const struct btf_type *struct_type,
                            const struct btf_member *member,
                            const struct btf_type *member_type);
+       int (*check_kflag_member)(struct btf_verifier_env *env,
+                                 const struct btf_type *struct_type,
+                                 const struct btf_member *member,
+                                 const struct btf_type *member_type);
        void (*log_details)(struct btf_verifier_env *env,
                            const struct btf_type *t);
        void (*seq_show)(const struct btf *btf, const struct btf_type *t,
        return BTF_INFO_VLEN(t->info);
 }
 
+static bool btf_type_kflag(const struct btf_type *t)
+{
+       return BTF_INFO_KFLAG(t->info);
+}
+
+static u32 btf_member_bit_offset(const struct btf_type *struct_type,
+                            const struct btf_member *member)
+{
+       return btf_type_kflag(struct_type) ? BTF_MEMBER_BIT_OFFSET(member->offset)
+                                          : member->offset;
+}
+
+static u32 btf_member_bitfield_size(const struct btf_type *struct_type,
+                                   const struct btf_member *member)
+{
+       return btf_type_kflag(struct_type) ? BTF_MEMBER_BITFIELD_SIZE(member->offset)
+                                          : 0;
+}
+
 static u32 btf_type_int(const struct btf_type *t)
 {
        return *(u32 *)(t + 1);
        if (env->phase != CHECK_META)
                btf_verifier_log_type(env, struct_type, NULL);
 
-       __btf_verifier_log(log, "\t%s type_id=%u bits_offset=%u",
-                          __btf_name_by_offset(btf, member->name_off),
-                          member->type, member->offset);
+       if (btf_type_kflag(struct_type))
+               __btf_verifier_log(log,
+                                  "\t%s type_id=%u bitfield_size=%u bits_offset=%u",
+                                  __btf_name_by_offset(btf, member->name_off),
+                                  member->type,
+                                  BTF_MEMBER_BITFIELD_SIZE(member->offset),
+                                  BTF_MEMBER_BIT_OFFSET(member->offset));
+       else
+               __btf_verifier_log(log, "\t%s type_id=%u bits_offset=%u",
+                                  __btf_name_by_offset(btf, member->name_off),
+                                  member->type, member->offset);
 
        if (fmt && *fmt) {
                __btf_verifier_log(log, " ");
        return -EINVAL;
 }
 
+static int btf_df_check_kflag_member(struct btf_verifier_env *env,
+                                    const struct btf_type *struct_type,
+                                    const struct btf_member *member,
+                                    const struct btf_type *member_type)
+{
+       btf_verifier_log_basic(env, struct_type,
+                              "Unsupported check_kflag_member");
+       return -EINVAL;
+}
+
+/* Used for ptr, array and struct/union type members.
+ * int, enum and modifier types have their specific callback functions.
+ */
+static int btf_generic_check_kflag_member(struct btf_verifier_env *env,
+                                         const struct btf_type *struct_type,
+                                         const struct btf_member *member,
+                                         const struct btf_type *member_type)
+{
+       if (BTF_MEMBER_BITFIELD_SIZE(member->offset)) {
+               btf_verifier_log_member(env, struct_type, member,
+                                       "Invalid member bitfield_size");
+               return -EINVAL;
+       }
+
+       /* bitfield size is 0, so member->offset represents bit offset only.
+        * It is safe to call non kflag check_member variants.
+        */
+       return btf_type_ops(member_type)->check_member(env, struct_type,
+                                                      member,
+                                                      member_type);
+}
+
 static int btf_df_resolve(struct btf_verifier_env *env,
                          const struct resolve_vertex *v)
 {
        return 0;
 }
 
+static int btf_int_check_kflag_member(struct btf_verifier_env *env,
+                                     const struct btf_type *struct_type,
+                                     const struct btf_member *member,
+                                     const struct btf_type *member_type)
+{
+       u32 struct_bits_off, nr_bits, nr_int_data_bits, bytes_offset;
+       u32 int_data = btf_type_int(member_type);
+       u32 struct_size = struct_type->size;
+       u32 nr_copy_bits;
+
+       /* a regular int type is required for the kflag int member */
+       if (!btf_type_int_is_regular(member_type)) {
+               btf_verifier_log_member(env, struct_type, member,
+                                       "Invalid member base type");
+               return -EINVAL;
+       }
+
+       /* check sanity of bitfield size */
+       nr_bits = BTF_MEMBER_BITFIELD_SIZE(member->offset);
+       struct_bits_off = BTF_MEMBER_BIT_OFFSET(member->offset);
+       nr_int_data_bits = BTF_INT_BITS(int_data);
+       if (!nr_bits) {
+               /* Not a bitfield member, member offset must be at byte
+                * boundary.
+                */
+               if (BITS_PER_BYTE_MASKED(struct_bits_off)) {
+                       btf_verifier_log_member(env, struct_type, member,
+                                               "Invalid member offset");
+                       return -EINVAL;
+               }
+
+               nr_bits = nr_int_data_bits;
+       } else if (nr_bits > nr_int_data_bits) {
+               btf_verifier_log_member(env, struct_type, member,
+                                       "Invalid member bitfield_size");
+               return -EINVAL;
+       }
+
+       bytes_offset = BITS_ROUNDDOWN_BYTES(struct_bits_off);
+       nr_copy_bits = nr_bits + BITS_PER_BYTE_MASKED(struct_bits_off);
+       if (nr_copy_bits > BITS_PER_U64) {
+               btf_verifier_log_member(env, struct_type, member,
+                                       "nr_copy_bits exceeds 64");
+               return -EINVAL;
+       }
+
+       if (struct_size < bytes_offset ||
+           struct_size - bytes_offset < BITS_ROUNDUP_BYTES(nr_copy_bits)) {
+               btf_verifier_log_member(env, struct_type, member,
+                                       "Member exceeds struct_size");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static s32 btf_int_check_meta(struct btf_verifier_env *env,
                              const struct btf_type *t,
                              u32 meta_left)
                return -EINVAL;
        }
 
+       if (btf_type_kflag(t)) {
+               btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
+               return -EINVAL;
+       }
+
        int_data = btf_type_int(t);
        if (int_data & ~BTF_INT_MASK) {
                btf_verifier_log_basic(env, t, "Invalid int_data:%x",
        seq_printf(m, "0x%llx", print_num);
 }
 
+
 static void btf_int_bits_seq_show(const struct btf *btf,
                                  const struct btf_type *t,
                                  void *data, u8 bits_offset,
        .check_meta = btf_int_check_meta,
        .resolve = btf_df_resolve,
        .check_member = btf_int_check_member,
+       .check_kflag_member = btf_int_check_kflag_member,
        .log_details = btf_int_log,
        .seq_show = btf_int_seq_show,
 };
                                                         resolved_type);
 }
 
+static int btf_modifier_check_kflag_member(struct btf_verifier_env *env,
+                                          const struct btf_type *struct_type,
+                                          const struct btf_member *member,
+                                          const struct btf_type *member_type)
+{
+       const struct btf_type *resolved_type;
+       u32 resolved_type_id = member->type;
+       struct btf_member resolved_member;
+       struct btf *btf = env->btf;
+
+       resolved_type = btf_type_id_size(btf, &resolved_type_id, NULL);
+       if (!resolved_type) {
+               btf_verifier_log_member(env, struct_type, member,
+                                       "Invalid member");
+               return -EINVAL;
+       }
+
+       resolved_member = *member;
+       resolved_member.type = resolved_type_id;
+
+       return btf_type_ops(resolved_type)->check_kflag_member(env, struct_type,
+                                                              &resolved_member,
+                                                              resolved_type);
+}
+
 static int btf_ptr_check_member(struct btf_verifier_env *env,
                                const struct btf_type *struct_type,
                                const struct btf_member *member,
                return -EINVAL;
        }
 
+       if (btf_type_kflag(t)) {
+               btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
+               return -EINVAL;
+       }
+
        if (!BTF_TYPE_ID_VALID(t->type)) {
                btf_verifier_log_type(env, t, "Invalid type_id");
                return -EINVAL;
        .check_meta = btf_ref_type_check_meta,
        .resolve = btf_modifier_resolve,
        .check_member = btf_modifier_check_member,
+       .check_kflag_member = btf_modifier_check_kflag_member,
        .log_details = btf_ref_type_log,
        .seq_show = btf_modifier_seq_show,
 };
        .check_meta = btf_ref_type_check_meta,
        .resolve = btf_ptr_resolve,
        .check_member = btf_ptr_check_member,
+       .check_kflag_member = btf_generic_check_kflag_member,
        .log_details = btf_ref_type_log,
        .seq_show = btf_ptr_seq_show,
 };
        .check_meta = btf_fwd_check_meta,
        .resolve = btf_df_resolve,
        .check_member = btf_df_check_member,
+       .check_kflag_member = btf_df_check_kflag_member,
        .log_details = btf_ref_type_log,
        .seq_show = btf_df_seq_show,
 };
                return -EINVAL;
        }
 
+       if (btf_type_kflag(t)) {
+               btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
+               return -EINVAL;
+       }
+
        if (t->size) {
                btf_verifier_log_type(env, t, "size != 0");
                return -EINVAL;
        .check_meta = btf_array_check_meta,
        .resolve = btf_array_resolve,
        .check_member = btf_array_check_member,
+       .check_kflag_member = btf_generic_check_kflag_member,
        .log_details = btf_array_log,
        .seq_show = btf_array_seq_show,
 };
        u32 meta_needed, last_offset;
        struct btf *btf = env->btf;
        u32 struct_size = t->size;
+       u32 offset;
        u16 i;
 
        meta_needed = btf_type_vlen(t) * sizeof(*member);
                        return -EINVAL;
                }
 
-               if (is_union && member->offset) {
+               offset = btf_member_bit_offset(t, member);
+               if (is_union && offset) {
                        btf_verifier_log_member(env, t, member,
                                                "Invalid member bits_offset");
                        return -EINVAL;
                 * ">" instead of ">=" because the last member could be
                 * "char a[0];"
                 */
-               if (last_offset > member->offset) {
+               if (last_offset > offset) {
                        btf_verifier_log_member(env, t, member,
                                                "Invalid member bits_offset");
                        return -EINVAL;
                }
 
-               if (BITS_ROUNDUP_BYTES(member->offset) > struct_size) {
+               if (BITS_ROUNDUP_BYTES(offset) > struct_size) {
                        btf_verifier_log_member(env, t, member,
                                                "Member bits_offset exceeds its struct size");
                        return -EINVAL;
                }
 
                btf_verifier_log_member(env, t, member, NULL);
-               last_offset = member->offset;
+               last_offset = offset;
        }
 
        return meta_needed;
 
                last_member_type = btf_type_by_id(env->btf,
                                                  last_member_type_id);
-               err = btf_type_ops(last_member_type)->check_member(env, v->t,
-                                                       last_member,
-                                                       last_member_type);
+               if (btf_type_kflag(v->t))
+                       err = btf_type_ops(last_member_type)->check_kflag_member(env, v->t,
+                                                               last_member,
+                                                               last_member_type);
+               else
+                       err = btf_type_ops(last_member_type)->check_member(env, v->t,
+                                                               last_member,
+                                                               last_member_type);
                if (err)
                        return err;
        }
                        return env_stack_push(env, member_type, member_type_id);
                }
 
-               err = btf_type_ops(member_type)->check_member(env, v->t,
-                                                             member,
-                                                             member_type);
+               if (btf_type_kflag(v->t))
+                       err = btf_type_ops(member_type)->check_kflag_member(env, v->t,
+                                                                           member,
+                                                                           member_type);
+               else
+                       err = btf_type_ops(member_type)->check_member(env, v->t,
+                                                                     member,
+                                                                     member_type);
                if (err)
                        return err;
        }
        for_each_member(i, t, member) {
                const struct btf_type *member_type = btf_type_by_id(btf,
                                                                member->type);
-               u32 member_offset = member->offset;
-               u32 bytes_offset = BITS_ROUNDDOWN_BYTES(member_offset);
-               u8 bits8_offset = BITS_PER_BYTE_MASKED(member_offset);
                const struct btf_kind_operations *ops;
+               u32 member_offset, bitfield_size;
+               u32 bytes_offset;
+               u8 bits8_offset;
 
                if (i)
                        seq_puts(m, seq);
 
-               ops = btf_type_ops(member_type);
-               ops->seq_show(btf, member_type, member->type,
-                             data + bytes_offset, bits8_offset, m);
+               member_offset = btf_member_bit_offset(t, member);
+               bitfield_size = btf_member_bitfield_size(t, member);
+               if (bitfield_size) {
+                       btf_bitfield_seq_show(data, member_offset,
+                                             bitfield_size, m);
+               } else {
+                       bytes_offset = BITS_ROUNDDOWN_BYTES(member_offset);
+                       bits8_offset = BITS_PER_BYTE_MASKED(member_offset);
+                       ops = btf_type_ops(member_type);
+                       ops->seq_show(btf, member_type, member->type,
+                                     data + bytes_offset, bits8_offset, m);
+               }
        }
        seq_puts(m, "}");
 }
        .check_meta = btf_struct_check_meta,
        .resolve = btf_struct_resolve,
        .check_member = btf_struct_check_member,
+       .check_kflag_member = btf_generic_check_kflag_member,
        .log_details = btf_struct_log,
        .seq_show = btf_struct_seq_show,
 };
        return 0;
 }
 
+static int btf_enum_check_kflag_member(struct btf_verifier_env *env,
+                                      const struct btf_type *struct_type,
+                                      const struct btf_member *member,
+                                      const struct btf_type *member_type)
+{
+       u32 struct_bits_off, nr_bits, bytes_end, struct_size;
+       u32 int_bitsize = sizeof(int) * BITS_PER_BYTE;
+
+       struct_bits_off = BTF_MEMBER_BIT_OFFSET(member->offset);
+       nr_bits = BTF_MEMBER_BITFIELD_SIZE(member->offset);
+       if (!nr_bits) {
+               if (BITS_PER_BYTE_MASKED(struct_bits_off)) {
+                       btf_verifier_log_member(env, struct_type, member,
+                                               "Member is not byte aligned");
+                               return -EINVAL;
+               }
+
+               nr_bits = int_bitsize;
+       } else if (nr_bits > int_bitsize) {
+               btf_verifier_log_member(env, struct_type, member,
+                                       "Invalid member bitfield_size");
+               return -EINVAL;
+       }
+
+       struct_size = struct_type->size;
+       bytes_end = BITS_ROUNDUP_BYTES(struct_bits_off + nr_bits);
+       if (struct_size < bytes_end) {
+               btf_verifier_log_member(env, struct_type, member,
+                                       "Member exceeds struct_size");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static s32 btf_enum_check_meta(struct btf_verifier_env *env,
                               const struct btf_type *t,
                               u32 meta_left)
                return -EINVAL;
        }
 
+       if (btf_type_kflag(t)) {
+               btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
+               return -EINVAL;
+       }
+
        if (t->size != sizeof(int)) {
                btf_verifier_log_type(env, t, "Expected size:%zu",
                                      sizeof(int));
        .check_meta = btf_enum_check_meta,
        .resolve = btf_df_resolve,
        .check_member = btf_enum_check_member,
+       .check_kflag_member = btf_enum_check_kflag_member,
        .log_details = btf_enum_log,
        .seq_show = btf_enum_seq_show,
 };
                return -EINVAL;
        }
 
+       if (btf_type_kflag(t)) {
+               btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
+               return -EINVAL;
+       }
+
        btf_verifier_log_type(env, t, NULL);
 
        return meta_needed;
         * Hence, there is no btf_func_check_member().
         */
        .check_member = btf_df_check_member,
+       .check_kflag_member = btf_df_check_kflag_member,
        .log_details = btf_func_proto_log,
        .seq_show = btf_df_seq_show,
 };
                return -EINVAL;
        }
 
+       if (btf_type_kflag(t)) {
+               btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
+               return -EINVAL;
+       }
+
        btf_verifier_log_type(env, t, NULL);
 
        return 0;
        .check_meta = btf_func_check_meta,
        .resolve = btf_df_resolve,
        .check_member = btf_df_check_member,
+       .check_kflag_member = btf_df_check_kflag_member,
        .log_details = btf_ref_type_log,
        .seq_show = btf_df_seq_show,
 };