1 krisbash 1.1 /*
2 * Copyright (C) 2012 Microsoft Corporation
3 * All rights reserved.
4 */
5 #ifndef HOOK_BUILD
6 #define HOOK_BUILD
7 #endif
8
9 #ifdef _MSC_VER
10 #include <windows.h>
11 #endif
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <nits/base/nits.h>
15 #include <pal/sem.h>
16 #include <pal/atomic.h>
17 #include <pal/strings.h>
18 #include <pal/process.h>
19 #include <pal/thread.h>
20 #include <pal/shlib.h>
21 #include <pal/file.h>
22 krisbash 1.1
23 #if defined(_MSC_VER) || defined(ENABLE_UNITTESTING)
24
25 void SignalInjector()
26 {
27 PAL_Char nameSignal[128] = PAL_T(CONFIG_SEMNAMELOCALPREFIX) PAL_T("NitsInjectorIn_");
28 PAL_Char nameWait[128] = PAL_T(CONFIG_SEMNAMELOCALPREFIX) PAL_T("NitsInjectorOut_");
29 PAL_Char nameLock[128] = PAL_T(CONFIG_SEMNAMELOCALPREFIX) PAL_T("NitsInjectorLock_");
30 NamedSem semaphore;
31 NamedSem lockSemaphore;
32 PAL_Char conversionBuf[64] = PAL_T("");
33 const PAL_Char *convertedStr = NULL;
34 size_t convertedSize = 0;
35 // int waitSemValue = 0;
36 int waitMilliSeconds = 100;
37 int waitForLockMilliSeconds = 500;
38 #ifndef _MSC_VER
39 waitForLockMilliSeconds = 1000;
40 #endif
41
42 TcsFromUInt64(conversionBuf, Process_ID(), &convertedStr, &convertedSize);
43 krisbash 1.1 Tcscat(nameSignal, 128, convertedStr);
44 Tcscat(nameWait, 128, convertedStr);
45 Tcscat(nameLock, 128, convertedStr);
46
47 if(NamedSem_Open_Injected(&lockSemaphore, SEM_USER_ACCESS_ALLOW_ALL, 0, nameLock, 0, NitsReservedCallSite()) != 0)
48 {
49 /* The injector isn't there. */
50 return;
51 }
52
53 if(NamedSem_TimedWait(&lockSemaphore, waitForLockMilliSeconds) != 0)
54 {
55 // could not acquire lock to the injector; some further shouldFault call will attempt to
56 NamedSem_Close(&lockSemaphore);
57 return;
58 }
59
60 if(NamedSem_Open_Injected(&semaphore, SEM_USER_ACCESS_ALLOW_ALL, 0, nameSignal, 0, NitsReservedCallSite()) != 0)
61 {
62 /* The injector isn't there. */
63 goto End;
64 krisbash 1.1 }
65
66 NamedSem_Post(&semaphore, 1);
67 NamedSem_Close(&semaphore);
68
69 if(NamedSem_Open_Injected(&semaphore, SEM_USER_ACCESS_ALLOW_ALL, 0, nameWait, 0, NitsReservedCallSite()) != 0)
70 {
71 /* The injector isn't there. */
72 goto End;
73 }
74
75 /* Use a short timeout to prevent undesired behavior. In the worst
76 * case, the injector thread will be starved and the patching will
77 * happen later. */
78
79 #ifndef _MSC_VER
80 // for non-windows the wait required is greater; this looks like a problem with the timedwait of namedsem;
81 waitMilliSeconds = 1000;
82 #endif
83 NamedSem_TimedWait(&semaphore, waitMilliSeconds);
84 NamedSem_Close(&semaphore);
85 krisbash 1.1
86 End:
87 NamedSem_Post(&lockSemaphore, 1);
88 NamedSem_Close(&lockSemaphore);
89 return;
90 }
91
92 Shlib* nitsinj_handle = NULL;
93 int (NITS_CALL *NitsStartInjectorFunc)(void);
94 void (NITS_CALL *NitsStopInjectorFunc)(void);
95
96 static void ATEXIT_API unloadInjector(void)
97 {
98 if(nitsinj_handle)
99 {
100 NitsStopInjectorFunc();
101 Shlib_Close(nitsinj_handle);
102 }
103 }
104
105 void LoadInjector(_In_z_ const PAL_Char *injectorLibName)
106 krisbash 1.1 {
107 int result = 0;
108 void* func = NULL;
109
110 if (nitsinj_handle)
111 {
112 goto End;
113 }
114
115 nitsinj_handle = Shlib_Open_Injected(injectorLibName, NitsReservedCallSite());
116 if (!nitsinj_handle)
117 {
118 goto End;
119 }
120
121 func = Shlib_Sym(nitsinj_handle, "NitsStartInjector");
122 if (func == NULL)
123 goto Unload;
124
125 NitsStartInjectorFunc = (int (NITS_CALL *)(void))func;
126
127 krisbash 1.1 func = Shlib_Sym(nitsinj_handle, "NitsStopInjector");
128 if (func == NULL)
129 goto Unload;
130
131 NitsStopInjectorFunc = (void (NITS_CALL *)(void))func;
132
133 result = NitsStartInjectorFunc();
134 if (result != 0)
135 goto Unload;
136
137 PAL_Atexit(unloadInjector);
138 End:
139 return;
140 Unload:
141 Shlib_Close(nitsinj_handle);
142 nitsinj_handle = NULL;
143 return;
144 }
145
146 // Nits Installation reads the nitsinj.dll name from registry key on windows
147 // On linux, we use the file based mechanism where we require that NitsInstalled file is present
148 krisbash 1.1 // at specific location. The windows way of doing this was required so that we are fine with layermap tool
149 void LoadInjectorIfRequired()
150 {
151 #ifdef _MSC_VER
152 #define InjectorStrLength (sizeof(L"nitsinj.dll")/sizeof(wchar_t))
153
154 HKEY key;
155 wchar_t value[InjectorStrLength];
156 DWORD valueSize = sizeof(value);
157 DWORD valueType = 0;
158 DWORD queryError = 0;
159
160 RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WSMAN", 0, KEY_QUERY_VALUE, &key);
161
162 queryError = RegQueryValueEx(key, L"NitsInjector", NULL, &valueType, (BYTE *)&value, &valueSize);
163
164 if((queryError == 0) && (InjectorStrLength*sizeof(wchar_t) == valueSize))
165 {
166 PAL_Char injectorLibName[InjectorStrLength];
167 value[InjectorStrLength - 1] = L'\0';
168 #ifdef CONFIG_ENABLE_WCHAR
169 krisbash 1.1 Wcslcpy(injectorLibName, value, InjectorStrLength);
170 #else
171 StrWcslcpy(injectorLibName, value, InjectorStrLength)
172 #endif
173 LoadInjector(injectorLibName);
174 }
175
176 RegCloseKey(key);
177 #else
178 FILE* fp = File_Open(CONFIG_TMPDIR "/NitsInstalled", "rb");
179 if(fp)
180 {
181 PAL_Char injectorLibName[NAME_MAX];
182 TcsStrlcpy(injectorLibName, CONFIG_LIBDIR "/libnitsinj.so", NAME_MAX);
183
184 LoadInjector(injectorLibName);
185 File_Close(fp);
186 }
187 #endif
188 }
189
190 krisbash 1.1 #endif
191
192 void CheckInjector()
193 {
194 /* The injector might not know we are here.
195 * Open up the injector refresh semaphore for this process.
196 * Then signal it once and wait for the NitsFT to be patched. */
197 if (Atomic_CompareAndSwap(&NITS_PRESENCE_STUB, NitsPresenceUnknown, NitsStubbedOut) == NitsPresenceUnknown)
198 {
199 #if defined(_MSC_VER) || defined(ENABLE_UNITTESTING)
200 // on linux; if we are not building to run unittests,
201 // in that case this will be a no-op and all further calls will bail out since
202 // NITS_PRESENCE_STUB will be NitsStubbedOut after we get here.
203 LoadInjectorIfRequired();
204 SignalInjector();
205 #endif
206 /* Re-enter through the function table. This should be patched! */
207 }
208 else
209 {
210 //printf("\nsignalSent was already 1\n");
211 krisbash 1.1 }
212
213 /* The function table should be unchanged. The caller will attempt to
214 * replace itself with the simple stub, since the check is complete. */
215 }
216
217 static NitsResult NITS_CALL ShouldFault_Checked(
218 NitsCallSite line,
219 NitsFaultMode mode)
220 {
221 NitsCallSite reservedCallsite = NitsReservedCallSite();
222 if(line.id == reservedCallsite.id)
223 {
224 return NitsFalse;
225 }
226
227 CheckInjector();
228
229 return NitsShouldFault(line, mode);
230 }
231
232 krisbash 1.1 static void NITS_CALL BeginResource_Checked(
233 _In_ void *resource,
234 int type,
235 NitsResourceScope scope,
236 NitsCallSite line)
237 {
238 CheckInjector();
239 NitsBeginResource(resource, type, scope, line);
240 }
241
242 static void NITS_CALL ChangeResource(
243 _In_ void *resource,
244 int type,
245 NitsResourceScope scope,
246 NitsCallSite line)
247 {
248 PAL_UNUSED(resource);
249 PAL_UNUSED(type);
250 PAL_UNUSED(scope);
251 PAL_UNUSED(line);
252 }
253 krisbash 1.1
254 static void NITS_CALL EndResource(
255 _In_ void *resource,
256 int type,
257 NitsCallSite line)
258 {
259 PAL_UNUSED(resource);
260 PAL_UNUSED(type);
261 PAL_UNUSED(line);
262 }
263
264 static void NITS_CALL TraceA(
265 _In_z_ const char *text,
266 NitsCallSite line,
267 NitsFaultMode mode)
268 {
269 PAL_UNUSED(text);
270 PAL_UNUSED(line);
271 PAL_UNUSED(mode);
272 }
273
274 krisbash 1.1 static void NITS_CALL TraceW(
275 _In_z_ const wchar_t *text,
276 NitsCallSite line,
277 NitsFaultMode mode)
278 {
279 PAL_UNUSED(text);
280 PAL_UNUSED(line);
281 PAL_UNUSED(mode);
282 }
283
284 static NitsResult NITS_CALL AssertA_Checked(
285 int test,
286 _In_z_ const char *text,
287 _In_z_ const char *description,
288 NitsCallSite line,
289 NitsFaultMode mode)
290 {
291 CheckInjector();
292 return (ShouldCallNITSTable ? NITS.AssertA(test, text, description, line, mode) : NitsTrue);
293 }
294
295 krisbash 1.1 static NitsResult NITS_CALL AssertW_Checked(
296 int test,
297 _In_z_ const char *text,
298 _In_z_ const wchar_t *description,
299 NitsCallSite line,
300 NitsFaultMode mode)
301 {
302 CheckInjector();
303
304 return (ShouldCallNITSTable ? NITS.AssertW(test, text, description, line, mode) : NitsTrue);
305 }
306
307 static NitsResult NITS_CALL CompareA_Checked(
308 int lhs,
309 int rhs,
310 _In_z_ const char *lhsText,
311 _In_z_ const char *rhsText,
312 _In_z_ const char *description,
313 NitsCallSite line,
314 NitsFaultMode mode)
315 {
316 krisbash 1.1 CheckInjector();
317 return (ShouldCallNITSTable ? NITS.CompareA(lhs, rhs, lhsText, rhsText, description, line, mode) : NitsTrue);
318 }
319
320
321 static NitsResult NITS_CALL CompareW_Checked(
322 int lhs,
323 int rhs,
324 _In_z_ const char *lhsText,
325 _In_z_ const char *rhsText,
326 _In_z_ const wchar_t *description,
327 NitsCallSite line,
328 NitsFaultMode mode)
329 {
330 CheckInjector();
331 return (ShouldCallNITSTable ? NITS.CompareW(lhs, rhs, lhsText, rhsText, description, line, mode) : NitsTrue);
332 }
333
334
335 static NitsResult NITS_CALL CompareStringA_Checked(
336 _In_z_ const char *lhs,
337 krisbash 1.1 _In_z_ const char *rhs,
338 _In_z_ const char *lhsText,
339 _In_z_ const char *rhsText,
340 _In_z_ const char *description,
341 NitsCallSite line,
342 NitsFaultMode mode)
343 {
344 CheckInjector();
345 return (ShouldCallNITSTable ? NITS.CompareStringA(lhs, rhs, lhsText, rhsText, description, line, mode) : NitsTrue);
346 }
347
348 static NitsResult NITS_CALL CompareStringW_Checked(
349 _In_z_ const wchar_t *lhs,
350 _In_z_ const wchar_t *rhs,
351 _In_z_ const char *lhsText,
352 _In_z_ const char *rhsText,
353 _In_z_ const wchar_t *description,
354 NitsCallSite line,
355 NitsFaultMode mode)
356 {
357 CheckInjector();
358 krisbash 1.1 return (ShouldCallNITSTable ? NITS.CompareStringW(lhs, rhs, lhsText, rhsText, description, line, mode) : NitsTrue);
359 }
360
361 static NitsResult NITS_CALL CompareSubstringA_Checked(
362 _In_z_ const char *lhs,
363 _In_z_ const char *rhs,
364 _In_z_ const char *lhsText,
365 _In_z_ const char *rhsText,
366 _In_z_ const char *description,
367 NitsCallSite line,
368 NitsFaultMode mode)
369 {
370 CheckInjector();
371 return (ShouldCallNITSTable ? NITS.CompareSubstringA(lhs, rhs, lhsText, rhsText, description, line, mode) : NitsTrue);
372 }
373
374 static NitsResult NITS_CALL CompareSubstringW_Checked(
375 _In_z_ const wchar_t *lhs,
376 _In_z_ const wchar_t *rhs,
377 _In_z_ const char *lhsText,
378 _In_z_ const char *rhsText,
379 krisbash 1.1 _In_z_ const wchar_t *description,
380 NitsCallSite line,
381 NitsFaultMode mode)
382 {
383 CheckInjector();
384 return (ShouldCallNITSTable ? NITS.CompareSubstringW(lhs, rhs, lhsText, rhsText, description, line, mode) : NitsTrue);
385 }
386
387 static NitsResult NITS_CALL DidFault()
388 {
389 return NitsFalse;
390 }
391
392 static NitsResult NITS_CALL IsActivated_Checked()
393 {
394 CheckInjector();
395 return NitsIsActivated();
396 }
397
398 static void NITS_CALL StopReportingIgnoredErrors()
399 {
400 krisbash 1.1 }
401
402 static int *NITS_CALL GetInt_Checked(
403 _In_z_ const char *name)
404 {
405 CheckInjector();
406 return NitsGetInt(name);
407 }
408
409 static const char *NITS_CALL GetStringA_Checked(
410 _In_z_ const char *name)
411 {
412 CheckInjector();
413 return NitsGetStringA(name);
414 }
415
416 static const wchar_t *NITS_CALL GetStringW_Checked(
417 _In_z_ const char *name)
418 {
419 CheckInjector();
420 return NitsGetStringW(name);
421 krisbash 1.1 }
422
423 static void NITS_CALL SetInt_Checked(
424 _In_z_ const char *name,
425 int data)
426 {
427 CheckInjector();
428 if(ShouldCallNITSTable) NITS.SetInt(name, data);
429 }
430
431 static void NITS_CALL SetStringA_Checked(
432 _In_z_ const char *name,
433 _In_z_ const char *data)
434 {
435 CheckInjector();
436 if(ShouldCallNITSTable) NITS.SetStringA(name, data);
437 }
438
439 static void NITS_CALL SetStringW_Checked(
440 _In_z_ const char *name,
441 _In_z_ const wchar_t *data)
442 krisbash 1.1 {
443 CheckInjector();
444 if(ShouldCallNITSTable) NITS.SetStringW(name, data);
445 }
446
447 static void NITS_CALL SetMode(
448 NitsTestMode mode)
449 {
450 PAL_UNUSED(mode);
451 }
452
453 static void NITS_CALL SetFault(
454 _In_opt_z_ const char *function,
455 _In_z_ const char *id,
456 int attempt)
457 {
458 PAL_UNUSED(function);
459 PAL_UNUSED(id);
460 PAL_UNUSED(attempt);
461 }
462
463 krisbash 1.1 static void NITS_CALL SetWait(
464 _In_opt_z_ const char *function,
465 _In_z_ const char *id,
466 int attempt,
467 _In_z_ const char *event)
468 {
469 PAL_UNUSED(function);
470 PAL_UNUSED(id);
471 PAL_UNUSED(attempt);
472 PAL_UNUSED(event);
473 }
474
475 static void NITS_CALL Signal(
476 _In_z_ const char *event)
477 {
478 PAL_UNUSED(event);
479 }
480
481 static NitsResult NITS_CALL Wait(
482 _In_opt_z_ const char *function,
483 _In_z_ const char *id,
484 krisbash 1.1 int attempt,
485 int timeout)
486 {
487 PAL_UNUSED(function);
488 PAL_UNUSED(id);
489 PAL_UNUSED(attempt);
490 PAL_UNUSED(timeout);
491
492 return NitsTrue;
493 }
494
495 static void NITS_CALL ResetFaults()
496 {
497 }
498
499 static NitsTrapHandle NITS_CALL OpenTrap(
500 _In_z_ const char *binary,
501 _In_z_ const char *table,
502 unsigned version)
503 {
504 PAL_UNUSED(binary);
505 krisbash 1.1 PAL_UNUSED(table);
506 PAL_UNUSED(version);
507
508 return 0;
509 }
510
511 static const void *NITS_CALL GetTrap(
512 _In_ NitsTrapHandle handle,
513 unsigned offset)
514 {
515 PAL_UNUSED(handle);
516 PAL_UNUSED(offset);
517
518 return 0;
519 }
520
521 static const void *NITS_CALL NextTrap(
522 _In_z_ const char *table,
523 unsigned offset)
524 {
525 PAL_UNUSED(table);
526 krisbash 1.1 PAL_UNUSED(offset);
527
528 return 0;
529 }
530
531 static void *NITS_CALL SetTrap(
532 _In_ NitsTrapHandle handle,
533 _In_ void *function,
534 unsigned offset)
535 {
536 PAL_UNUSED(handle);
537 PAL_UNUSED(function);
538 PAL_UNUSED(offset);
539
540 return 0;
541 }
542
543 static void NITS_CALL CopyTrap(
544 _In_z_ const char *table,
545 _In_z_ const char *from,
546 _In_z_ const char *to)
547 krisbash 1.1 {
548 PAL_UNUSED(table);
549 PAL_UNUSED(from);
550 PAL_UNUSED(to);
551 }
552
553 static void NITS_CALL CloseTrap(
554 _In_ NitsTrapHandle handle)
555 {
556 PAL_UNUSED(handle);
557 }
558
559 NITS_DLLEXPORT ptrdiff_t NITS_PRESENCE_STUB = NitsPresenceUnknown;
560 NITS_DLLEXPORT NITS_CONST_FT NitsFT NITS_STUB =
561 {
562 ShouldFault_Checked,
563 TraceA,
564 TraceW,
565 AssertA_Checked,
566 AssertW_Checked,
567 CompareA_Checked,
568 krisbash 1.1 CompareW_Checked,
569 CompareStringA_Checked,
570 CompareStringW_Checked,
571 CompareSubstringA_Checked,
572 CompareSubstringW_Checked,
573 DidFault,
574 IsActivated_Checked,
575 StopReportingIgnoredErrors,
576 GetInt_Checked,
577 GetStringA_Checked,
578 GetStringW_Checked,
579 SetInt_Checked,
580 SetStringA_Checked,
581 SetStringW_Checked,
582 SetMode,
583 SetFault,
584 SetWait,
585 Signal,
586 Wait,
587 ResetFaults,
588 BeginResource_Checked,
589 krisbash 1.1 ChangeResource,
590 EndResource,
591 NULL,
592 NULL,
593 NULL,
594 OpenTrap,
595 GetTrap,
596 NextTrap,
597 SetTrap,
598 CopyTrap,
599 CloseTrap,
600 };
|