(file) Return to stub.c CVS log (file) (dir) Up to [OMI] / omi / pal

  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              };

ViewCVS 0.9.2