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