int prog_fd;
        unsigned int hid;
        int retval;
+       int insert_head;
 };
 
 struct hid_hw_request_syscall_args {
 
 struct test_program {
        const char *name;
+       int insert_head;
 };
 #define LOAD_PROGRAMS(progs) \
        load_programs(progs, ARRAY_SIZE(progs), _metadata, self, variant)
 
                args.prog_fd = bpf_program__fd(prog);
                args.hid = self->hid_id;
+               args.insert_head = programs[i].insert_head;
                err = bpf_prog_test_run_opts(attach_fd, &tattr);
                ASSERT_OK(args.retval) TH_LOG("attach_hid(%s): %d", programs[i].name, args.retval);
        }
        ASSERT_EQ(args.data[1], 2);
 }
 
+/*
+ * Attach hid_insert{0,1,2} to the given uhid device,
+ * retrieve and open the matching hidraw node,
+ * inject one event in the uhid device,
+ * check that the programs have been inserted in the correct order.
+ */
+TEST_F(hid_bpf, test_hid_attach_flags)
+{
+       const struct test_program progs[] = {
+               {
+                       .name = "hid_test_insert2",
+                       .insert_head = 0,
+               },
+               {
+                       .name = "hid_test_insert1",
+                       .insert_head = 1,
+               },
+               {
+                       .name = "hid_test_insert3",
+                       .insert_head = 0,
+               },
+       };
+       __u8 buf[10] = {0};
+       int err;
+
+       LOAD_PROGRAMS(progs);
+
+       /* inject one event */
+       buf[0] = 1;
+       uhid_send_event(_metadata, self->uhid_fd, buf, 6);
+
+       /* read the data from hidraw */
+       memset(buf, 0, sizeof(buf));
+       err = read(self->hidraw_fd, buf, sizeof(buf));
+       ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
+       ASSERT_EQ(buf[1], 1);
+       ASSERT_EQ(buf[2], 2);
+       ASSERT_EQ(buf[3], 3);
+}
+
 /*
  * Attach hid_rdesc_fixup to the given uhid device,
  * retrieve and open the matching hidraw node,
 
        int prog_fd;
        unsigned int hid;
        int retval;
+       int insert_head;
 };
 
 __u64 callback_check = 52;
 {
        ctx->retval = hid_bpf_attach_prog(ctx->hid,
                                          ctx->prog_fd,
-                                         0);
+                                         ctx->insert_head ? HID_BPF_FLAG_INSERT_HEAD :
+                                                            HID_BPF_FLAG_NONE);
        return 0;
 }
 
 
        return sizeof(rdesc) + 73;
 }
+
+SEC("?fmod_ret/hid_bpf_device_event")
+int BPF_PROG(hid_test_insert1, struct hid_bpf_ctx *hid_ctx)
+{
+       __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
+
+       if (!data)
+               return 0; /* EPERM check */
+
+       /* we need to be run first */
+       if (data[2] || data[3])
+               return -1;
+
+       data[1] = 1;
+
+       return 0;
+}
+
+SEC("?fmod_ret/hid_bpf_device_event")
+int BPF_PROG(hid_test_insert2, struct hid_bpf_ctx *hid_ctx)
+{
+       __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
+
+       if (!data)
+               return 0; /* EPERM check */
+
+       /* after insert0 and before insert2 */
+       if (!data[1] || data[3])
+               return -1;
+
+       data[2] = 2;
+
+       return 0;
+}
+
+SEC("?fmod_ret/hid_bpf_device_event")
+int BPF_PROG(hid_test_insert3, struct hid_bpf_ctx *hid_ctx)
+{
+       __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
+
+       if (!data)
+               return 0; /* EPERM check */
+
+       /* at the end */
+       if (!data[1] || !data[2])
+               return -1;
+
+       data[3] = 3;
+
+       return 0;
+}