CodeGen.ml 70 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682
  1. (*
  2. * Copyright (C) 2011-2018 Intel Corporation. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in
  12. * the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Intel Corporation nor the names of its
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. *)
  31. open Printf
  32. open Util (* for failwithf *)
  33. (* --------------------------------------------------------------------
  34. * We first introduce a `parse_enclave_ast' function (see below) to
  35. * parse a value of type `Ast.enclave' into a `enclave_content' record.
  36. * --------------------------------------------------------------------
  37. *)
  38. (* This record type is used to better organize a value of Ast.enclave *)
  39. type enclave_content = {
  40. file_shortnm : string; (* the short name of original EDL file *)
  41. enclave_name : string; (* the normalized C identifier *)
  42. include_list : string list;
  43. import_exprs : Ast.import_decl list;
  44. comp_defs : Ast.composite_type list;
  45. tfunc_decls : Ast.trusted_func list;
  46. ufunc_decls : Ast.untrusted_func list;
  47. }
  48. (* Whether to prefix untrusted proxy with Enclave name *)
  49. let g_use_prefix = ref false
  50. let g_untrusted_dir = ref "."
  51. let g_trusted_dir = ref "."
  52. let empty_ec =
  53. { file_shortnm = "";
  54. enclave_name = "";
  55. include_list = [];
  56. import_exprs = [];
  57. comp_defs = [];
  58. tfunc_decls = [];
  59. ufunc_decls = []; }
  60. let get_tf_fname (tf: Ast.trusted_func) =
  61. tf.Ast.tf_fdecl.Ast.fname
  62. let is_priv_ecall (tf: Ast.trusted_func) =
  63. tf.Ast.tf_is_priv
  64. let get_uf_fname (uf: Ast.untrusted_func) =
  65. uf.Ast.uf_fdecl.Ast.fname
  66. let get_trusted_func_names (ec: enclave_content) =
  67. List.map get_tf_fname ec.tfunc_decls
  68. let get_untrusted_func_names (ec: enclave_content) =
  69. List.map get_uf_fname ec.ufunc_decls
  70. let tf_list_to_fd_list (tfs: Ast.trusted_func list) =
  71. List.map (fun (tf: Ast.trusted_func) -> tf.Ast.tf_fdecl) tfs
  72. let tf_list_to_priv_list (tfs: Ast.trusted_func list) =
  73. List.map is_priv_ecall tfs
  74. (* Get a list of names of all private ECALLs *)
  75. let get_priv_ecall_names (tfs: Ast.trusted_func list) =
  76. List.filter is_priv_ecall tfs |> List.map get_tf_fname
  77. let uf_list_to_fd_list (ufs: Ast.untrusted_func list) =
  78. List.map (fun (uf: Ast.untrusted_func) -> uf.Ast.uf_fdecl) ufs
  79. (* Get a list of names of all allowed ECALLs from `allow(...)' *)
  80. let get_allowed_names (ufs: Ast.untrusted_func list) =
  81. let allow_lists =
  82. List.map (fun (uf: Ast.untrusted_func) -> uf.Ast.uf_allow_list) ufs
  83. in
  84. List.flatten allow_lists |> dedup_list
  85. (* With `parse_enclave_ast', each enclave AST is traversed only once. *)
  86. let parse_enclave_ast (e: Ast.enclave) =
  87. let ac_include_list = ref [] in
  88. let ac_import_exprs = ref [] in
  89. let ac_comp_defs = ref [] in
  90. let ac_tfunc_decls = ref [] in
  91. let ac_ufunc_decls = ref [] in
  92. List.iter (fun ex ->
  93. match ex with
  94. Ast.Composite x -> ac_comp_defs := x :: !ac_comp_defs
  95. | Ast.Include x -> ac_include_list := x :: !ac_include_list
  96. | Ast.Importing x -> ac_import_exprs := x :: !ac_import_exprs
  97. | Ast.Interface xs ->
  98. List.iter (fun ef ->
  99. match ef with
  100. Ast.Trusted f ->
  101. ac_tfunc_decls := f :: !ac_tfunc_decls
  102. | Ast.Untrusted f ->
  103. ac_ufunc_decls := f :: !ac_ufunc_decls) xs
  104. ) e.Ast.eexpr;
  105. { file_shortnm = e.Ast.ename;
  106. enclave_name = Util.to_c_identifier e.Ast.ename;
  107. include_list = List.rev !ac_include_list;
  108. import_exprs = List.rev !ac_import_exprs;
  109. comp_defs = List.rev !ac_comp_defs;
  110. tfunc_decls = List.rev !ac_tfunc_decls;
  111. ufunc_decls = List.rev !ac_ufunc_decls; }
  112. let is_foreign_array (pt: Ast.parameter_type) =
  113. match pt with
  114. Ast.PTVal _ -> false
  115. | Ast.PTPtr(t, a) ->
  116. match t with
  117. Ast.Foreign _ -> a.Ast.pa_isary
  118. | _ -> false
  119. (* A naked function has neither parameters nor return value. *)
  120. let is_naked_func (fd: Ast.func_decl) =
  121. fd.Ast.rtype = Ast.Void && fd.Ast.plist = []
  122. (*
  123. * If user only defined a trusted function w/o neither parameter nor
  124. * return value, the generated trusted bridge will not call any tRTS
  125. * routines. If the real trusted function doesn't call tRTS function
  126. * either (highly possible), then the MSVC linker will not link tRTS
  127. * into the result enclave.
  128. *)
  129. let tbridge_gen_dummy_variable (ec: enclave_content) =
  130. let _dummy_variable =
  131. sprintf "\n#ifdef _MSC_VER\n\
  132. \t/* In case enclave `%s' doesn't call any tRTS function. */\n\
  133. \tvolatile int force_link_trts = sgx_is_within_enclave(NULL, 0);\n\
  134. \t(void) force_link_trts; /* avoid compiler warning */\n\
  135. #endif\n\n" ec.enclave_name
  136. in
  137. if ec.ufunc_decls <> [] then ""
  138. else
  139. if List.for_all (fun tfd -> is_naked_func tfd.Ast.tf_fdecl) ec.tfunc_decls
  140. then _dummy_variable
  141. else ""
  142. (* This function is used to convert Array form into Pointer form.
  143. * e.g.: int array[10][20] => [count = 200] int* array
  144. *
  145. * This function is called when generating proxy/bridge code and
  146. * the marshaling structure.
  147. *)
  148. let conv_array_to_ptr (pd: Ast.pdecl): Ast.pdecl =
  149. let (pt, declr) = pd in
  150. let get_count_attr ilist =
  151. (* XXX: assume the size of each dimension will be > 0. *)
  152. Ast.ANumber (List.fold_left (fun acc i -> acc*i) 1 ilist)
  153. in
  154. match pt with
  155. Ast.PTVal _ -> (pt, declr)
  156. | Ast.PTPtr(aty, pa) ->
  157. if Ast.is_array declr then
  158. let tmp_declr = { declr with Ast.array_dims = [] } in
  159. let tmp_aty = Ast.Ptr aty in
  160. let tmp_cnt = get_count_attr declr.Ast.array_dims in
  161. let tmp_pa = { pa with Ast.pa_size = { Ast.empty_ptr_size with Ast.ps_count = Some tmp_cnt } }
  162. in (Ast.PTPtr(tmp_aty, tmp_pa), tmp_declr)
  163. else (pt, declr)
  164. (* ------------------------------------------------------------------
  165. * Code generation for edge-routines.
  166. * ------------------------------------------------------------------
  167. *)
  168. (* Little functions for naming of a struct and its members etc *)
  169. let retval_name = "retval"
  170. let retval_declr = { Ast.identifier = retval_name; Ast.array_dims = []; }
  171. let eid_name = "eid"
  172. let ms_ptr_name = "pms"
  173. let ms_struct_val = "ms"
  174. let mk_ms_member_name (pname: string) = "ms_" ^ pname
  175. let mk_ms_struct_name (fname: string) = "ms_" ^ fname ^ "_t"
  176. let ms_retval_name = mk_ms_member_name retval_name
  177. let mk_tbridge_name (fname: string) = "sgx_" ^ fname
  178. let mk_parm_accessor name = sprintf "%s->%s" ms_struct_val (mk_ms_member_name name)
  179. let mk_tmp_var name = "_tmp_" ^ name
  180. let mk_len_var name = "_len_" ^ name
  181. let mk_in_var name = "_in_" ^ name
  182. let mk_ocall_table_name enclave_name = "ocall_table_" ^ enclave_name
  183. (* Un-trusted bridge name is prefixed with enclave file short name. *)
  184. let mk_ubridge_name (file_shortnm: string) (funcname: string) =
  185. sprintf "%s_%s" file_shortnm funcname
  186. let mk_ubridge_proto (file_shortnm: string) (funcname: string) =
  187. sprintf "static sgx_status_t SGX_CDECL %s(void* %s)"
  188. (mk_ubridge_name file_shortnm funcname) ms_ptr_name
  189. (* Common macro definitions. *)
  190. let common_macros = "#include <stdlib.h> /* for size_t */\n\n\
  191. #define SGX_CAST(type, item) ((type)(item))\n\n\
  192. #ifdef __cplusplus\n\
  193. extern \"C\" {\n\
  194. #endif\n"
  195. (* Header footer *)
  196. let header_footer = "\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n\n#endif\n"
  197. (* Little functions for generating file names. *)
  198. let get_uheader_short_name (file_shortnm: string) = file_shortnm ^ "_u.h"
  199. let get_uheader_name (file_shortnm: string) =
  200. !g_untrusted_dir ^ separator_str ^ (get_uheader_short_name file_shortnm)
  201. let get_usource_name (file_shortnm: string) =
  202. !g_untrusted_dir ^ separator_str ^ file_shortnm ^ "_u.c"
  203. let get_theader_short_name (file_shortnm: string) = file_shortnm ^ "_t.h"
  204. let get_theader_name (file_shortnm: string) =
  205. !g_trusted_dir ^ separator_str ^ (get_theader_short_name file_shortnm)
  206. let get_tsource_name (file_shortnm: string) =
  207. !g_trusted_dir ^ separator_str ^ file_shortnm ^ "_t.c"
  208. (* Construct the string of structure definition *)
  209. let mk_struct_decl (fs: string) (name: string) =
  210. sprintf "typedef struct %s {\n%s} %s;\n" name fs name
  211. (* Construct the string of union definition *)
  212. let mk_union_decl (fs: string) (name: string) =
  213. sprintf "typedef union %s {\n%s} %s;\n" name fs name
  214. (* Generate a definition of enum *)
  215. let mk_enum_def (e: Ast.enum_def) =
  216. let gen_enum_ele_str (ele: Ast.enum_ele) =
  217. let k, v = ele in
  218. match v with
  219. Ast.EnumValNone -> k
  220. | Ast.EnumVal ev -> sprintf "%s = %s" k (Ast.attr_value_to_string ev)
  221. in
  222. let enname = e.Ast.enname in
  223. let enbody = e.Ast.enbody in
  224. let enbody_str =
  225. if enbody = [] then ""
  226. else List.fold_left (fun acc ele ->
  227. acc ^ "\t" ^ gen_enum_ele_str ele ^ ",\n") "" enbody
  228. in
  229. if enname = "" then sprintf "enum {\n%s};\n" enbody_str
  230. else sprintf "typedef enum %s {\n%s} %s;\n" enname enbody_str enname
  231. let get_array_dims (ns: int list) =
  232. (* Get the array declaration from a list of array dimensions.
  233. * Empty `ns' indicates the corresponding declarator is a simple identifier.
  234. * Element of value -1 means that user does not specify the dimension size.
  235. *)
  236. let get_dim n = if n = -1 then "[]" else sprintf "[%d]" n
  237. in
  238. if ns = [] then ""
  239. else List.fold_left (fun acc n -> acc ^ get_dim n) "" ns
  240. let get_typed_declr_str (ty: Ast.atype) (declr: Ast.declarator) =
  241. let tystr = Ast.get_tystr ty in
  242. let dmstr = get_array_dims declr.Ast.array_dims in
  243. sprintf "%s %s%s" tystr declr.Ast.identifier dmstr
  244. (* Construct a member declaration string *)
  245. let mk_member_decl (ty: Ast.atype) (declr: Ast.declarator) =
  246. sprintf "\t%s;\n" (get_typed_declr_str ty declr)
  247. (* Note that, for a foreign array type `foo_array_t' we will generate
  248. * foo_array_t* ms_field;
  249. * in the marshaling data structure to keep the pass-by-address scheme
  250. * as in the C programming language.
  251. *)
  252. let mk_ms_member_decl (pt: Ast.parameter_type) (declr: Ast.declarator) (isecall: bool) =
  253. let aty = Ast.get_param_atype pt in
  254. let tystr = Ast.get_tystr aty in
  255. let ptr = if is_foreign_array pt then "* " else "" in
  256. let field = mk_ms_member_name declr.Ast.identifier in
  257. (* String attribute is available for in/inout both ecall and ocall.
  258. * For ocall ,strlen is called in trusted proxy ocde, so no need to defense it.
  259. *)
  260. let need_str_len_var (pt: Ast.parameter_type) =
  261. match pt with
  262. Ast.PTVal _ -> false
  263. | Ast.PTPtr(_, pa) ->
  264. if pa.Ast.pa_isstr || pa.Ast.pa_iswstr then
  265. match pa.Ast.pa_direction with
  266. Ast.PtrInOut | Ast.PtrIn -> if isecall then true else false
  267. | _ -> false
  268. else false
  269. in
  270. let str_len = if need_str_len_var pt then sprintf "\tsize_t %s_len;\n" field else ""
  271. in
  272. let dmstr = get_array_dims declr.Ast.array_dims in
  273. sprintf "\t%s%s %s%s;\n%s" tystr ptr field dmstr str_len
  274. (* Generate data structure definition *)
  275. let gen_comp_def (st: Ast.composite_type) =
  276. let gen_member_list mlist =
  277. List.fold_left (fun acc (ty, declr) ->
  278. acc ^ mk_member_decl ty declr) "" mlist
  279. in
  280. match st with
  281. Ast.StructDef s -> mk_struct_decl (gen_member_list s.Ast.mlist) s.Ast.sname
  282. | Ast.UnionDef u -> mk_union_decl (gen_member_list u.Ast.mlist) u.Ast.sname
  283. | Ast.EnumDef e -> mk_enum_def e
  284. (* Generate a list of '#include' *)
  285. let gen_include_list (xs: string list) =
  286. List.fold_left (fun acc s -> acc ^ sprintf "#include \"%s\"\n" s) "" xs
  287. (* Get the type string from 'parameter_type' *)
  288. let get_param_tystr (pt: Ast.parameter_type) =
  289. Ast.get_tystr (Ast.get_param_atype pt)
  290. (* Generate marshaling structure definition *)
  291. let gen_marshal_struct (fd: Ast.func_decl) (errno: string) (isecall: bool) =
  292. let member_list_str = errno ^
  293. let new_param_list = List.map conv_array_to_ptr fd.Ast.plist in
  294. List.fold_left (fun acc (pt, declr) ->
  295. acc ^ mk_ms_member_decl pt declr isecall) "" new_param_list in
  296. let struct_name = mk_ms_struct_name fd.Ast.fname in
  297. match fd.Ast.rtype with
  298. (* A function w/o return value and parameters doesn't need
  299. a marshaling struct. *)
  300. Ast.Void -> if fd.Ast.plist = [] && errno = "" then ""
  301. else mk_struct_decl member_list_str struct_name
  302. | _ -> let rv_str = mk_ms_member_decl (Ast.PTVal fd.Ast.rtype) retval_declr isecall
  303. in mk_struct_decl (rv_str ^ member_list_str) struct_name
  304. let gen_ecall_marshal_struct (tf: Ast.trusted_func) =
  305. gen_marshal_struct tf.Ast.tf_fdecl "" true
  306. let gen_ocall_marshal_struct (uf: Ast.untrusted_func) =
  307. let errno_decl = if uf.Ast.uf_propagate_errno then "\tint ocall_errno;\n" else "" in
  308. gen_marshal_struct uf.Ast.uf_fdecl errno_decl false
  309. (* Check whether given parameter is `const' specified. *)
  310. let is_const_ptr (pt: Ast.parameter_type) =
  311. let aty = Ast.get_param_atype pt in
  312. match pt with
  313. Ast.PTVal _ -> false
  314. | Ast.PTPtr(_, pa) ->
  315. if not pa.Ast.pa_rdonly then false
  316. else
  317. match aty with
  318. Ast.Foreign _ -> false
  319. | _ -> true
  320. (* Generate parameter representation. *)
  321. let gen_parm_str (p: Ast.pdecl) =
  322. let (pt, (declr : Ast.declarator)) = p in
  323. let aty = Ast.get_param_atype pt in
  324. let str = get_typed_declr_str aty declr in
  325. if is_const_ptr pt then "const " ^ str else str
  326. (* Generate parameter representation of return value. *)
  327. let gen_parm_retval (rt: Ast.atype) =
  328. if rt = Ast.Void then ""
  329. else Ast.get_tystr rt ^ "* " ^ retval_name
  330. (* ---------------------------------------------------------------------- *)
  331. (* `gen_ecall_table' is used to generate ECALL table with the following form:
  332. SGX_EXTERNC const struct {
  333. size_t nr_ecall; /* number of ECALLs */
  334. struct {
  335. void *ecall_addr;
  336. uint8_t is_priv;
  337. } ecall_table [nr_ecall];
  338. } g_ecall_table = {
  339. 2, { {sgx_foo, 1}, {sgx_bar, 0} }
  340. };
  341. *)
  342. let gen_ecall_table (tfs: Ast.trusted_func list) =
  343. let ecall_table_name = "g_ecall_table" in
  344. let ecall_table_size = List.length tfs in
  345. let trusted_fds = tf_list_to_fd_list tfs in
  346. let priv_bits = tf_list_to_priv_list tfs in
  347. let tbridge_names = List.map (fun (fd: Ast.func_decl) ->
  348. mk_tbridge_name fd.Ast.fname) trusted_fds in
  349. let ecall_table =
  350. let bool_to_int b = if b then 1 else 0 in
  351. let inner_table =
  352. List.fold_left2 (fun acc s b ->
  353. sprintf "%s\t\t{(void*)(uintptr_t)%s, %d},\n" acc s (bool_to_int b)) "" tbridge_names priv_bits
  354. in "\t{\n" ^ inner_table ^ "\t}\n"
  355. in
  356. sprintf "SGX_EXTERNC const struct {\n\
  357. \tsize_t nr_ecall;\n\
  358. \tstruct {void* ecall_addr; uint8_t is_priv;} ecall_table[%d];\n\
  359. } %s = {\n\
  360. \t%d,\n\
  361. %s};\n" ecall_table_size
  362. ecall_table_name
  363. ecall_table_size
  364. (if ecall_table_size = 0 then "" else ecall_table)
  365. (* `gen_entry_table' is used to generate Dynamic Entry Table with the form:
  366. SGX_EXTERNC const struct {
  367. /* number of OCALLs (number of ECALLs can be found in ECALL table) */
  368. size_t nr_ocall;
  369. /* entry_table[m][n] = 1 iff. ECALL n is allowed in the OCALL m. */
  370. uint8_t entry_table[NR_OCALL][NR_ECALL];
  371. } g_dyn_entry_table = {
  372. 3, {{0, 0}, {0, 1}, {1, 0}}
  373. };
  374. *)
  375. let gen_entry_table (ec: enclave_content) =
  376. let dyn_entry_table_name = "g_dyn_entry_table" in
  377. let ocall_table_size = List.length ec.ufunc_decls in
  378. let trusted_func_names = get_trusted_func_names ec in
  379. let ecall_table_size = List.length trusted_func_names in
  380. let get_entry_array (allowed_ecalls: string list) =
  381. List.fold_left (fun acc name ->
  382. acc ^ (if List.exists (fun x -> x=name) allowed_ecalls
  383. then "1"
  384. else "0") ^ ", ") "" trusted_func_names in
  385. let entry_table =
  386. let inner_table =
  387. List.fold_left (fun acc (uf: Ast.untrusted_func) ->
  388. let entry_array = get_entry_array uf.Ast.uf_allow_list
  389. in acc ^ "\t\t{" ^ entry_array ^ "},\n") "" ec.ufunc_decls
  390. in
  391. "\t{\n" ^ inner_table ^ "\t}\n"
  392. in
  393. (* Generate dynamic entry table iff. both sgx_ecall/ocall_table_size > 0 *)
  394. let gen_table_p = (ecall_table_size > 0) && (ocall_table_size > 0) in
  395. (* When NR_ECALL is 0, or NR_OCALL is 0, there will be no entry table field. *)
  396. let entry_table_field =
  397. if gen_table_p then
  398. sprintf "\tuint8_t entry_table[%d][%d];\n" ocall_table_size ecall_table_size
  399. else
  400. ""
  401. in
  402. sprintf "SGX_EXTERNC const struct {\n\
  403. \tsize_t nr_ocall;\n%s\
  404. } %s = {\n\
  405. \t%d,\n\
  406. %s};\n" entry_table_field
  407. dyn_entry_table_name
  408. ocall_table_size
  409. (if gen_table_p then entry_table else "")
  410. (* ---------------------------------------------------------------------- *)
  411. (* Generate the function prototype for untrusted proxy in COM style.
  412. * For example, un-trusted functions
  413. * int foo(double d);
  414. * void bar(float f);
  415. *
  416. * will have an untrusted proxy like below:
  417. * sgx_status_t foo(int* retval, double d);
  418. * sgx_status_t bar(float f);
  419. *)
  420. let gen_tproxy_proto (fd: Ast.func_decl) =
  421. let parm_list =
  422. match fd.Ast.plist with
  423. [] -> ""
  424. | x :: xs ->
  425. List.fold_left (fun acc pd ->
  426. acc ^ ", " ^ gen_parm_str pd) (gen_parm_str x) xs
  427. in
  428. let retval_parm_str = gen_parm_retval fd.Ast.rtype in
  429. if fd.Ast.plist = [] then
  430. sprintf "sgx_status_t SGX_CDECL %s(%s)" fd.Ast.fname retval_parm_str
  431. else if fd.Ast.rtype = Ast.Void then
  432. sprintf "sgx_status_t SGX_CDECL %s(%s)" fd.Ast.fname parm_list
  433. else
  434. sprintf "sgx_status_t SGX_CDECL %s(%s, %s)" fd.Ast.fname retval_parm_str parm_list
  435. (* Generate the function prototype for untrusted proxy in COM style.
  436. * For example, trusted functions
  437. * int foo(double d);
  438. * void bar(float f);
  439. *
  440. * will have an untrusted proxy like below:
  441. * sgx_status_t foo(sgx_enclave_id_t eid, int* retval, double d);
  442. * sgx_status_t foo(sgx_enclave_id_t eid, float f);
  443. *
  444. * When `g_use_prefix' is true, the untrusted proxy name is prefixed
  445. * with the `prefix' parameter.
  446. *
  447. *)
  448. let gen_uproxy_com_proto (fd: Ast.func_decl) (prefix: string) =
  449. let retval_parm_str = gen_parm_retval fd.Ast.rtype in
  450. let eid_parm_str =
  451. if fd.Ast.rtype = Ast.Void then sprintf "(sgx_enclave_id_t %s" eid_name
  452. else sprintf "(sgx_enclave_id_t %s, " eid_name in
  453. let parm_list =
  454. List.fold_left (fun acc pd -> acc ^ ", " ^ gen_parm_str pd)
  455. retval_parm_str fd.Ast.plist in
  456. let fname =
  457. if !g_use_prefix then sprintf "%s_%s" prefix fd.Ast.fname
  458. else fd.Ast.fname
  459. in "sgx_status_t " ^ fname ^ eid_parm_str ^ parm_list ^ ")"
  460. let get_ret_tystr (fd: Ast.func_decl) = Ast.get_tystr fd.Ast.rtype
  461. let get_plist_str (fd: Ast.func_decl) =
  462. if fd.Ast.plist = [] then ""
  463. else List.fold_left (fun acc pd -> acc ^ ", " ^ gen_parm_str pd)
  464. (gen_parm_str (List.hd fd.Ast.plist))
  465. (List.tl fd.Ast.plist)
  466. (* Generate the function prototype as is. *)
  467. let gen_func_proto (fd: Ast.func_decl) =
  468. let ret_tystr = get_ret_tystr fd in
  469. let plist_str = get_plist_str fd in
  470. sprintf "%s %s(%s)" ret_tystr fd.Ast.fname plist_str
  471. (* Generate prototypes for untrusted function. *)
  472. let gen_ufunc_proto (uf: Ast.untrusted_func) =
  473. let dllimport = if uf.Ast.uf_fattr.Ast.fa_dllimport then "SGX_DLLIMPORT " else "" in
  474. let ret_tystr = get_ret_tystr uf.Ast.uf_fdecl in
  475. let cconv_str = "SGX_" ^ Ast.get_call_conv_str uf.Ast.uf_fattr.Ast.fa_convention in
  476. let func_name = uf.Ast.uf_fdecl.Ast.fname in
  477. let plist_str = get_plist_str uf.Ast.uf_fdecl in
  478. sprintf "%s%s SGX_UBRIDGE(%s, %s, (%s))"
  479. dllimport ret_tystr cconv_str func_name plist_str
  480. (* The preemble contains common include expressions. *)
  481. let gen_uheader_preemble (guard: string) (inclist: string)=
  482. let grd_hdr = sprintf "#ifndef %s\n#define %s\n\n" guard guard in
  483. let inc_exp = "#include <stdint.h>\n\
  484. #include <wchar.h>\n\
  485. #include <stddef.h>\n\
  486. #include <string.h>\n\
  487. #include \"sgx_edger8r.h\" /* for sgx_satus_t etc. */\n" in
  488. grd_hdr ^ inc_exp ^ "\n" ^ inclist ^ "\n" ^ common_macros
  489. let ms_writer out_chan ec =
  490. let ms_struct_ecall = List.map gen_ecall_marshal_struct ec.tfunc_decls in
  491. let ms_struct_ocall = List.map gen_ocall_marshal_struct ec.ufunc_decls in
  492. let output_struct s =
  493. match s with
  494. "" -> s
  495. | _ -> sprintf "%s\n" s
  496. in
  497. List.iter (fun s -> output_string out_chan (output_struct s)) ms_struct_ecall;
  498. List.iter (fun s -> output_string out_chan (output_struct s)) ms_struct_ocall
  499. (* Generate untrusted header for enclave *)
  500. let gen_untrusted_header (ec: enclave_content) =
  501. let header_fname = get_uheader_name ec.file_shortnm in
  502. let guard_macro = sprintf "%s_U_H__" (String.uppercase ec.enclave_name) in
  503. let preemble_code =
  504. let include_list = gen_include_list (ec.include_list @ !untrusted_headers) in
  505. gen_uheader_preemble guard_macro include_list
  506. in
  507. let comp_def_list = List.map gen_comp_def ec.comp_defs in
  508. let func_proto_ufunc = List.map gen_ufunc_proto ec.ufunc_decls in
  509. let uproxy_com_proto =
  510. List.map (fun (tf: Ast.trusted_func) ->
  511. gen_uproxy_com_proto tf.Ast.tf_fdecl ec.enclave_name)
  512. ec.tfunc_decls
  513. in
  514. let out_chan = open_out header_fname in
  515. output_string out_chan (preemble_code ^ "\n");
  516. List.iter (fun s -> output_string out_chan (s ^ "\n")) comp_def_list;
  517. List.iter (fun s -> output_string out_chan (s ^ ";\n")) func_proto_ufunc;
  518. output_string out_chan "\n";
  519. List.iter (fun s -> output_string out_chan (s ^ ";\n")) uproxy_com_proto;
  520. output_string out_chan header_footer;
  521. close_out out_chan
  522. (* It generates preemble for trusted header file. *)
  523. let gen_theader_preemble (guard: string) (inclist: string) =
  524. let grd_hdr = sprintf "#ifndef %s\n#define %s\n\n" guard guard in
  525. let inc_exp = "#include <stdint.h>\n\
  526. #include <wchar.h>\n\
  527. #include <stddef.h>\n\
  528. #include \"sgx_edger8r.h\" /* for sgx_ocall etc. */\n\n" in
  529. grd_hdr ^ inc_exp ^ inclist ^ "\n" ^ common_macros
  530. (* Generate trusted header for enclave *)
  531. let gen_trusted_header (ec: enclave_content) =
  532. let header_fname = get_theader_name ec.file_shortnm in
  533. let guard_macro = sprintf "%s_T_H__" (String.uppercase ec.enclave_name) in
  534. let guard_code =
  535. let include_list = gen_include_list (ec.include_list @ !trusted_headers) in
  536. gen_theader_preemble guard_macro include_list in
  537. let comp_def_list = List.map gen_comp_def ec.comp_defs in
  538. let func_proto_list = List.map gen_func_proto (tf_list_to_fd_list ec.tfunc_decls) in
  539. let func_tproxy_list= List.map gen_tproxy_proto (uf_list_to_fd_list ec.ufunc_decls) in
  540. let out_chan = open_out header_fname in
  541. output_string out_chan (guard_code ^ "\n");
  542. List.iter (fun s -> output_string out_chan (s ^ "\n")) comp_def_list;
  543. List.iter (fun s -> output_string out_chan (s ^ ";\n")) func_proto_list;
  544. output_string out_chan "\n";
  545. List.iter (fun s -> output_string out_chan (s ^ ";\n")) func_tproxy_list;
  546. output_string out_chan header_footer;
  547. close_out out_chan
  548. (* It generates function invocation expression. *)
  549. let mk_parm_name_raw (pt: Ast.parameter_type) (declr: Ast.declarator) =
  550. let cast_expr =
  551. let tystr = get_param_tystr pt in
  552. if Ast.is_array declr && List.length declr.Ast.array_dims > 1
  553. then
  554. let dims = get_array_dims (List.tl declr.Ast.array_dims) in
  555. sprintf "(%s (*)%s)" tystr dims
  556. else if is_const_ptr pt then
  557. sprintf "(const %s)" tystr
  558. else ""
  559. in
  560. cast_expr ^ mk_parm_accessor declr.Ast.identifier
  561. (* We passed foreign array `foo_array_t foo' as `&foo[0]', thus we
  562. * need to get back `foo' by '* array_ptr' where
  563. * array_ptr = &foo[0]
  564. *)
  565. let add_foreign_array_ptrref
  566. (f: Ast.parameter_type -> Ast.declarator -> string)
  567. (pt: Ast.parameter_type)
  568. (declr: Ast.declarator) =
  569. let arg = f pt declr in
  570. if is_foreign_array pt
  571. then sprintf "(%s != NULL) ? (*%s) : NULL" arg arg
  572. else arg
  573. let mk_parm_name_ubridge (pt: Ast.parameter_type) (declr: Ast.declarator) =
  574. add_foreign_array_ptrref mk_parm_name_raw pt declr
  575. let mk_parm_name_ext (pt: Ast.parameter_type) (declr: Ast.declarator) =
  576. let name = declr.Ast.identifier in
  577. match pt with
  578. Ast.PTVal _ -> mk_parm_name_raw pt declr
  579. | Ast.PTPtr (_, attr) ->
  580. match attr.Ast.pa_direction with
  581. | Ast.PtrNoDirection -> mk_parm_name_raw pt declr
  582. | _ -> mk_in_var name
  583. let gen_func_invoking (fd: Ast.func_decl)
  584. (mk_parm_name: Ast.parameter_type -> Ast.declarator -> string) =
  585. match fd.Ast.plist with
  586. [] -> sprintf "%s();" fd.Ast.fname
  587. | (pt, (declr : Ast.declarator)) :: ps ->
  588. sprintf "%s(%s);"
  589. fd.Ast.fname
  590. (let p0 = mk_parm_name pt declr in
  591. List.fold_left (fun acc (pty, dlr) ->
  592. acc ^ ", " ^ mk_parm_name pty dlr) p0 ps)
  593. (* Generate untrusted bridge code for a given untrusted function. *)
  594. let gen_func_ubridge (file_shortnm: string) (ufunc: Ast.untrusted_func) =
  595. let fd = ufunc.Ast.uf_fdecl in
  596. let propagate_errno = ufunc.Ast.uf_propagate_errno in
  597. let func_open = sprintf "%s\n{\n" (mk_ubridge_proto file_shortnm fd.Ast.fname) in
  598. let func_close = "\treturn SGX_SUCCESS;\n}\n" in
  599. let set_errno = if propagate_errno then "\tms->ocall_errno = errno;" else "" in
  600. let ms_struct_name = mk_ms_struct_name fd.Ast.fname in
  601. let declare_ms_ptr = sprintf "%s* %s = SGX_CAST(%s*, %s);"
  602. ms_struct_name
  603. ms_struct_val
  604. ms_struct_name
  605. ms_ptr_name in
  606. let call_with_pms =
  607. let invoke_func = gen_func_invoking fd mk_parm_name_ubridge in
  608. if fd.Ast.rtype = Ast.Void then invoke_func
  609. else sprintf "%s = %s" (mk_parm_accessor retval_name) invoke_func
  610. in
  611. if (is_naked_func fd) && (propagate_errno = false) then
  612. let check_pms =
  613. sprintf "if (%s != NULL) return SGX_ERROR_INVALID_PARAMETER;" ms_ptr_name
  614. in
  615. sprintf "%s\t%s\n\t%s\n%s" func_open check_pms call_with_pms func_close
  616. else
  617. sprintf "%s\t%s\n\t%s\n%s\n%s" func_open declare_ms_ptr call_with_pms set_errno func_close
  618. let fill_ms_field (isptr: bool) (pd: Ast.pdecl) =
  619. let accessor = if isptr then "->" else "." in
  620. let (pt, declr) = pd in
  621. let param_name = declr.Ast.identifier in
  622. let ms_member_name = mk_ms_member_name param_name in
  623. let assignment_str (use_cast: bool) (aty: Ast.atype) =
  624. let cast_str = if use_cast then sprintf "(%s)" (Ast.get_tystr aty) else ""
  625. in
  626. sprintf "%s%s%s = %s%s;" ms_struct_val accessor ms_member_name cast_str param_name
  627. in
  628. let gen_setup_foreign_array aty =
  629. sprintf "%s%s%s = (%s *)&%s[0];"
  630. ms_struct_val accessor ms_member_name (Ast.get_tystr aty) param_name
  631. in
  632. let gen_setup_foreign_str aty =
  633. sprintf "%s%s%s_len = %s ? strlen(%s) + 1 : 0;"
  634. ms_struct_val accessor ms_member_name param_name param_name
  635. in
  636. let gen_setup_foreign_wstr aty =
  637. sprintf "%s%s%s_len = %s ? (wcslen(%s) + 1) * sizeof(wchar_t) : 0;"
  638. ms_struct_val accessor ms_member_name param_name param_name
  639. in
  640. if declr.Ast.array_dims = [] then
  641. match pt with
  642. Ast.PTVal(aty) -> assignment_str false aty
  643. | Ast.PTPtr(aty, pattr) ->
  644. if pattr.Ast.pa_isary
  645. then gen_setup_foreign_array aty
  646. else if pattr.Ast.pa_isstr
  647. then assignment_str true aty ^ "\n\t" ^ gen_setup_foreign_str aty
  648. else if pattr.Ast.pa_iswstr
  649. then assignment_str true aty ^ "\n\t" ^ gen_setup_foreign_wstr aty
  650. else
  651. if pattr.Ast.pa_rdonly then assignment_str true aty
  652. else assignment_str false aty
  653. else
  654. (* Arrays are passed by address. *)
  655. let tystr = Ast.get_tystr (Ast.Ptr (Ast.get_param_atype pt)) in
  656. sprintf "%s%s%s = (%s)%s;" ms_struct_val accessor ms_member_name tystr param_name
  657. (* Generate untrusted proxy code for a given trusted function. *)
  658. let gen_func_uproxy (fd: Ast.func_decl) (idx: int) (ec: enclave_content) =
  659. let func_open =
  660. gen_uproxy_com_proto fd ec.enclave_name ^
  661. "\n{\n\tsgx_status_t status;\n"
  662. in
  663. let func_close = "\treturn status;\n}\n" in
  664. let ocall_table_name = mk_ocall_table_name ec.enclave_name in
  665. let ms_struct_name = mk_ms_struct_name fd.Ast.fname in
  666. let declare_ms_expr = sprintf "%s %s;" ms_struct_name ms_struct_val in
  667. let ocall_table_ptr =
  668. sprintf "&%s" ocall_table_name in
  669. (* Normal case - do ECALL with marshaling structure*)
  670. let ecall_with_ms = sprintf "status = sgx_ecall(%s, %d, %s, &%s);"
  671. eid_name idx ocall_table_ptr ms_struct_val in
  672. (* Rare case - the trusted function doesn't have parameter nor return value.
  673. * In this situation, no marshaling structure is required - passing in NULL.
  674. *)
  675. let ecall_null = sprintf "status = sgx_ecall(%s, %d, %s, NULL);"
  676. eid_name idx ocall_table_ptr
  677. in
  678. let update_retval = sprintf "if (status == SGX_SUCCESS && %s) *%s = %s.%s;"
  679. retval_name retval_name ms_struct_val ms_retval_name in
  680. let func_body = ref [] in
  681. if is_naked_func fd then
  682. sprintf "%s\t%s\n%s" func_open ecall_null func_close
  683. else
  684. begin
  685. func_body := declare_ms_expr :: !func_body;
  686. List.iter (fun pd -> func_body := fill_ms_field false pd :: !func_body) fd.Ast.plist;
  687. func_body := ecall_with_ms :: !func_body;
  688. if fd.Ast.rtype <> Ast.Void then func_body := update_retval :: !func_body;
  689. List.fold_left (fun acc s -> acc ^ "\t" ^ s ^ "\n") func_open (List.rev !func_body) ^ func_close
  690. end
  691. (* Generate an expression to check the pointers. *)
  692. let mk_check_ptr (name: string) (lenvar: string) =
  693. let checker = "CHECK_UNIQUE_POINTER"
  694. in sprintf "\t%s(%s, %s);\n" checker name lenvar
  695. (* Pointer to marshaling structure should never be NULL. *)
  696. let mk_check_pms (fname: string) =
  697. let lenvar = sprintf "sizeof(%s)" (mk_ms_struct_name fname)
  698. in sprintf "\t%s(%s, %s);%s" "CHECK_REF_POINTER" ms_ptr_name lenvar
  699. "\n\t//\n\t// fence after pointer checks\n\t//\n\tsgx_lfence();\n"
  700. (* Generate code to get the size of the pointer. *)
  701. let gen_ptr_size (ty: Ast.atype) (pattr: Ast.ptr_attr) (name: string) (get_parm: string -> string) =
  702. let len_var = mk_len_var name in
  703. let parm_name = get_parm name in
  704. let mk_len_size v =
  705. match v with
  706. Ast.AString s -> get_parm s
  707. | Ast.ANumber n -> sprintf "%d" n in
  708. let mk_len_count v size_str =
  709. match v with
  710. Ast.AString s -> sprintf "%s * %s" (get_parm s) size_str
  711. | Ast.ANumber n -> sprintf "%d * %s" n size_str in
  712. let do_ps_attribute (sattr: Ast.ptr_size) =
  713. let size_str =
  714. match sattr.Ast.ps_size with
  715. Some a -> mk_len_size a
  716. | None -> sprintf "sizeof(*%s)" parm_name
  717. in
  718. match sattr.Ast.ps_count with
  719. None -> size_str
  720. | Some a -> mk_len_count a size_str
  721. in
  722. sprintf "size_t %s = %s;\n"
  723. len_var
  724. (if pattr.Ast.pa_isary then
  725. sprintf "sizeof(%s)" (Ast.get_tystr ty)
  726. else
  727. (* genrerate ms_parm_len only for ecall with string/wstring in _t.c.*)
  728. if (pattr.Ast.pa_isstr || pattr.Ast.pa_iswstr) && parm_name <> name then
  729. sprintf "%s_len " (mk_parm_accessor name)
  730. else
  731. (* genrerate strlen(param)/wcslen(param) only for ocall with string/wstring in _t.c.*)
  732. if pattr.Ast.pa_isstr then
  733. sprintf "%s ? strlen(%s) + 1 : 0" parm_name parm_name
  734. else
  735. if pattr.Ast.pa_iswstr then
  736. sprintf "%s ? (wcslen(%s) + 1) * sizeof(wchar_t) : 0" parm_name parm_name
  737. else do_ps_attribute pattr.Ast.pa_size)
  738. (* Find the data type of a parameter. *)
  739. let find_param_type (name: string) (plist: Ast.pdecl list) =
  740. try
  741. let (pt, _) = List.find (fun (pd: Ast.pdecl) ->
  742. let (pt, declr) = pd
  743. in declr.Ast.identifier = name) plist
  744. in get_param_tystr pt
  745. with
  746. Not_found -> failwithf "parameter `%s' not found." name
  747. (* Generate code to check the length of buffers. *)
  748. let gen_check_tbridge_length_overflow (plist: Ast.pdecl list) =
  749. let gen_check_length (ty: Ast.atype) (attr: Ast.ptr_attr) (declr: Ast.declarator) =
  750. let name = declr.Ast.identifier in
  751. let tmp_ptr_name= mk_tmp_var name in
  752. let mk_len_size v =
  753. match v with
  754. Ast.AString s -> mk_tmp_var s
  755. | Ast.ANumber n -> sprintf "%d" n in
  756. let gen_check_overflow cnt size_str =
  757. let if_statement =
  758. match cnt with
  759. Ast.AString s -> sprintf "\tif (%s != 0 &&\n\t\t(size_t)%s > (SIZE_MAX / %s)) {\n" size_str (mk_tmp_var s) size_str
  760. | Ast.ANumber n -> sprintf "\tif (%s != 0 &&\n\t\t%d > (SIZE_MAX / %s)) {\n" size_str n size_str
  761. in
  762. sprintf "%s\t\treturn SGX_ERROR_INVALID_PARAMETER;\n\t}" if_statement
  763. in
  764. let size_str =
  765. match attr.Ast.pa_size.Ast.ps_size with
  766. Some a -> mk_len_size a
  767. | None -> sprintf "sizeof(*%s)" tmp_ptr_name
  768. in
  769. match attr.Ast.pa_size.Ast.ps_count with
  770. None -> ""
  771. | Some a -> sprintf "%s\n\n" (gen_check_overflow a size_str)
  772. in
  773. List.fold_left
  774. (fun acc (pty, declr) ->
  775. match pty with
  776. Ast.PTVal _ -> acc
  777. | Ast.PTPtr(ty, attr) -> acc ^ gen_check_length ty attr declr) "" plist
  778. (* Generate code to check all function parameters which are pointers. *)
  779. let gen_check_tbridge_ptr_parms (plist: Ast.pdecl list) =
  780. let gen_check_ptr (ty: Ast.atype) (pattr: Ast.ptr_attr) (declr: Ast.declarator) =
  781. if not pattr.Ast.pa_chkptr then ""
  782. else
  783. let name = declr.Ast.identifier in
  784. let len_var = mk_len_var name in
  785. let parm_name = mk_tmp_var name in
  786. if pattr.Ast.pa_chkptr
  787. then mk_check_ptr parm_name len_var
  788. else ""
  789. in
  790. let new_param_list = List.map conv_array_to_ptr plist
  791. in
  792. let pointer_checkings =
  793. List.fold_left
  794. (fun acc (pty, declr) ->
  795. match pty with
  796. Ast.PTVal _ -> acc
  797. | Ast.PTPtr(ty, attr) -> acc ^ gen_check_ptr ty attr declr) "" new_param_list
  798. in
  799. if pointer_checkings = "" then ""
  800. else pointer_checkings ^ "\n\t//\n\t// fence after pointer checks\n\t//\n\tsgx_lfence();\n"
  801. (* If a foreign type is a readonly pointer, we cast it to 'void*' for memcpy() and free() *)
  802. let mk_in_ptr_dst_name (rdonly: bool) (ptr_name: string) =
  803. if rdonly then "(void*)" ^ ptr_name
  804. else ptr_name
  805. (* Generate the code to handle function pointer parameter direction,
  806. * which is to be inserted before actually calling the trusted function.
  807. *)
  808. let gen_parm_ptr_direction_pre (plist: Ast.pdecl list) =
  809. let clone_in_ptr (ty: Ast.atype) (attr: Ast.ptr_attr) (declr: Ast.declarator) =
  810. let name = declr.Ast.identifier in
  811. let is_ary = (Ast.is_array declr || attr.Ast.pa_isary) in
  812. let in_ptr_name = mk_in_var name in
  813. let in_ptr_type = sprintf "%s%s" (Ast.get_tystr ty) (if is_ary then "*" else "") in
  814. let len_var = mk_len_var name in
  815. let in_ptr_dst_name = mk_in_ptr_dst_name attr.Ast.pa_rdonly in_ptr_name in
  816. let tmp_ptr_name= mk_tmp_var name in
  817. let malloc_and_copy pre_indent =
  818. match attr.Ast.pa_direction with
  819. Ast.PtrIn | Ast.PtrInOut ->
  820. let wstr_len_check =
  821. if attr.Ast.pa_iswstr then
  822. let wstr_len_check_template = [
  823. sprintf "\n\t\tif (%s %% sizeof(wchar_t) != 0)" len_var;
  824. "\t\t{";
  825. "\t\t\tstatus = SGX_ERROR_UNEXPECTED;";
  826. "\t\t\tgoto err;";
  827. "\t\t}";
  828. ]
  829. in
  830. List.fold_left (fun acc s -> acc ^ s ^ "\n") "" wstr_len_check_template
  831. else ""
  832. in
  833. let code_template = [
  834. sprintf "if (%s != NULL && %s != 0) {%s" tmp_ptr_name len_var wstr_len_check;
  835. sprintf "\t%s = (%s)malloc(%s);" in_ptr_name in_ptr_type len_var;
  836. sprintf "\tif (%s == NULL) {" in_ptr_name;
  837. "\t\tstatus = SGX_ERROR_OUT_OF_MEMORY;";
  838. "\t\tgoto err;";
  839. "\t}\n";
  840. sprintf "\tmemcpy(%s, %s, %s);" in_ptr_dst_name tmp_ptr_name len_var;
  841. ]
  842. in
  843. let s1 = List.fold_left (fun acc s -> acc ^ pre_indent ^ s ^ "\n") "" code_template in
  844. let s2 =
  845. if attr.Ast.pa_isstr then
  846. let code_template2 = [
  847. sprintf "\t%s[%s - 1] = '\\0';" in_ptr_name len_var;
  848. sprintf "\tif (%s != strlen(%s) + 1)" len_var in_ptr_name;
  849. "\t{";
  850. "\t\tstatus = SGX_ERROR_UNEXPECTED;";
  851. "\t\tgoto err;";
  852. "\t}";
  853. ]
  854. in
  855. s1 ^ List.fold_left (fun acc s -> acc ^ pre_indent ^ s ^ "\n") "" code_template2
  856. else if attr.Ast.pa_iswstr then
  857. let code_template3 = [
  858. sprintf "\t%s[(%s - sizeof(wchar_t))/sizeof(wchar_t)] = (wchar_t)0;" in_ptr_name len_var;
  859. sprintf "\tif ( %s / sizeof(wchar_t) != wcslen(%s) + 1)" len_var in_ptr_name;
  860. "\t{";
  861. "\t\tstatus = SGX_ERROR_UNEXPECTED;";
  862. "\t\tgoto err;";
  863. "\t}";
  864. ]
  865. in
  866. s1 ^ List.fold_left (fun acc s -> acc ^ pre_indent ^ s ^ "\n") "" code_template3
  867. else s1 in
  868. sprintf "%s\t}\n" s2
  869. | Ast.PtrOut ->
  870. let code_template = [
  871. sprintf "if (%s != NULL && %s != 0) {" tmp_ptr_name len_var;
  872. sprintf "\tif ((%s = (%s)malloc(%s)) == NULL) {" in_ptr_name in_ptr_type len_var;
  873. "\t\tstatus = SGX_ERROR_OUT_OF_MEMORY;";
  874. "\t\tgoto err;";
  875. "\t}\n";
  876. sprintf "\tmemset((void*)%s, 0, %s);" in_ptr_name len_var;
  877. "}"]
  878. in
  879. List.fold_left (fun acc s -> acc ^ pre_indent ^ s ^ "\n") "" code_template
  880. | _ -> ""
  881. in
  882. malloc_and_copy "\t"
  883. in List.fold_left
  884. (fun acc (pty, declr) ->
  885. match pty with
  886. Ast.PTVal _ -> acc
  887. | Ast.PTPtr (ty, attr) -> acc ^ clone_in_ptr ty attr declr) "" plist
  888. (* Generate the code to handle function pointer parameter direction,
  889. * which is to be inserted after finishing calling the trusted function.
  890. *)
  891. let gen_parm_ptr_direction_post (plist: Ast.pdecl list) =
  892. let copy_and_free (attr: Ast.ptr_attr) (declr: Ast.declarator) =
  893. let name = declr.Ast.identifier in
  894. let in_ptr_name = mk_in_var name in
  895. let len_var = mk_len_var name in
  896. let in_ptr_dst_name = mk_in_ptr_dst_name attr.Ast.pa_rdonly in_ptr_name in
  897. match attr.Ast.pa_direction with
  898. Ast.PtrIn -> sprintf "\tif (%s) free(%s);\n" in_ptr_name in_ptr_dst_name
  899. | Ast.PtrInOut | Ast.PtrOut ->
  900. if attr.Ast.pa_isstr then
  901. let code_template = [
  902. sprintf "\tif (%s)" in_ptr_name;
  903. "\t{";
  904. sprintf "\t\t%s[%s - 1] = '\\0';" in_ptr_name len_var;
  905. sprintf "\t\t%s = strlen(%s) + 1;" len_var in_ptr_name;
  906. sprintf "\t\tmemcpy((void*)%s, %s, %s);" (mk_tmp_var name) in_ptr_name len_var;
  907. sprintf "\t\tfree(%s);" in_ptr_name;
  908. "\t}";
  909. ]
  910. in
  911. List.fold_left (fun acc s -> acc ^ s ^ "\n") "" code_template
  912. else if attr.Ast.pa_iswstr then
  913. let code_template = [
  914. sprintf "\tif (%s)" in_ptr_name;
  915. "\t{";
  916. sprintf "\t\t%s[(%s - sizeof(wchar_t))/sizeof(wchar_t)] = (wchar_t)0;" in_ptr_name len_var;
  917. sprintf "\t\t%s = (wcslen(%s) + 1) * sizeof(wchar_t);" len_var in_ptr_name;
  918. sprintf "\t\tmemcpy((void*)%s, %s, %s);" (mk_tmp_var name) in_ptr_name len_var;
  919. sprintf "\t\tfree(%s);" in_ptr_name;
  920. "\t}";
  921. ]
  922. in
  923. List.fold_left (fun acc s -> acc ^ s ^ "\n") "" code_template
  924. else
  925. sprintf "\tif (%s) {\n\t\tmemcpy(%s, %s, %s);\n\t\tfree(%s);\n\t}\n"
  926. in_ptr_name
  927. (mk_tmp_var name)
  928. in_ptr_name
  929. len_var
  930. in_ptr_name
  931. | _ -> ""
  932. in List.fold_left
  933. (fun acc (pty, declr) ->
  934. match pty with
  935. Ast.PTVal _ -> acc
  936. | Ast.PTPtr (ty, attr) -> acc ^ copy_and_free attr declr) "" plist
  937. (* Generate an "err:" goto mark if necessary. *)
  938. let gen_err_mark (plist: Ast.pdecl list) =
  939. let has_inout_p (attr: Ast.ptr_attr): bool =
  940. attr.Ast.pa_direction <> Ast.PtrNoDirection
  941. in
  942. if List.exists (fun (pt, name) ->
  943. match pt with
  944. Ast.PTVal _ -> false
  945. | Ast.PTPtr(_, attr) -> has_inout_p attr) plist
  946. then "err:"
  947. else ""
  948. (* It is used to save the parameters used as the value of size/count attribute. *)
  949. let param_cache = Hashtbl.create 1
  950. let is_in_param_cache s = Hashtbl.mem param_cache s
  951. (* Try to generate a temporary value to save the size of the buffer. *)
  952. let gen_tmp_size (pattr: Ast.ptr_attr) (plist: Ast.pdecl list) =
  953. let do_gen_temp_var (s: string) =
  954. if is_in_param_cache s then ""
  955. else
  956. let param_tystr = find_param_type s plist in
  957. let tmp_var = mk_tmp_var s in
  958. let parm_str = mk_parm_accessor s in
  959. Hashtbl.add param_cache s true;
  960. sprintf "\t%s %s = %s;\n" param_tystr tmp_var parm_str
  961. in
  962. let gen_temp_var (v: Ast.attr_value) =
  963. match v with
  964. Ast.ANumber _ -> ""
  965. | Ast.AString s -> do_gen_temp_var s
  966. in
  967. let tmp_size_str =
  968. match pattr.Ast.pa_size.Ast.ps_size with
  969. Some v -> gen_temp_var v
  970. | None -> ""
  971. in
  972. let tmp_count_str =
  973. match pattr.Ast.pa_size.Ast.ps_count with
  974. Some v -> gen_temp_var v
  975. | None -> ""
  976. in
  977. sprintf "%s%s" tmp_size_str tmp_count_str
  978. let is_ptr (pt: Ast.parameter_type) =
  979. match pt with
  980. Ast.PTVal _ -> false
  981. | Ast.PTPtr _ -> true
  982. let is_ptr_type (aty: Ast.atype) =
  983. match aty with
  984. Ast.Ptr _ -> true
  985. | _ -> false
  986. let ptr_has_direction (pt: Ast.parameter_type) =
  987. match pt with
  988. Ast.PTVal _ -> false
  989. | Ast.PTPtr(_, a) -> a.Ast.pa_direction <> Ast.PtrNoDirection
  990. let tbridge_mk_parm_name_ext (pt: Ast.parameter_type) (declr: Ast.declarator) =
  991. let cast_expr =
  992. let tystr = get_param_tystr pt in
  993. if Ast.is_array declr && List.length declr.Ast.array_dims > 1
  994. then
  995. let dims = get_array_dims (List.tl declr.Ast.array_dims) in
  996. sprintf "(%s (*)%s)" tystr dims
  997. else if is_const_ptr pt then
  998. sprintf "(const %s)" tystr
  999. else ""
  1000. in
  1001. if is_in_param_cache declr.Ast.identifier || (is_ptr pt && (not (is_foreign_array pt)))
  1002. then
  1003. if ptr_has_direction pt
  1004. then cast_expr ^ mk_in_var declr.Ast.identifier
  1005. else cast_expr ^ mk_tmp_var declr.Ast.identifier
  1006. else mk_parm_name_ext pt declr
  1007. let mk_parm_name_tbridge (pt: Ast.parameter_type) (declr: Ast.declarator) =
  1008. add_foreign_array_ptrref tbridge_mk_parm_name_ext pt declr
  1009. (* Generate local variables required for the trusted bridge. *)
  1010. let gen_tbridge_local_vars (plist: Ast.pdecl list) =
  1011. let status_var = "\tsgx_status_t status = SGX_SUCCESS;\n" in
  1012. let do_gen_local_var (ty: Ast.atype) (attr: Ast.ptr_attr) (name: string) =
  1013. let tmp_var =
  1014. (* Save a copy of pointer in case it might be modified in the marshaling structure. *)
  1015. sprintf "\t%s %s = %s;\n" (Ast.get_tystr ty) (mk_tmp_var name) (mk_parm_accessor name)
  1016. in
  1017. let len_var =
  1018. if not attr.Ast.pa_chkptr then ""
  1019. else gen_tmp_size attr plist ^ "\t" ^ gen_ptr_size ty attr name mk_tmp_var in
  1020. let in_ptr =
  1021. match attr.Ast.pa_direction with
  1022. Ast.PtrNoDirection -> ""
  1023. | _ -> sprintf "\t%s %s = NULL;\n" (Ast.get_tystr ty) (mk_in_var name)
  1024. in
  1025. tmp_var ^ len_var ^ in_ptr
  1026. in
  1027. let gen_local_var_for_foreign_array (ty: Ast.atype) (attr: Ast.ptr_attr) (name: string) =
  1028. let tystr = Ast.get_tystr ty in
  1029. let tmp_var =
  1030. sprintf "\t%s* %s = %s;\n" tystr (mk_tmp_var name) (mk_parm_accessor name)
  1031. in
  1032. let len_var = sprintf "\tsize_t %s = sizeof(%s);\n" (mk_len_var name) tystr
  1033. in
  1034. let in_ptr = sprintf "\t%s* %s = NULL;\n" tystr (mk_in_var name)
  1035. in
  1036. match attr.Ast.pa_direction with
  1037. Ast.PtrNoDirection -> ""
  1038. | _ -> tmp_var ^ len_var ^ in_ptr
  1039. in
  1040. let gen_local_var (pd: Ast.pdecl) =
  1041. let (pty, declr) = pd in
  1042. match pty with
  1043. Ast.PTVal _ -> ""
  1044. | Ast.PTPtr (ty, attr) ->
  1045. if is_foreign_array pty
  1046. then gen_local_var_for_foreign_array ty attr declr.Ast.identifier
  1047. else do_gen_local_var ty attr declr.Ast.identifier
  1048. in
  1049. let new_param_list = List.map conv_array_to_ptr plist
  1050. in
  1051. Hashtbl.clear param_cache;
  1052. List.fold_left (fun acc pd -> acc ^ gen_local_var pd) status_var new_param_list
  1053. (* It generates trusted bridge code for a trusted function. *)
  1054. let gen_func_tbridge (fd: Ast.func_decl) (dummy_var: string) =
  1055. let func_open = sprintf "static sgx_status_t SGX_CDECL %s(void* %s)\n{\n"
  1056. (mk_tbridge_name fd.Ast.fname)
  1057. ms_ptr_name in
  1058. let local_vars = gen_tbridge_local_vars fd.Ast.plist in
  1059. let func_close = "\treturn status;\n}\n" in
  1060. let ms_struct_name = mk_ms_struct_name fd.Ast.fname in
  1061. let declare_ms_ptr = sprintf "%s* %s = SGX_CAST(%s*, %s);"
  1062. ms_struct_name
  1063. ms_struct_val
  1064. ms_struct_name
  1065. ms_ptr_name in
  1066. let invoke_func = gen_func_invoking fd mk_parm_name_tbridge in
  1067. let update_retval = sprintf "%s = %s"
  1068. (mk_parm_accessor retval_name)
  1069. invoke_func in
  1070. if is_naked_func fd then
  1071. let check_pms =
  1072. sprintf "if (%s != NULL) return SGX_ERROR_INVALID_PARAMETER;" ms_ptr_name
  1073. in
  1074. sprintf "%s%s%s\t%s\n\t%s\n%s" func_open local_vars dummy_var check_pms invoke_func func_close
  1075. else
  1076. sprintf "%s%s\t%s\n%s\n%s%s\n%s\n\t%s\n%s\n%s\n%s"
  1077. func_open
  1078. (mk_check_pms fd.Ast.fname)
  1079. declare_ms_ptr
  1080. local_vars
  1081. (gen_check_tbridge_length_overflow fd.Ast.plist)
  1082. (gen_check_tbridge_ptr_parms fd.Ast.plist)
  1083. (gen_parm_ptr_direction_pre fd.Ast.plist)
  1084. (if fd.Ast.rtype <> Ast.Void then update_retval else invoke_func)
  1085. (gen_err_mark fd.Ast.plist)
  1086. (gen_parm_ptr_direction_post fd.Ast.plist)
  1087. func_close
  1088. let tproxy_fill_ms_field (pd: Ast.pdecl) =
  1089. let (pt, declr) = pd in
  1090. let name = declr.Ast.identifier in
  1091. let len_var = mk_len_var name in
  1092. let parm_accessor = mk_parm_accessor name in
  1093. match pt with
  1094. Ast.PTVal _ -> fill_ms_field true pd
  1095. | Ast.PTPtr(ty, attr) ->
  1096. let is_ary = (Ast.is_array declr || attr.Ast.pa_isary) in
  1097. let tystr = sprintf "%s%s" (get_param_tystr pt) (if is_ary then "*" else "") in
  1098. if not attr.Ast.pa_chkptr (* [user_check] specified *)
  1099. then sprintf "%s = SGX_CAST(%s, %s);" parm_accessor tystr name
  1100. else
  1101. match attr.Ast.pa_direction with
  1102. Ast.PtrOut ->
  1103. let code_template =
  1104. [sprintf "if (%s != NULL && sgx_is_within_enclave(%s, %s)) {" name name len_var;
  1105. sprintf "\t%s = (%s)__tmp;" parm_accessor tystr;
  1106. sprintf "\t__tmp_%s = __tmp;" name;
  1107. sprintf "\tmemset(__tmp_%s, 0, %s);" name len_var;
  1108. sprintf "\t__tmp = (void *)((size_t)__tmp + %s);" len_var;
  1109. sprintf "} else if (%s == NULL) {" name;
  1110. sprintf "\t%s = NULL;" parm_accessor;
  1111. "} else {";
  1112. "\tsgx_ocfree();";
  1113. "\treturn SGX_ERROR_INVALID_PARAMETER;";
  1114. "}"
  1115. ]
  1116. in List.fold_left (fun acc s -> acc ^ s ^ "\n\t") "" code_template
  1117. | Ast.PtrInOut ->
  1118. let code_template =
  1119. [sprintf "if (%s != NULL && sgx_is_within_enclave(%s, %s)) {" name name len_var;
  1120. sprintf "\t%s = (%s)__tmp;" parm_accessor tystr;
  1121. sprintf "\t__tmp_%s = __tmp;" name;
  1122. sprintf "\tmemcpy(__tmp_%s, %s, %s);" name name len_var;
  1123. sprintf "\t__tmp = (void *)((size_t)__tmp + %s);" len_var;
  1124. sprintf "} else if (%s == NULL) {" name;
  1125. sprintf "\t%s = NULL;" parm_accessor;
  1126. "} else {";
  1127. "\tsgx_ocfree();";
  1128. "\treturn SGX_ERROR_INVALID_PARAMETER;";
  1129. "}"
  1130. ]
  1131. in List.fold_left (fun acc s -> acc ^ s ^ "\n\t") "" code_template
  1132. | _ ->
  1133. let code_template =
  1134. [sprintf "if (%s != NULL && sgx_is_within_enclave(%s, %s)) {" name name len_var;
  1135. sprintf "\t%s = (%s)__tmp;" parm_accessor tystr;
  1136. sprintf "\tmemcpy(__tmp, %s, %s);" name len_var;
  1137. sprintf "\t__tmp = (void *)((size_t)__tmp + %s);" len_var;
  1138. sprintf "} else if (%s == NULL) {" name;
  1139. sprintf "\t%s = NULL;" parm_accessor;
  1140. "} else {";
  1141. "\tsgx_ocfree();";
  1142. "\treturn SGX_ERROR_INVALID_PARAMETER;";
  1143. "}"
  1144. ]
  1145. in List.fold_left (fun acc s -> acc ^ s ^ "\n\t") "" code_template
  1146. (* Generate local variables required for the trusted proxy. *)
  1147. let gen_tproxy_local_vars (plist: Ast.pdecl list) =
  1148. let status_var = "sgx_status_t status = SGX_SUCCESS;\n" in
  1149. let do_gen_local_var (ty: Ast.atype) (attr: Ast.ptr_attr) (name: string) =
  1150. if not attr.Ast.pa_chkptr then ""
  1151. else "\t" ^ gen_ptr_size ty attr name (fun x -> x)
  1152. in
  1153. let gen_local_var (pd: Ast.pdecl) =
  1154. let (pty, declr) = pd in
  1155. match pty with
  1156. Ast.PTVal _ -> ""
  1157. | Ast.PTPtr (ty, attr) -> do_gen_local_var ty attr declr.Ast.identifier
  1158. in
  1159. let new_param_list = List.map conv_array_to_ptr plist
  1160. in
  1161. List.fold_left (fun acc pd -> acc ^ gen_local_var pd) status_var new_param_list
  1162. (* Generate only one ocalloc block required for the trusted proxy. *)
  1163. let gen_ocalloc_block (fname: string) (plist: Ast.pdecl list) =
  1164. let ms_struct_name = mk_ms_struct_name fname in
  1165. let local_vars_block = sprintf "%s* %s = NULL;\n\tsize_t ocalloc_size = sizeof(%s);\n\tvoid *__tmp = NULL;\n\n" ms_struct_name ms_struct_val ms_struct_name in
  1166. let local_var (attr: Ast.ptr_attr) (name: string) =
  1167. if not attr.Ast.pa_chkptr then ""
  1168. else
  1169. match attr.Ast.pa_direction with
  1170. Ast.PtrOut | Ast.PtrInOut -> sprintf "\tvoid *__tmp_%s = NULL;\n" name
  1171. | _ -> ""
  1172. in
  1173. let do_local_var (pd: Ast.pdecl) =
  1174. let (pty, declr) = pd in
  1175. match pty with
  1176. Ast.PTVal _ -> ""
  1177. | Ast.PTPtr (_, attr) -> local_var attr declr.Ast.identifier
  1178. in
  1179. let count_ocalloc_size (ty: Ast.atype) (attr: Ast.ptr_attr) (name: string) =
  1180. if not attr.Ast.pa_chkptr then ""
  1181. else sprintf "\tocalloc_size += (%s != NULL && sgx_is_within_enclave(%s, %s)) ? %s : 0;\n" name name (mk_len_var name) (mk_len_var name)
  1182. in
  1183. let do_count_ocalloc_size (pd: Ast.pdecl) =
  1184. let (pty, declr) = pd in
  1185. match pty with
  1186. Ast.PTVal _ -> ""
  1187. | Ast.PTPtr (ty, attr) -> count_ocalloc_size ty attr declr.Ast.identifier
  1188. in
  1189. let do_gen_ocalloc_block = [
  1190. "\n\t__tmp = sgx_ocalloc(ocalloc_size);\n";
  1191. "\tif (__tmp == NULL) {\n";
  1192. "\t\tsgx_ocfree();\n";
  1193. "\t\treturn SGX_ERROR_UNEXPECTED;\n";
  1194. "\t}\n";
  1195. sprintf "\t%s = (%s*)__tmp;\n" ms_struct_val ms_struct_name;
  1196. sprintf "\t__tmp = (void *)((size_t)__tmp + sizeof(%s));\n" ms_struct_name;
  1197. ]
  1198. in
  1199. let new_param_list = List.map conv_array_to_ptr plist
  1200. in
  1201. let s1 = List.fold_left (fun acc pd -> acc ^ do_local_var pd) local_vars_block new_param_list in
  1202. let s2 = List.fold_left (fun acc pd -> acc ^ do_count_ocalloc_size pd) s1 new_param_list in
  1203. List.fold_left (fun acc s -> acc ^ s) s2 do_gen_ocalloc_block
  1204. (* Generate trusted proxy code for a given untrusted function. *)
  1205. let gen_func_tproxy (ufunc: Ast.untrusted_func) (idx: int) =
  1206. let fd = ufunc.Ast.uf_fdecl in
  1207. let propagate_errno = ufunc.Ast.uf_propagate_errno in
  1208. let func_open = sprintf "%s\n{\n" (gen_tproxy_proto fd) in
  1209. let local_vars = gen_tproxy_local_vars fd.Ast.plist in
  1210. let ocalloc_ms_struct = gen_ocalloc_block fd.Ast.fname fd.Ast.plist in
  1211. let gen_ocfree rtype plist =
  1212. if rtype = Ast.Void && plist = [] then "" else "\tsgx_ocfree();\n"
  1213. in
  1214. let handle_out_ptr plist =
  1215. let copy_memory (attr: Ast.ptr_attr) (declr: Ast.declarator) =
  1216. let name = declr.Ast.identifier in
  1217. match attr.Ast.pa_direction with
  1218. Ast.PtrInOut | Ast.PtrOut ->
  1219. if attr.Ast.pa_isstr then
  1220. let code_template = [
  1221. sprintf "\tif (%s)" name;
  1222. "\t{";
  1223. sprintf "\t\tsize_t __tmp%s;" (mk_len_var name);
  1224. sprintf "\t\tmemcpy((void*)%s, __tmp_%s, %s);" name name (mk_len_var name);
  1225. sprintf "\t\t((char*)%s)[%s - 1] = '\\0';" name (mk_len_var name);
  1226. sprintf "\t\t__tmp%s = strlen(%s) + 1;" (mk_len_var name) name;
  1227. sprintf "\t\tmemset(%s +__tmp%s - 1, 0, %s -__tmp%s);" name (mk_len_var name) (mk_len_var name) (mk_len_var name);
  1228. "\t}";
  1229. ]
  1230. in
  1231. List.fold_left (fun acc s -> acc ^ "\t" ^ s ^ "\n") "" code_template
  1232. else if attr.Ast.pa_iswstr then
  1233. let code_template = [
  1234. sprintf "\tif (%s)" name;
  1235. "\t{";
  1236. sprintf "\t\tsize_t __tmp%s;" (mk_len_var name);
  1237. sprintf "\t\tmemcpy((void*)%s, __tmp_%s, %s);" name name (mk_len_var name);
  1238. sprintf "\t\t((wchar_t*)%s)[(%s - sizeof(wchar_t))/sizeof(wchar_t)] = (wchar_t)0;" name (mk_len_var name);
  1239. sprintf "\t\t__tmp%s = (wcslen(%s) + 1) * sizeof(wchar_t);" (mk_len_var name) name;
  1240. sprintf "\t\tmemset(((uint8_t*)%s) + __tmp%s - sizeof(wchar_t), 0, %s -__tmp%s);" name (mk_len_var name) (mk_len_var name) (mk_len_var name);
  1241. "\t}";
  1242. ]
  1243. in
  1244. List.fold_left (fun acc s -> acc ^ "\t" ^ s ^ "\n") "" code_template
  1245. else
  1246. sprintf "\t\tif (%s) memcpy((void*)%s, __tmp_%s, %s);\n" name name name (mk_len_var name)
  1247. | _ -> ""
  1248. in List.fold_left (fun acc (pty, declr) ->
  1249. match pty with
  1250. Ast.PTVal _ -> acc
  1251. | Ast.PTPtr(ty, attr) -> acc ^ copy_memory attr declr) "" plist in
  1252. let set_errno = if propagate_errno then "\t\terrno = ms->ocall_errno;" else "" in
  1253. let func_close = sprintf "%s%s%s\n%s%s\n"
  1254. (handle_out_ptr fd.Ast.plist)
  1255. set_errno
  1256. "\t}"
  1257. (gen_ocfree fd.Ast.rtype fd.Ast.plist)
  1258. "\treturn status;\n}" in
  1259. let ocall_null = sprintf "status = sgx_ocall(%d, NULL);\n" idx in
  1260. let ocall_with_ms = sprintf "status = sgx_ocall(%d, %s);\n"
  1261. idx ms_struct_val in
  1262. let update_retval = sprintf "\tif (%s) *%s = %s;"
  1263. retval_name retval_name (mk_parm_accessor retval_name) in
  1264. let func_body = ref [] in
  1265. if (is_naked_func fd) && (propagate_errno = false) then
  1266. sprintf "%s\t%s\t%s%s" func_open local_vars ocall_null "\n\treturn status;\n}"
  1267. else
  1268. begin
  1269. func_body := local_vars :: !func_body;
  1270. func_body := ocalloc_ms_struct:: !func_body;
  1271. List.iter (fun pd -> func_body := tproxy_fill_ms_field pd :: !func_body) fd.Ast.plist;
  1272. func_body := ocall_with_ms :: !func_body;
  1273. func_body := "if (status == SGX_SUCCESS) {" :: !func_body;
  1274. if fd.Ast.rtype <> Ast.Void then func_body := update_retval :: !func_body;
  1275. List.fold_left (fun acc s -> acc ^ "\t" ^ s ^ "\n") func_open (List.rev !func_body) ^ func_close
  1276. end
  1277. (* It generates OCALL table and the untrusted proxy to setup OCALL table. *)
  1278. let gen_ocall_table (ec: enclave_content) =
  1279. let func_proto_ubridge = List.map (fun (uf: Ast.untrusted_func) ->
  1280. let fd : Ast.func_decl = uf.Ast.uf_fdecl in
  1281. mk_ubridge_name ec.file_shortnm fd.Ast.fname)
  1282. ec.ufunc_decls in
  1283. let nr_ocall = List.length ec.ufunc_decls in
  1284. let ocall_table_name = mk_ocall_table_name ec.enclave_name in
  1285. let ocall_table =
  1286. let ocall_members =
  1287. List.fold_left
  1288. (fun acc proto -> acc ^ "\t\t(void*)" ^ proto ^ ",\n") "" func_proto_ubridge
  1289. in "\t{\n" ^ ocall_members ^ "\t}\n"
  1290. in
  1291. sprintf "static const struct {\n\
  1292. \tsize_t nr_ocall;\n\
  1293. \tvoid * table[%d];\n\
  1294. } %s = {\n\
  1295. \t%d,\n\
  1296. %s};\n" (max nr_ocall 1)
  1297. ocall_table_name
  1298. nr_ocall
  1299. (if nr_ocall <> 0 then ocall_table else "\t{ NULL },\n")
  1300. (* It generates untrusted code to be saved in a `.c' file. *)
  1301. let gen_untrusted_source (ec: enclave_content) =
  1302. let code_fname = get_usource_name ec.file_shortnm in
  1303. let include_hd = "#include \"" ^ get_uheader_short_name ec.file_shortnm ^ "\"\n" in
  1304. let include_errno = "#include <errno.h>\n" in
  1305. let uproxy_list =
  1306. List.map2 (fun fd ecall_idx -> gen_func_uproxy fd ecall_idx ec)
  1307. (tf_list_to_fd_list ec.tfunc_decls)
  1308. (Util.mk_seq 0 (List.length ec.tfunc_decls - 1))
  1309. in
  1310. let ubridge_list =
  1311. List.map (fun fd -> gen_func_ubridge ec.file_shortnm fd)
  1312. (ec.ufunc_decls) in
  1313. let out_chan = open_out code_fname in
  1314. output_string out_chan (include_hd ^ include_errno ^ "\n");
  1315. ms_writer out_chan ec;
  1316. List.iter (fun s -> output_string out_chan (s ^ "\n")) ubridge_list;
  1317. output_string out_chan (gen_ocall_table ec);
  1318. List.iter (fun s -> output_string out_chan (s ^ "\n")) uproxy_list;
  1319. close_out out_chan
  1320. (* It generates trusted code to be saved in a `.c' file. *)
  1321. let gen_trusted_source (ec: enclave_content) =
  1322. let code_fname = get_tsource_name ec.file_shortnm in
  1323. let include_hd = "#include \"" ^ get_theader_short_name ec.file_shortnm ^ "\"\n\n\
  1324. #include \"sgx_trts.h\" /* for sgx_ocalloc, sgx_is_outside_enclave */\n\
  1325. #include \"sgx_lfence.h\" /* for sgx_lfence */\n\n\
  1326. #include <errno.h>\n\
  1327. #include <string.h> /* for memcpy etc */\n\
  1328. #include <stdlib.h> /* for malloc/free etc */\n\
  1329. \n\
  1330. #define CHECK_REF_POINTER(ptr, siz) do {\t\\\n\
  1331. \tif (!(ptr) || ! sgx_is_outside_enclave((ptr), (siz)))\t\\\n\
  1332. \t\treturn SGX_ERROR_INVALID_PARAMETER;\\\n\
  1333. } while (0)\n\
  1334. \n\
  1335. #define CHECK_UNIQUE_POINTER(ptr, siz) do {\t\\\n\
  1336. \tif ((ptr) && ! sgx_is_outside_enclave((ptr), (siz)))\t\\\n\
  1337. \t\treturn SGX_ERROR_INVALID_PARAMETER;\\\n\
  1338. } while (0)\n\
  1339. \n" in
  1340. let trusted_fds = tf_list_to_fd_list ec.tfunc_decls in
  1341. let tbridge_list =
  1342. let dummy_var = tbridge_gen_dummy_variable ec in
  1343. List.map (fun tfd -> gen_func_tbridge tfd dummy_var) trusted_fds in
  1344. let ecall_table = gen_ecall_table ec.tfunc_decls in
  1345. let entry_table = gen_entry_table ec in
  1346. let tproxy_list = List.map2
  1347. (fun fd idx -> gen_func_tproxy fd idx)
  1348. (ec.ufunc_decls)
  1349. (Util.mk_seq 0 (List.length ec.ufunc_decls - 1)) in
  1350. let out_chan = open_out code_fname in
  1351. output_string out_chan (include_hd ^ "\n");
  1352. ms_writer out_chan ec;
  1353. List.iter (fun s -> output_string out_chan (s ^ "\n")) tbridge_list;
  1354. output_string out_chan (ecall_table ^ "\n");
  1355. output_string out_chan (entry_table ^ "\n");
  1356. output_string out_chan "\n";
  1357. List.iter (fun s -> output_string out_chan (s ^ "\n")) tproxy_list;
  1358. close_out out_chan
  1359. (* We use a stack to keep record of imported files.
  1360. *
  1361. * A file will be pushed to the stack before we parsing it,
  1362. * and we will pop the stack after each `parse_import_file'.
  1363. *)
  1364. let already_read = SimpleStack.create ()
  1365. let save_file fullpath =
  1366. if SimpleStack.mem fullpath already_read
  1367. then failwithf "detected circled import for `%s'" fullpath
  1368. else SimpleStack.push fullpath already_read
  1369. (* The entry point of the Edger8r parser front-end.
  1370. * ------------------------------------------------
  1371. *)
  1372. let start_parsing (fname: string) : Ast.enclave =
  1373. let set_initial_pos lexbuf filename =
  1374. lexbuf.Lexing.lex_curr_p <- {
  1375. lexbuf.Lexing.lex_curr_p with Lexing.pos_fname = fname;
  1376. }
  1377. in
  1378. try
  1379. let fullpath = Util.get_file_path fname in
  1380. let preprocessed =
  1381. save_file fullpath; Preprocessor.processor_macro(fullpath) in
  1382. let lexbuf =
  1383. match preprocessed with
  1384. | None ->
  1385. let chan = open_in fullpath in
  1386. Lexing.from_channel chan
  1387. | Some(preprocessed_string) -> Lexing.from_string preprocessed_string
  1388. in
  1389. try
  1390. set_initial_pos lexbuf fname;
  1391. let e : Ast.enclave = Parser.start_parsing Lexer.tokenize lexbuf in
  1392. let short_name = Util.get_short_name fname in
  1393. if short_name = ""
  1394. then (eprintf "error: %s: file short name is empty\n" fname; exit 1;)
  1395. else
  1396. let res = { e with Ast.ename = short_name } in
  1397. if Util.is_c_identifier short_name then res
  1398. else (eprintf "warning: %s: file short name `%s' is not a valid C identifier\n" fname short_name; res)
  1399. with exn ->
  1400. begin match exn with
  1401. | Parsing.Parse_error ->
  1402. let curr = lexbuf.Lexing.lex_curr_p in
  1403. let line = curr.Lexing.pos_lnum in
  1404. let cnum = curr.Lexing.pos_cnum - curr.Lexing.pos_bol in
  1405. let tok = Lexing.lexeme lexbuf in
  1406. failwithf "%s:%d:%d: unexpected token: %s\n" fname line cnum tok
  1407. | _ -> raise exn
  1408. end
  1409. with Sys_error s -> failwithf "%s\n" s
  1410. (* Check duplicated ECALL/OCALL names.
  1411. *
  1412. * This is a pretty simple implementation - to improve it, the
  1413. * location information of each token should be carried to AST.
  1414. *)
  1415. let check_duplication (ec: enclave_content) =
  1416. let dict = Hashtbl.create 10 in
  1417. let trusted_fds = tf_list_to_fd_list ec.tfunc_decls in
  1418. let untrusted_fds = uf_list_to_fd_list ec.ufunc_decls in
  1419. let check_and_add fname =
  1420. if Hashtbl.mem dict fname then
  1421. failwithf "Multiple definition of function \"%s\" detected." fname
  1422. else
  1423. Hashtbl.add dict fname true
  1424. in
  1425. List.iter (fun (fd: Ast.func_decl) ->
  1426. check_and_add fd.Ast.fname) (trusted_fds @ untrusted_fds)
  1427. (* For each untrusted functions, check that allowed ECALL does exist. *)
  1428. let check_allow_list (ec: enclave_content) =
  1429. let trusted_func_names = get_trusted_func_names ec in
  1430. let do_check_allow_list fname allowed_ecalls =
  1431. List.iter (fun trusted_func ->
  1432. if List.exists (fun x -> x = trusted_func) trusted_func_names
  1433. then ()
  1434. else
  1435. failwithf "\"%s\" declared to allow unknown function \"%s\"."
  1436. fname trusted_func) allowed_ecalls
  1437. in
  1438. List.iter (fun (uf: Ast.untrusted_func) ->
  1439. let fd = uf.Ast.uf_fdecl in
  1440. let allowed_ecalls = uf.Ast.uf_allow_list in
  1441. do_check_allow_list fd.Ast.fname allowed_ecalls) ec.ufunc_decls
  1442. (* Report private ECALL not used in any "allow(...)" expression. *)
  1443. let report_orphaned_priv_ecall (ec: enclave_content) =
  1444. let priv_ecall_names = get_priv_ecall_names ec.tfunc_decls in
  1445. let allowed_names = get_allowed_names ec.ufunc_decls in
  1446. let check_ecall n = if List.mem n allowed_names then ()
  1447. else eprintf "warning: private ECALL `%s' is not used by any OCALL\n" n
  1448. in
  1449. List.iter check_ecall priv_ecall_names
  1450. (* Check that there is at least one public ECALL function. *)
  1451. let check_priv_funcs (ec: enclave_content) =
  1452. let priv_bits = tf_list_to_priv_list ec.tfunc_decls in
  1453. if List.for_all (fun is_priv -> is_priv) priv_bits
  1454. then failwithf "the enclave `%s' contains no public root ECALL.\n" ec.file_shortnm
  1455. else report_orphaned_priv_ecall ec
  1456. (* When generating edge-routines, it need first to check whether there
  1457. * are `import' expressions inside EDL. If so, it will parse the given
  1458. * importing file to get an `enclave_content' record, recursively.
  1459. *
  1460. * `ec' is the toplevel `enclave_content' record.
  1461. * Here, a tree reduce algorithm is used. `ec' is the root-node, each
  1462. * `import' expression is considered as a children.
  1463. *)
  1464. let reduce_import (ec: enclave_content) =
  1465. (* Append a EDL list to another. Keep the first element and replace the
  1466. second one with empty element contains functions not in the first one
  1467. if both lists contain a same EDL. The function sequence is backwards compatible.*)
  1468. let join (ec1: enclave_content list) (ec2: enclave_content list) =
  1469. let join_one (acc: enclave_content list) (ec: enclave_content) =
  1470. if List.exists (fun (x: enclave_content) -> x.enclave_name = ec.enclave_name) acc
  1471. then
  1472. let match_ec = List.find (fun (x: enclave_content) -> x.enclave_name = ec.enclave_name) acc in
  1473. let filter_one func_decls decl= List.filter(fun x -> not (x = decl)) func_decls in
  1474. let filtered_ec =
  1475. {empty_ec with
  1476. tfunc_decls = List.fold_left(filter_one) ec.tfunc_decls match_ec.tfunc_decls;
  1477. ufunc_decls = List.fold_left(filter_one) ec.ufunc_decls match_ec.ufunc_decls; }
  1478. in
  1479. acc @ filtered_ec::[]
  1480. else
  1481. acc @ ec ::[]
  1482. in
  1483. List.fold_left(join_one) ec1 ec2
  1484. in
  1485. let parse_import_file fname =
  1486. parse_enclave_ast (start_parsing fname)
  1487. in
  1488. let check_funs funcs (ec: enclave_content list) =
  1489. (* Check whether `funcs' are listed in head of `ec'. It returns a
  1490. production (x, y), where:
  1491. x - functions not listed in head `ec';
  1492. y - a new `ec' that its head contains functions from `funcs' listed in `ec'.
  1493. *)
  1494. let enclave_funcs =
  1495. let trusted_func_names = get_trusted_func_names (List.hd ec) in
  1496. let untrusted_func_names = get_untrusted_func_names (List.hd ec) in
  1497. trusted_func_names @ untrusted_func_names
  1498. in
  1499. let in_ec_def name = List.exists (fun x -> x = name) enclave_funcs in
  1500. let in_import_list name = List.exists (fun x -> x = name) funcs in
  1501. let x = List.filter (fun name -> not (in_ec_def name)) funcs in
  1502. let y =
  1503. { (List.hd ec) with
  1504. tfunc_decls = List.filter (fun tf ->
  1505. in_import_list (get_tf_fname tf)) (List.hd ec).tfunc_decls;
  1506. ufunc_decls = List.filter (fun uf ->
  1507. in_import_list (get_uf_fname uf)) (List.hd ec).ufunc_decls; }
  1508. in (x, y::(List.tl ec))
  1509. in
  1510. (* Import functions listed in `funcs' from `importee'. *)
  1511. let rec import_funcs (funcs: string list) (importee: enclave_content list) =
  1512. (* A `*' means importing all the functions. *)
  1513. if List.exists (fun x -> x = "*") funcs
  1514. then
  1515. let finished_ec = List.fold_left (fun acc (ipd: Ast.import_decl) ->
  1516. let next_ec = parse_import_file ipd.Ast.mname
  1517. in join acc (import_funcs ipd.Ast.flist (next_ec::[]))) importee (List.hd importee).import_exprs
  1518. in
  1519. (SimpleStack.pop already_read |> ignore; finished_ec)
  1520. else
  1521. let (x, y) = check_funs funcs importee
  1522. in
  1523. match (List.hd importee).import_exprs with
  1524. [] ->
  1525. if x = []
  1526. then (SimpleStack.pop already_read |> ignore;y) (* Resolved all importings *)
  1527. else failwithf "import failed - functions `%s' not found" (List.hd x)
  1528. | ex ->
  1529. (* Continue importing even if all function importings resolved to avoid circled import.*)
  1530. let finished_ec = List.fold_left (fun acc (ipd: Ast.import_decl) ->
  1531. let next_ec = parse_import_file ipd.Ast.mname
  1532. in join acc (import_funcs x (next_ec::[]))) y ex
  1533. in
  1534. (SimpleStack.pop already_read |> ignore; finished_ec)
  1535. in
  1536. let imported_ec_list = import_funcs ["*"] (ec::[])
  1537. in
  1538. (* combine two EDLs by appending items except import. *)
  1539. let combine (acc: enclave_content) (ec2: enclave_content) =
  1540. { acc with
  1541. include_list = acc.include_list @ ec2.include_list;
  1542. import_exprs = [];
  1543. comp_defs = acc.comp_defs @ ec2.comp_defs;
  1544. tfunc_decls = acc.tfunc_decls @ ec2.tfunc_decls;
  1545. ufunc_decls = acc.ufunc_decls @ ec2.ufunc_decls; }
  1546. in
  1547. List.fold_left (combine) (List.hd imported_ec_list) (List.tl imported_ec_list)
  1548. (* Generate the Enclave code. *)
  1549. let gen_enclave_code (e: Ast.enclave) (ep: edger8r_params) =
  1550. let ec = reduce_import (parse_enclave_ast e) in
  1551. g_use_prefix := ep.use_prefix;
  1552. g_untrusted_dir := ep.untrusted_dir;
  1553. g_trusted_dir := ep.trusted_dir;
  1554. create_dir ep.untrusted_dir;
  1555. create_dir ep.trusted_dir;
  1556. check_duplication ec;
  1557. check_allow_list ec;
  1558. (if not ep.header_only then check_priv_funcs ec);
  1559. (if ep.gen_untrusted then (gen_untrusted_header ec; if not ep.header_only then gen_untrusted_source ec));
  1560. (if ep.gen_trusted then (gen_trusted_header ec; if not ep.header_only then gen_trusted_source ec))