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 13 T_GLOBAL_META( 14 T_META_NAMESPACE("xnu.ipc"), 15 T_META_RUN_CONCURRENTLY(TRUE), 16 T_META_RADAR_COMPONENT_NAME("xnu"), 17 T_META_RADAR_COMPONENT_VERSION("IPC")); 18 19 T_DECL(voucher_entry, "voucher_entry", T_META_CHECK_LEAKS(false), T_META_ALL_VALID_ARCHS(true)) 20 { 21 kern_return_t kr = KERN_SUCCESS; 22 mach_voucher_t voucher = MACH_VOUCHER_NULL; 23 24 /* 25 * The bank voucher already exists in this process, so using it doesn't 26 * actually test the problem. Use an importance voucher instead. 27 */ 28 mach_voucher_attr_recipe_data_t recipe = { 29 .key = MACH_VOUCHER_ATTR_KEY_IMPORTANCE, 30 .command = MACH_VOUCHER_ATTR_IMPORTANCE_SELF, 31 .previous_voucher = MACH_VOUCHER_NULL, 32 .content_size = 0, 33 }; 34 35 kr = host_create_mach_voucher(mach_host_self(), 36 (mach_voucher_attr_raw_recipe_array_t)&recipe, 37 sizeof(recipe), &voucher); 38 39 T_ASSERT_MACH_SUCCESS(kr, "host_create_mach_voucher"); 40 41 T_ASSERT_NOTNULL(voucher, "voucher must not be null"); 42 43 mach_port_urefs_t refs = 0; 44 45 kr = mach_port_get_refs(mach_task_self(), voucher, MACH_PORT_RIGHT_SEND, &refs); 46 47 T_ASSERT_MACH_SUCCESS(kr, "mach_port_get_refs"); 48 49 T_ASSERT_EQ(refs, (mach_port_urefs_t)1, "voucher must have only one ref"); 50 51 /* First, try with two moves (must fail because there's only one ref) */ 52 mach_msg_header_t request_msg_1 = { 53 .msgh_remote_port = voucher, 54 .msgh_local_port = MACH_PORT_NULL, 55 .msgh_voucher_port = voucher, 56 .msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND, 0, MACH_MSG_TYPE_MOVE_SEND, 0), 57 .msgh_id = 0xDEAD, 58 .msgh_size = sizeof(request_msg_1), 59 }; 60 61 kr = mach_msg_send(&request_msg_1); 62 63 T_ASSERT_MACH_ERROR(MACH_SEND_INVALID_DEST, kr, "send with two moves should fail with invalid dest"); 64 65 /* Next, try with a move and a copy (will succeed and destroy the last ref) */ 66 mach_msg_header_t request_msg_2 = { 67 .msgh_remote_port = voucher, 68 .msgh_local_port = MACH_PORT_NULL, 69 .msgh_voucher_port = voucher, 70 .msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND, 0, MACH_MSG_TYPE_COPY_SEND, 0), 71 .msgh_id = 0xDEAD, 72 .msgh_size = sizeof(request_msg_2), 73 }; 74 75 /* panic happens here */ 76 kr = mach_msg_send(&request_msg_2); 77 78 T_ASSERT_MACH_SUCCESS(kr, "send with move and copy succeeds"); 79 80 kr = mach_port_get_refs(mach_task_self(), voucher, MACH_PORT_RIGHT_SEND, &refs); 81 82 T_ASSERT_MACH_ERROR(KERN_INVALID_NAME, kr, "voucher should now be invalid name"); 83 } 84