]>
Commit | Line | Data |
---|---|---|
d190cdc3 A |
1 | /* |
2 | * Test that sending a message to a voucher with the same voucher as the voucher port | |
3 | * with only one send right count with move send before the copy send doesn't panic. | |
4 | * | |
5 | * clang -o voucherentry voucherentry.c -ldarwintest -Weverything -Wno-gnu-flexible-array-initializer | |
6 | * | |
7 | * <rdar://problem/18826844> | |
8 | */ | |
9 | ||
10 | #include <mach/mach.h> | |
11 | #include <darwintest.h> | |
12 | ||
813fb2f6 | 13 | T_DECL(voucher_entry, "voucher_entry", T_META_CHECK_LEAKS(false), T_META_ALL_VALID_ARCHS(true)) |
d190cdc3 A |
14 | { |
15 | kern_return_t kr = KERN_SUCCESS; | |
16 | mach_voucher_t voucher = MACH_VOUCHER_NULL; | |
17 | ||
18 | /* | |
19 | * The bank voucher already exists in this process, so using it doesn't | |
20 | * actually test the problem. Use an importance voucher instead. | |
21 | */ | |
22 | mach_voucher_attr_recipe_data_t recipe = { | |
23 | .key = MACH_VOUCHER_ATTR_KEY_IMPORTANCE, | |
24 | .command = MACH_VOUCHER_ATTR_IMPORTANCE_SELF, | |
25 | .previous_voucher = MACH_VOUCHER_NULL, | |
26 | .content_size = 0, | |
27 | }; | |
28 | ||
29 | kr = host_create_mach_voucher(mach_host_self(), | |
30 | (mach_voucher_attr_raw_recipe_array_t)&recipe, | |
31 | sizeof(recipe), &voucher); | |
32 | ||
33 | T_ASSERT_MACH_SUCCESS(kr, "host_create_mach_voucher"); | |
34 | ||
35 | T_ASSERT_NOTNULL(voucher, "voucher must not be null"); | |
36 | ||
37 | mach_port_urefs_t refs = 0; | |
38 | ||
39 | kr = mach_port_get_refs(mach_task_self(), voucher, MACH_PORT_RIGHT_SEND, &refs); | |
40 | ||
41 | T_ASSERT_MACH_SUCCESS(kr, "mach_port_get_refs"); | |
42 | ||
43 | T_ASSERT_EQ(refs, (mach_port_urefs_t)1, "voucher must have only one ref"); | |
44 | ||
45 | /* First, try with two moves (must fail because there's only one ref) */ | |
46 | mach_msg_header_t request_msg_1 = { | |
47 | .msgh_remote_port = voucher, | |
48 | .msgh_local_port = MACH_PORT_NULL, | |
49 | .msgh_voucher_port = voucher, | |
50 | .msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND, 0, MACH_MSG_TYPE_MOVE_SEND, 0), | |
51 | .msgh_id = 0xDEAD, | |
52 | .msgh_size = sizeof(request_msg_1), | |
53 | }; | |
54 | ||
55 | kr = mach_msg_send(&request_msg_1); | |
56 | ||
57 | T_ASSERT_MACH_ERROR(MACH_SEND_INVALID_DEST, kr, "send with two moves should fail with invalid dest"); | |
58 | ||
59 | /* Next, try with a move and a copy (will succeed and destroy the last ref) */ | |
60 | mach_msg_header_t request_msg_2 = { | |
61 | .msgh_remote_port = voucher, | |
62 | .msgh_local_port = MACH_PORT_NULL, | |
63 | .msgh_voucher_port = voucher, | |
64 | .msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND, 0, MACH_MSG_TYPE_COPY_SEND, 0), | |
65 | .msgh_id = 0xDEAD, | |
66 | .msgh_size = sizeof(request_msg_2), | |
67 | }; | |
68 | ||
69 | /* panic happens here */ | |
70 | kr = mach_msg_send(&request_msg_2); | |
71 | ||
72 | T_ASSERT_MACH_SUCCESS(kr, "send with move and copy succeeds"); | |
73 | ||
74 | kr = mach_port_get_refs(mach_task_self(), voucher, MACH_PORT_RIGHT_SEND, &refs); | |
75 | ||
76 | T_ASSERT_MACH_ERROR(KERN_INVALID_NAME, kr, "voucher should now be invalid name"); | |
77 | } | |
78 |