1import sys 2 3# This script's return values 4ERROR = 1 5SUCCESS = 0 6 7error_help_message = """Safe types were used in MIG in violation of VM API sanitization enforcement. 8\t- If you created a new MIG file that is not related to Virtual Memory, you will want to add it to the list of \ 9exceptions in this Python script. 10\t- If your work is related to Virtual Memory, you need to use unsafe types for userspace inputs. Make sure you \ 11define VM_KERNEL_SERVER in the MIG file, and that the safe type is associated to an unsafe type via VM_UNSAFE_TYPE/VM_TYPE_SAFE_UNSAFE. Learn more by reading doc/vm/sanitize.md.""" 12 13# List of safe types that should not be used to represent userspace inputs. 14# Note that is may be counter-intuitive that we want to prevent the use of 15# safe types: they are safe after all, so wouldn't it be better to use them? 16# The source of the confusion is that the safety of the type really describes 17# the safety of the data. Since the data will be coming from userspace, it is 18# considered unsafe/untrusted, and we want to make sure we represent it with 19# unsafe types to force the programmer to sanitize it before it can be 20# represented with the (directly usable) safe type. 21# This is a list of all the safe types which have corresponding unsafe types 22# in vm_types_unsafe.h. 23safe_type_list = [ 24 "mach_vm_address_t", 25 "mach_vm_offset_t", 26 "mach_vm_size_t", 27 "vm_address_t", 28 "vm_offset_t", 29 "vm_size_t", 30 "vm_map_address_t", 31 "vm_map_offset_t", 32 "vm_map_size_t", 33 "memory_object_offset_t", 34 "memory_object_size_t", 35 "vm_object_offset_t", 36 "vm_object_size_t", 37 "pointer_t", 38 "vm32_address_t", 39 "vm32_offset_t", 40 "vm32_size_t", 41 "vm_prot_t", 42 "vm_inherit_t", 43 "vm_behavior_t", 44 "caddr_t", 45 "user_addr_t", 46 "size_t", 47 "user_size_t", 48 "struct mach_vm_range", 49 "mach_vm_range_recipe_v1_t", 50] 51 52# Files that are considered outside the VM boundary and are thus not subject to enforcement. 53file_ignorelist = [ 54 "arcade_register_server.c", 55 "clock_server.c", 56 "exc_server.c", 57 "mach_eventlink_server.c", 58 "mach_exc_server.c", 59 "mach_notify_server.c", 60 "mach_port_server.c", 61 "mach_voucher_server.c", 62 "memory_entry_server.c", 63 "processor_server.c", 64 "processor_set_server.c", 65 "restartable_server.c", 66 "task_server.c", 67 "thread_act_server.c", 68 "upl_server.c", 69] 70 71def print_error(*args, **kwargs): 72 print("error:", *args, file=sys.stderr, **kwargs) 73 74def is_type_used_in_line(safe_type, line): 75 # This is used by an autogenerated struct in MIG that isn't an argument to a MIG call 76 if "vm_address_t reserved; /* Reserved */" in line: 77 return False 78 79 # arguments to MIG functions are typically the first thing on the line in the generated header, 80 # but we search for the type elsewhere to be on the safe side. We still need to be careful not 81 # to trigger false positives by doing a naive search 82 # e.g. size_t is in "__Request__host_page_size_t __attribute__((unused));" 83 if safe_type in line.replace(':', ' ').replace(';', ' ').replace(',', ' ').split(): 84 return True 85 86 return False 87 88def are_safe_types_used_in_file(filepath): 89 are_safe_types_used = False 90 lineno = 1 91 with open(filepath, "r") as file: 92 for line in file: 93 for safe_type in safe_type_list: 94 if is_type_used_in_line(safe_type, line): 95 print_error("Found safe type \"" + safe_type + "\" in " +filepath + ":" + str(lineno) + ". Line is \"" + line.strip() + "\"") 96 are_safe_types_used = True 97 lineno += 1 98 return are_safe_types_used 99 100def main(): 101 if len(sys.argv) < 2: 102 print_error("usage: python vm_api_enforcement.py filename [extra_filename...]") 103 return ERROR 104 105 are_safe_types_used = False 106 for filename in sys.argv[1:]: 107 if filename in file_ignorelist: 108 continue 109 110 if not (filename.endswith(".c") or filename.endswith(".h")): 111 print_error("File should be a .c or .h file:", filename) 112 return ERROR 113 header = filename[:-1] + "h" 114 115 are_safe_types_used = are_safe_types_used_in_file(header) 116 117 if are_safe_types_used: 118 print_error("{}: {}".format(sys.argv[0], error_help_message)) 119 return ERROR 120 return SUCCESS 121 122sys.exit(main()) 123