xref: /xnu-11417.121.6/tools/vm_sanitize_enforcement.py (revision a1e26a70f38d1d7daa7b49b258e2f8538ad81650)
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