elfcomm.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. /*++
  2. Copyright (c) 2016 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. elfcomm.c
  9. Abstract:
  10. This module implements ELF support functions that are agnostic to the
  11. address size (the same in 32-bit or 64-bit).
  12. Author:
  13. Evan Green 8-Apr-2016
  14. Environment:
  15. Any
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. //
  21. // Note that elfn.h is not included here because all functions in this file
  22. // should be agnostic to 32 vs 64 bit. Needing to include that headers means
  23. // the function belongs in a different file.
  24. //
  25. #include "imp.h"
  26. #include "elf.h"
  27. //
  28. // ---------------------------------------------------------------- Definitions
  29. //
  30. //
  31. // ------------------------------------------------------ Data Type Definitions
  32. //
  33. typedef enum _ELF_LIBRARY_PATH_VARIABLE {
  34. ElfLibraryPathOrigin,
  35. ElfLibraryPathLib,
  36. ElfLibraryPathPlatform
  37. } ELF_LIBRARY_PATH_VARIABLE, *PELF_LIBRARY_PATH_VARIABLE;
  38. /*++
  39. Structure Description:
  40. This structure stores an entry in the table of variables that can be
  41. substituted in ELF library paths.
  42. Members:
  43. Variable - Stores the variable code.
  44. Name - Stores the variable name.
  45. --*/
  46. typedef struct _ELF_LIBRARY_PATH_VARIABLE_ENTRY {
  47. ELF_LIBRARY_PATH_VARIABLE Variable;
  48. PSTR Name;
  49. } ELF_LIBRARY_PATH_VARIABLE_ENTRY, *PELF_LIBRARY_PATH_VARIABLE_ENTRY;
  50. //
  51. // ----------------------------------------------- Internal Function Prototypes
  52. //
  53. KSTATUS
  54. ImpElfPerformLibraryPathSubstitutions (
  55. PLOADED_IMAGE Image,
  56. PSTR *Path,
  57. PUINTN PathCapacity
  58. );
  59. //
  60. // -------------------------------------------------------------------- Globals
  61. //
  62. ELF_LIBRARY_PATH_VARIABLE_ENTRY ElfLibraryPathVariables[] = {
  63. {ElfLibraryPathOrigin, "ORIGIN"},
  64. {ElfLibraryPathLib, "LIB"},
  65. {ElfLibraryPathPlatform, "PLATFORM"}
  66. };
  67. //
  68. // ------------------------------------------------------------------ Functions
  69. //
  70. KSTATUS
  71. ImpElfOpenWithPathList (
  72. PLOADED_IMAGE PathImage,
  73. PCSTR LibraryName,
  74. PSTR PathList,
  75. PIMAGE_FILE_INFORMATION File,
  76. PSTR *Path
  77. )
  78. /*++
  79. Routine Description:
  80. This routine attempts to load a needed library for an ELF image.
  81. Arguments:
  82. PathImage - Supplies a pointer to the image that owns the path list. This
  83. will be the image that needs the library or an ancestor of the image
  84. that needs the library.
  85. LibraryName - Supplies the name of the library to load.
  86. PathList - Supplies a colon-separated list of paths to try.
  87. File - Supplies a pointer where the information for the file including its
  88. open handle will be returned.
  89. Path - Supplies a pointer where the real path to the opened file will be
  90. returned. The caller is responsible for freeing this memory.
  91. Return Value:
  92. Status code.
  93. --*/
  94. {
  95. PSTR CompletePath;
  96. UINTN CompletePathCapacity;
  97. UINTN CompletePathSize;
  98. PSTR CurrentPath;
  99. UINTN LibraryLength;
  100. PSTR NextSeparator;
  101. UINTN PrefixLength;
  102. KSTATUS Status;
  103. LibraryLength = RtlStringLength(LibraryName);
  104. CompletePath = NULL;
  105. CompletePathCapacity = 0;
  106. CurrentPath = PathList;
  107. while (TRUE) {
  108. NextSeparator = RtlStringFindCharacter(CurrentPath, ':', -1);
  109. if (NextSeparator == NULL) {
  110. PrefixLength = RtlStringLength(CurrentPath);
  111. } else {
  112. PrefixLength = (UINTN)NextSeparator - (UINTN)CurrentPath;
  113. }
  114. //
  115. // The complete path is "prefix/library". Reallocate the buffer if
  116. // needed.
  117. //
  118. CompletePathSize = PrefixLength + LibraryLength + 2;
  119. if (CompletePathSize > CompletePathCapacity) {
  120. if (CompletePath != NULL) {
  121. ImFreeMemory(CompletePath);
  122. }
  123. CompletePath = ImAllocateMemory(CompletePathSize,
  124. IM_ALLOCATION_TAG);
  125. if (CompletePath == NULL) {
  126. Status = STATUS_INSUFFICIENT_RESOURCES;
  127. break;
  128. }
  129. CompletePathCapacity = CompletePathSize;
  130. }
  131. if (PrefixLength != 0) {
  132. RtlCopyMemory(CompletePath, CurrentPath, PrefixLength);
  133. if (CompletePath[PrefixLength - 1] != '/') {
  134. CompletePath[PrefixLength] = '/';
  135. PrefixLength += 1;
  136. }
  137. }
  138. RtlCopyMemory(CompletePath + PrefixLength,
  139. LibraryName,
  140. LibraryLength);
  141. CompletePath[PrefixLength + LibraryLength] = '\0';
  142. Status = ImpElfPerformLibraryPathSubstitutions(PathImage,
  143. &CompletePath,
  144. &CompletePathCapacity);
  145. if (!KSUCCESS(Status)) {
  146. break;
  147. }
  148. Status = ImOpenFile(PathImage->SystemContext, CompletePath, File);
  149. if (KSUCCESS(Status)) {
  150. break;
  151. }
  152. if (NextSeparator == NULL) {
  153. break;
  154. }
  155. CurrentPath = NextSeparator + 1;
  156. }
  157. //
  158. // If the file could be opened, get its real path.
  159. //
  160. if (KSUCCESS(Status)) {
  161. if (Path != NULL) {
  162. *Path = CompletePath;
  163. CompletePath = NULL;
  164. }
  165. }
  166. if (CompletePath != NULL) {
  167. ImFreeMemory(CompletePath);
  168. }
  169. return Status;
  170. }
  171. ULONG
  172. ImpElfOriginalHash (
  173. PCSTR SymbolName
  174. )
  175. /*++
  176. Routine Description:
  177. This routine hashes a symbol name to get the index into the ELF hash table.
  178. Arguments:
  179. SymbolName - Supplies a pointer to the name to hash.
  180. Return Value:
  181. Returns the hash of the name.
  182. --*/
  183. {
  184. ULONG Hash;
  185. ULONG Temporary;
  186. Hash = 0;
  187. while (*SymbolName != '\0') {
  188. Hash = (Hash << 4) + *SymbolName;
  189. Temporary = Hash & 0xF0000000;
  190. if (Temporary != 0) {
  191. Hash ^= Temporary >> 24;
  192. }
  193. Hash &= ~Temporary;
  194. SymbolName += 1;
  195. }
  196. return Hash;
  197. }
  198. ULONG
  199. ImpElfGnuHash (
  200. PCSTR SymbolName
  201. )
  202. /*++
  203. Routine Description:
  204. This routine hashes a symbol name to get the index into the ELF hash table
  205. using the GNU style hash function.
  206. Arguments:
  207. SymbolName - Supplies a pointer to the name to hash.
  208. Return Value:
  209. Returns the hash of the name.
  210. --*/
  211. {
  212. ULONG Hash;
  213. Hash = 5381;
  214. while (*SymbolName != '\0') {
  215. //
  216. // It's really hash * 33 + Character, but multiply by 33 is expanded
  217. // into multiply by 32 plus one.
  218. //
  219. Hash = ((Hash << 5) + Hash) + (UCHAR)*SymbolName;
  220. SymbolName += 1;
  221. }
  222. return Hash;
  223. }
  224. PSTR
  225. ImpElfGetEnvironmentVariable (
  226. PSTR Variable
  227. )
  228. /*++
  229. Routine Description:
  230. This routine gets an environment variable value for the image library.
  231. Arguments:
  232. Variable - Supplies a pointer to a null terminated string containing the
  233. name of the variable to get.
  234. Return Value:
  235. Returns a pointer to the value of the environment variable. The image
  236. library will not free or modify this value.
  237. NULL if the given environment variable is not set.
  238. --*/
  239. {
  240. if (ImGetEnvironmentVariable != NULL) {
  241. return ImGetEnvironmentVariable(Variable);
  242. }
  243. return NULL;
  244. }
  245. //
  246. // --------------------------------------------------------- Internal Functions
  247. //
  248. KSTATUS
  249. ImpElfPerformLibraryPathSubstitutions (
  250. PLOADED_IMAGE PathImage,
  251. PSTR *Path,
  252. PUINTN PathCapacity
  253. )
  254. /*++
  255. Routine Description:
  256. This routine performs any variable substitutions in a library path.
  257. Arguments:
  258. PathImage - Supplies a pointer to the image that owns the library path (not
  259. the library itself obviously, that hasn't been loaded yet).
  260. Path - Supplies a pointer that on input contains the complete path. On
  261. output this will contain the complete path with variables expanded.
  262. PathCapacity - Supplies a pointer that on input contains the size of the
  263. path allocation. This will be updated on output if the string is
  264. reallocated.
  265. Return Value:
  266. STATUS_SUCCESS on success.
  267. STATUS_INSUFFICIENT_RESOURCES if memory could not be allocated.
  268. --*/
  269. {
  270. PSTR CurrentCharacter;
  271. PSTR CurrentPath;
  272. UINTN Delta;
  273. PELF_LIBRARY_PATH_VARIABLE_ENTRY Entry;
  274. UINTN EntryCount;
  275. UINTN EntryIndex;
  276. UINTN Index;
  277. PSTR Name;
  278. UINTN NameLength;
  279. PSTR NewBuffer;
  280. UINTN RemainderOffset;
  281. PSTR Replacement;
  282. UINTN ReplacementLength;
  283. PSTR Separator;
  284. KSTATUS Status;
  285. UINTN VariableLength;
  286. UINTN VariableOffset;
  287. PSTR VariableStart;
  288. EntryCount = sizeof(ElfLibraryPathVariables) /
  289. sizeof(ElfLibraryPathVariables[0]);
  290. CurrentCharacter = RtlStringFindCharacter(*Path, '$', -1);
  291. while (CurrentCharacter != NULL) {
  292. //
  293. // Find the name of the variable and the size of the region to replace.
  294. //
  295. VariableStart = CurrentCharacter;
  296. CurrentCharacter += 1;
  297. if (*CurrentCharacter == '{') {
  298. CurrentCharacter += 1;
  299. Name = CurrentCharacter;
  300. while ((*CurrentCharacter != '\0') && (*CurrentCharacter != '}')) {
  301. CurrentCharacter += 1;
  302. }
  303. if (*CurrentCharacter != '}') {
  304. RtlDebugPrint("ELF: Missing closing brace on %s.\n", *Path);
  305. Status = STATUS_INVALID_SEQUENCE;
  306. goto ElfPerformLibraryPathSubstitutionsEnd;
  307. }
  308. NameLength = (UINTN)CurrentCharacter - (UINTN)Name;
  309. CurrentCharacter += 1;
  310. } else {
  311. Name = CurrentCharacter;
  312. while (RtlIsCharacterAlphabetic(*CurrentCharacter) != FALSE) {
  313. CurrentCharacter += 1;
  314. }
  315. NameLength = (UINTN)CurrentCharacter - (UINTN)Name;
  316. }
  317. VariableLength = (UINTN)CurrentCharacter - (UINTN)VariableStart;
  318. VariableOffset = (UINTN)VariableStart - (UINTN)(*Path);
  319. //
  320. // Decode the variable.
  321. //
  322. for (EntryIndex = 0; EntryIndex < EntryCount; EntryIndex += 1) {
  323. Entry = &(ElfLibraryPathVariables[EntryIndex]);
  324. if ((RtlAreStringsEqual(Name, Entry->Name, NameLength) != FALSE) &&
  325. (Entry->Name[NameLength] == '\0')) {
  326. break;
  327. }
  328. }
  329. if (EntryIndex == EntryCount) {
  330. RtlDebugPrint("ELF: Warning: Unknown variable starting at %s.\n",
  331. Name);
  332. } else {
  333. ReplacementLength = 0;
  334. switch (Entry->Variable) {
  335. case ElfLibraryPathOrigin:
  336. Separator = RtlStringFindCharacterRight(PathImage->FileName,
  337. '/',
  338. -1);
  339. if (Separator != NULL) {
  340. Replacement = PathImage->FileName;
  341. ReplacementLength = (UINTN)Separator - (UINTN)Replacement;
  342. } else {
  343. Replacement = ".";
  344. }
  345. break;
  346. case ElfLibraryPathLib:
  347. if (PathImage->Format == ImageElf64) {
  348. Replacement = "lib64";
  349. } else {
  350. Replacement = "lib";
  351. }
  352. break;
  353. case ElfLibraryPathPlatform:
  354. switch (PathImage->Machine) {
  355. case ImageMachineTypeX86:
  356. Replacement = "i686";
  357. break;
  358. case ImageMachineTypeX64:
  359. Replacement = "x86_64";
  360. break;
  361. case ImageMachineTypeArm32:
  362. Replacement = "armv7";
  363. break;
  364. case ImageMachineTypeArm64:
  365. Replacement = "armv8";
  366. break;
  367. default:
  368. ASSERT(FALSE);
  369. Replacement = ".";
  370. break;
  371. }
  372. break;
  373. default:
  374. ASSERT(FALSE);
  375. Replacement = ".";
  376. break;
  377. }
  378. if (ReplacementLength == 0) {
  379. ReplacementLength = RtlStringLength(Replacement);
  380. }
  381. //
  382. // If the replacement is shorter than the original variable, then
  383. // just copy the replacement over and shift the rest to the left.
  384. //
  385. if (ReplacementLength <= VariableLength) {
  386. RtlCopyMemory(VariableStart,
  387. Replacement,
  388. ReplacementLength);
  389. Delta = VariableLength - ReplacementLength;
  390. if (Delta != 0) {
  391. CurrentPath = *Path;
  392. for (Index = VariableOffset + ReplacementLength;
  393. Index < *PathCapacity - Delta;
  394. Index += 1) {
  395. CurrentPath[Index] = CurrentPath[Index + Delta];
  396. }
  397. CurrentCharacter -= Delta;
  398. }
  399. //
  400. // The replacement is bigger than the variable it's replacing.
  401. //
  402. } else {
  403. Delta = ReplacementLength - VariableLength;
  404. NewBuffer = ImAllocateMemory(*PathCapacity + Delta,
  405. IM_ALLOCATION_TAG);
  406. if (NewBuffer == NULL) {
  407. Status = STATUS_INSUFFICIENT_RESOURCES;
  408. goto ElfPerformLibraryPathSubstitutionsEnd;
  409. }
  410. RtlCopyMemory(NewBuffer, *Path, VariableOffset);
  411. RtlCopyMemory(NewBuffer + VariableOffset,
  412. Replacement,
  413. ReplacementLength);
  414. RemainderOffset = VariableOffset + VariableLength;
  415. RtlCopyMemory(NewBuffer + VariableOffset + ReplacementLength,
  416. *Path + RemainderOffset,
  417. *PathCapacity - (RemainderOffset));
  418. CurrentCharacter = (PSTR)((UINTN)NewBuffer +
  419. VariableOffset +
  420. ReplacementLength);
  421. ImFreeMemory(*Path);
  422. *Path = NewBuffer;
  423. *PathCapacity += Delta;
  424. }
  425. }
  426. //
  427. // Find the next variable.
  428. //
  429. CurrentCharacter = RtlStringFindCharacter(CurrentCharacter, '$', -1);
  430. }
  431. Status = STATUS_SUCCESS;
  432. ElfPerformLibraryPathSubstitutionsEnd:
  433. return Status;
  434. }