1*e3723e1fSApple OSS Distributions /* 2*e3723e1fSApple OSS Distributions * Test that sending a message to a voucher with the same voucher as the voucher port 3*e3723e1fSApple OSS Distributions * with only one send right count with move send before the copy send doesn't panic. 4*e3723e1fSApple OSS Distributions * 5*e3723e1fSApple OSS Distributions * clang -o voucherentry voucherentry.c -ldarwintest -Weverything -Wno-gnu-flexible-array-initializer 6*e3723e1fSApple OSS Distributions * 7*e3723e1fSApple OSS Distributions * <rdar://problem/18826844> 8*e3723e1fSApple OSS Distributions */ 9*e3723e1fSApple OSS Distributions 10*e3723e1fSApple OSS Distributions #include <mach/mach.h> 11*e3723e1fSApple OSS Distributions #include <darwintest.h> 12*e3723e1fSApple OSS Distributions 13*e3723e1fSApple OSS Distributions T_GLOBAL_META( 14*e3723e1fSApple OSS Distributions T_META_NAMESPACE("xnu.ipc"), 15*e3723e1fSApple OSS Distributions T_META_RUN_CONCURRENTLY(TRUE), 16*e3723e1fSApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"), 17*e3723e1fSApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("IPC")); 18*e3723e1fSApple OSS Distributions 19*e3723e1fSApple OSS Distributions T_DECL(voucher_entry, "voucher_entry", T_META_CHECK_LEAKS(false), T_META_ALL_VALID_ARCHS(true), T_META_TAG_VM_PREFERRED) 20*e3723e1fSApple OSS Distributions { 21*e3723e1fSApple OSS Distributions kern_return_t kr = KERN_SUCCESS; 22*e3723e1fSApple OSS Distributions mach_voucher_t voucher = MACH_VOUCHER_NULL; 23*e3723e1fSApple OSS Distributions mach_port_name_t reply; 24*e3723e1fSApple OSS Distributions mach_port_options_t opts = { 25*e3723e1fSApple OSS Distributions .flags = MPO_REPLY_PORT, 26*e3723e1fSApple OSS Distributions }; 27*e3723e1fSApple OSS Distributions 28*e3723e1fSApple OSS Distributions /* 29*e3723e1fSApple OSS Distributions * The bank voucher already exists in this process, so using it doesn't 30*e3723e1fSApple OSS Distributions * actually test the problem. Use an importance voucher instead. 31*e3723e1fSApple OSS Distributions */ 32*e3723e1fSApple OSS Distributions mach_voucher_attr_recipe_data_t recipe = { 33*e3723e1fSApple OSS Distributions .key = MACH_VOUCHER_ATTR_KEY_IMPORTANCE, 34*e3723e1fSApple OSS Distributions .command = MACH_VOUCHER_ATTR_IMPORTANCE_SELF, 35*e3723e1fSApple OSS Distributions .previous_voucher = MACH_VOUCHER_NULL, 36*e3723e1fSApple OSS Distributions .content_size = 0, 37*e3723e1fSApple OSS Distributions }; 38*e3723e1fSApple OSS Distributions 39*e3723e1fSApple OSS Distributions kr = host_create_mach_voucher(mach_host_self(), 40*e3723e1fSApple OSS Distributions (mach_voucher_attr_raw_recipe_array_t)&recipe, 41*e3723e1fSApple OSS Distributions sizeof(recipe), &voucher); 42*e3723e1fSApple OSS Distributions 43*e3723e1fSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "host_create_mach_voucher"); 44*e3723e1fSApple OSS Distributions 45*e3723e1fSApple OSS Distributions T_ASSERT_NOTNULL(voucher, "voucher must not be null"); 46*e3723e1fSApple OSS Distributions 47*e3723e1fSApple OSS Distributions mach_port_urefs_t refs = 0; 48*e3723e1fSApple OSS Distributions 49*e3723e1fSApple OSS Distributions kr = mach_port_get_refs(mach_task_self(), voucher, MACH_PORT_RIGHT_SEND, &refs); 50*e3723e1fSApple OSS Distributions 51*e3723e1fSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "mach_port_get_refs"); 52*e3723e1fSApple OSS Distributions 53*e3723e1fSApple OSS Distributions T_ASSERT_EQ(refs, (mach_port_urefs_t)1, "voucher must have only one ref"); 54*e3723e1fSApple OSS Distributions 55*e3723e1fSApple OSS Distributions T_ASSERT_MACH_SUCCESS(mach_port_construct(mach_task_self(), 56*e3723e1fSApple OSS Distributions &opts, 0, &reply), "make reply port"); 57*e3723e1fSApple OSS Distributions 58*e3723e1fSApple OSS Distributions /* First, try with two moves (must fail because there's only one ref) */ 59*e3723e1fSApple OSS Distributions mach_msg_header_t request_msg_1 = { 60*e3723e1fSApple OSS Distributions .msgh_remote_port = voucher, 61*e3723e1fSApple OSS Distributions .msgh_local_port = reply, 62*e3723e1fSApple OSS Distributions .msgh_voucher_port = voucher, 63*e3723e1fSApple OSS Distributions .msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND, 64*e3723e1fSApple OSS Distributions MACH_MSG_TYPE_MAKE_SEND_ONCE, MACH_MSG_TYPE_MOVE_SEND, 0), 65*e3723e1fSApple OSS Distributions .msgh_id = 0xDEAD, 66*e3723e1fSApple OSS Distributions .msgh_size = sizeof(request_msg_1), 67*e3723e1fSApple OSS Distributions }; 68*e3723e1fSApple OSS Distributions 69*e3723e1fSApple OSS Distributions kr = mach_msg2(&request_msg_1, MACH64_SEND_MSG | MACH64_RCV_MSG | MACH64_SEND_KOBJECT_CALL, 70*e3723e1fSApple OSS Distributions request_msg_1, request_msg_1.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, 0); 71*e3723e1fSApple OSS Distributions 72*e3723e1fSApple OSS Distributions T_ASSERT_MACH_ERROR(MACH_SEND_INVALID_DEST, kr, "send with two moves should fail with invalid dest"); 73*e3723e1fSApple OSS Distributions 74*e3723e1fSApple OSS Distributions T_ASSERT_MACH_SUCCESS(mach_port_destruct(mach_task_self(), reply, 0, 0), 75*e3723e1fSApple OSS Distributions "destroy reply port"); 76*e3723e1fSApple OSS Distributions 77*e3723e1fSApple OSS Distributions T_ASSERT_MACH_SUCCESS(mach_port_construct(mach_task_self(), 78*e3723e1fSApple OSS Distributions &opts, 0, &reply), "make reply port"); 79*e3723e1fSApple OSS Distributions 80*e3723e1fSApple OSS Distributions /* Next, try with a move and a copy (will succeed and destroy the last ref) */ 81*e3723e1fSApple OSS Distributions union { 82*e3723e1fSApple OSS Distributions mach_msg_header_t hdr; 83*e3723e1fSApple OSS Distributions struct { 84*e3723e1fSApple OSS Distributions mig_reply_error_t err; 85*e3723e1fSApple OSS Distributions mach_msg_trailer_t trailer; 86*e3723e1fSApple OSS Distributions }; 87*e3723e1fSApple OSS Distributions } request_msg_2 = { 88*e3723e1fSApple OSS Distributions .hdr = { 89*e3723e1fSApple OSS Distributions .msgh_remote_port = voucher, 90*e3723e1fSApple OSS Distributions .msgh_local_port = reply, 91*e3723e1fSApple OSS Distributions .msgh_voucher_port = voucher, 92*e3723e1fSApple OSS Distributions .msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MOVE_SEND, 93*e3723e1fSApple OSS Distributions MACH_MSG_TYPE_MAKE_SEND_ONCE, MACH_MSG_TYPE_COPY_SEND, 0), 94*e3723e1fSApple OSS Distributions .msgh_id = 0xDEAD, 95*e3723e1fSApple OSS Distributions .msgh_size = sizeof(request_msg_2), 96*e3723e1fSApple OSS Distributions } 97*e3723e1fSApple OSS Distributions }; 98*e3723e1fSApple OSS Distributions 99*e3723e1fSApple OSS Distributions /* panic happens here */ 100*e3723e1fSApple OSS Distributions kr = mach_msg2(&request_msg_2, MACH64_SEND_MSG | MACH64_RCV_MSG | MACH64_SEND_KOBJECT_CALL, 101*e3723e1fSApple OSS Distributions request_msg_2.hdr, request_msg_2.hdr.msgh_size, sizeof(request_msg_2), 102*e3723e1fSApple OSS Distributions reply, MACH_MSG_TIMEOUT_NONE, 0); 103*e3723e1fSApple OSS Distributions 104*e3723e1fSApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "send with move and copy succeeds"); 105*e3723e1fSApple OSS Distributions 106*e3723e1fSApple OSS Distributions T_ASSERT_MACH_SUCCESS(mach_port_destruct(mach_task_self(), reply, 0, 0), 107*e3723e1fSApple OSS Distributions "destroy reply port"); 108*e3723e1fSApple OSS Distributions 109*e3723e1fSApple OSS Distributions kr = mach_port_get_refs(mach_task_self(), voucher, MACH_PORT_RIGHT_SEND, &refs); 110*e3723e1fSApple OSS Distributions 111*e3723e1fSApple OSS Distributions T_ASSERT_MACH_ERROR(KERN_INVALID_NAME, kr, "voucher should now be invalid name"); 112*e3723e1fSApple OSS Distributions } 113