Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

557 lines
18 KiB

  1. #include "stdafx.h"
  2. #include "sxsplugMap.h"
  3. #define PRAGMA_UNSAFE_DELIMITER_DEFAULT ' '
  4. #define PRAGMA_UNSAFE_DELIMITER_BETWEEN_STATEMENT ';'
  5. #define PRAGMA_UNSAFE_DELIMITER_BETWEEN_VALUESTR ','
  6. #define PRAGMA_UNSAFE_DELIMITER_BETWEEN_KEYWORD_AND_VALUESTR ':'
  7. #define PRAGMA_UNSAFE_KEYWORD_UNSAFE "unsafe"
  8. #define PRAGMA_UNSAFE_KEYWORD_UNSAFE_PUSH "push"
  9. #define PRAGMA_UNSAFE_KEYWORD_UNSAFE_DISABLE "disable"
  10. #define PRAGMA_UNSAFE_KEYWORD_UNSAFE_ENABLE "enable"
  11. #define PRAGMA_UNSAFE_KEYWORD_UNSAFE_POP "pop"
  12. #define PRAGMA_UNSAFE_GETUSAFEOPERPARAMETERS_DWFLAG_UNSAFE_ENABLE 0
  13. #define PRAGMA_UNSAFE_GETUSAFEOPERPARAMETERS_DWFLAG_UNSAFE_DISABLE 1
  14. BOOL CPragmaUnsafe_UnsafeFunctionStateStack::ReInitialize()
  15. {
  16. m_UnsafeFuncs.clear(); // void function
  17. m_fInitialized = FALSE;
  18. return this->Initialize();
  19. }
  20. BOOL CPragmaUnsafe_UnsafeFunctionStateStack::Initialize()
  21. {
  22. ASSERT(m_fInitialized == FALSE);
  23. m_index = 0;
  24. BOOL fSuccess = AddFunctionIntoStack(POINTER_ARITHMATIC_FUNC);
  25. if (fSuccess)
  26. m_fInitialized = TRUE;
  27. return fSuccess;
  28. }
  29. BOOL CPragmaUnsafe_UnsafeFunctionStateStack::IsFunctionNotUnsafe(const char * strFuncName)
  30. {
  31. BOOL fSafe = TRUE; // defaultly all function are SAFE
  32. PragmaUnsafe_PRAGMA_UNSAFE_FUNCTIONS::iterator pIter;
  33. if (true == m_UnsafeFuncs.empty())
  34. return TRUE;
  35. DWORD CurrentIndex = m_index - 1;
  36. for (pIter = m_UnsafeFuncs.begin(); pIter != m_UnsafeFuncs.end(); pIter ++)
  37. {
  38. if (pIter->first.compare(strFuncName) == 0)
  39. {
  40. PragmaUnsafe_FUNCTION_STATUS & FuncStatusRecord = pIter->second;
  41. //
  42. // get current status : enabled or not
  43. //
  44. BYTE x = (FuncStatusRecord[CurrentIndex / sizeof(BYTE)] & (1 << (CurrentIndex % sizeof(BYTE)))) >> (CurrentIndex % sizeof(BYTE));
  45. // duplicate last status
  46. if (x == 0){
  47. fSafe = FALSE;
  48. }
  49. break; // find a result already
  50. }
  51. }
  52. return fSafe;
  53. }
  54. BOOL CPragmaUnsafe_UnsafeFunctionStateStack::OnUnsafeDisable(const char * strFuncNameGroups)
  55. {
  56. if (FALSE == IsInitialized())
  57. {
  58. PragmaUnsafe_ReportError("Not Initialized !!!\n");
  59. return FALSE;
  60. }
  61. if (IsStackFull())
  62. {
  63. PragmaUnsafe_ReportError("Stack is Full Sized now!\n");
  64. return FALSE;
  65. }
  66. return ResetStack(strFuncNameGroups, false);
  67. }
  68. VOID CPragmaUnsafe_UnsafeFunctionStateStack::PackStack()
  69. {
  70. if ( m_index == 0)
  71. return;
  72. BYTE AllEnabledStatus[8];
  73. for ( DWORD i = 0; i < (m_index - 1) / sizeof(BYTE); i++)
  74. AllEnabledStatus[i] = 0xFF;
  75. AllEnabledStatus[(m_index - 1) / sizeof(BYTE)] = ((1 << (((m_index - 1)% sizeof(BYTE)) + 1)) - 1) & 0xFF;
  76. //
  77. // if from 0..m_index - 1, all state is enabled: just delete this function from the map
  78. //
  79. for (PragmaUnsafe_PRAGMA_UNSAFE_FUNCTIONS::iterator pIter = m_UnsafeFuncs.begin(); pIter != m_UnsafeFuncs.end(); pIter ++)
  80. {
  81. if (memcmp((PVOID)(&pIter->second[0]), AllEnabledStatus, PragmaUnsafe_STACK_SIZE_IN_BYTE) == 0)
  82. m_UnsafeFuncs.erase(pIter->first);
  83. }
  84. //
  85. // no func in the stack, clean the map and reset m_index == 0;
  86. //
  87. if (m_UnsafeFuncs.empty())
  88. {
  89. m_UnsafeFuncs.clear();
  90. m_index = 0;
  91. }
  92. }
  93. BOOL CPragmaUnsafe_UnsafeFunctionStateStack::OnUnsafePop()
  94. {
  95. if (FALSE == IsInitialized())
  96. {
  97. PragmaUnsafe_ReportError("Not Initialized !!!\n");
  98. return FALSE;
  99. }
  100. ASSERT(m_index > 0);
  101. if (IsStackEmpty())
  102. {
  103. PragmaUnsafe_ReportError("Stack is current empty!\n");
  104. return FALSE;
  105. }
  106. m_index--;
  107. if (m_index == 0)
  108. {
  109. m_UnsafeFuncs.clear(); // delete the map
  110. }
  111. PackStack(); // void function
  112. return TRUE;
  113. }
  114. BOOL CPragmaUnsafe_UnsafeFunctionStateStack::OnUnsafePush()
  115. {
  116. BOOL fSuccess = FALSE;
  117. PragmaUnsafe_PRAGMA_UNSAFE_FUNCTIONS::iterator pIter, qIter;
  118. string strFuncName;
  119. DWORD CurrentIndex;
  120. if (FALSE == IsInitialized())
  121. {
  122. PragmaUnsafe_ReportError("Not Initialized !!!\n");
  123. goto Exit;
  124. }
  125. if (IsStackFull())
  126. {
  127. PragmaUnsafe_ReportError("Stack is Full Sized now!\n");
  128. goto Exit;
  129. }
  130. CurrentIndex = (m_index - 1);
  131. ASSERT(CurrentIndex >= 0); //because we have check that the stack is not empty
  132. for (pIter = m_UnsafeFuncs.begin(); pIter != m_UnsafeFuncs.end(); pIter ++)
  133. {
  134. PragmaUnsafe_FUNCTION_STATUS & FuncStatusRecord = pIter->second; // ref is return...
  135. //
  136. // get current status of each function
  137. //
  138. BYTE x = (FuncStatusRecord[CurrentIndex / sizeof(BYTE)] & (1 << (CurrentIndex % sizeof(BYTE)))) >> (CurrentIndex % sizeof(BYTE));
  139. ASSERT((x == 0) || (x == 1));
  140. // duplicate last status
  141. if ( x == 1)
  142. FuncStatusRecord[m_index / sizeof(BYTE)] |= ((1 << (m_index % sizeof(BYTE))) & 0x00ff);
  143. else
  144. FuncStatusRecord[m_index / sizeof(BYTE)] &= (~((1 << (m_index % sizeof(BYTE))) & 0x00ff) & 0x00ff);
  145. }
  146. m_index ++;
  147. fSuccess = TRUE;
  148. Exit:
  149. return fSuccess;
  150. }
  151. BOOL CPragmaUnsafe_UnsafeFunctionStateStack::OnUnsafeEnable(const char * strFuncNameGroups)
  152. {
  153. if (FALSE == IsInitialized())
  154. {
  155. PragmaUnsafe_ReportError("Not Initialized !!!\n");
  156. return FALSE;
  157. }
  158. if (IsStackEmpty())
  159. {
  160. PragmaUnsafe_ReportError("Stack is Empty now!\n");
  161. return TRUE;
  162. }
  163. return ResetStack(strFuncNameGroups, true);
  164. }
  165. // if a function is already in the stack, change current status
  166. // if a function is not in the stack:
  167. // if you try to disable it : add it to the stack and would disfunction after pop is done
  168. // if you try to enable it : we cannot igore it in case that it go with a push and later a pop, so
  169. // just add it to the stack and would disfunction after pop is done
  170. BOOL CPragmaUnsafe_UnsafeFunctionStateStack::ResetStack(const char * strFuncNameGroups, bool fEnable)
  171. {
  172. BOOL fSuccess = FALSE;
  173. PragmaUnsafe_PRAGMA_UNSAFE_FUNCTIONS::iterator pIter, qIter;
  174. string strFuncName;
  175. istrstream streamFuncNameStream(strFuncNameGroups);
  176. DWORD CurIndex;
  177. //
  178. // suppose that the func names are delimited using ;
  179. // for each function which reset status
  180. //
  181. for (; getline(streamFuncNameStream, strFuncName, PRAGMA_UNSAFE_DELIMITER_BETWEEN_VALUESTR); )
  182. {
  183. if (strFuncName.empty())
  184. break;
  185. qIter = m_UnsafeFuncs.find(strFuncName);
  186. //
  187. // this function is not on map currently,
  188. //
  189. if (qIter == m_UnsafeFuncs.end())
  190. {
  191. //
  192. // adding into the stack as a disabled function, see the comments at the function declaration
  193. //
  194. if ( FALSE == AddFunctionIntoStack(strFuncName.c_str(), fEnable))
  195. {
  196. PragmaUnsafe_ReportError("AddFunctionIntoStack for %s failed\n", strFuncName.c_str());
  197. }
  198. continue;
  199. }
  200. ASSERT(m_index > 0);
  201. CurIndex = m_index - 1;
  202. PragmaUnsafe_FUNCTION_STATUS & FuncStatusRecord = qIter->second;
  203. // overwrite the current status
  204. if (fEnable == true)
  205. FuncStatusRecord[CurIndex / sizeof(BYTE)] |= ((1 << (CurIndex % sizeof(BYTE))) & 0xff);
  206. else
  207. FuncStatusRecord[CurIndex / sizeof(BYTE)] &= (~((1 << (CurIndex % sizeof(BYTE))) & 0xff) & 0xff);
  208. }
  209. fSuccess = TRUE;
  210. return fSuccess;
  211. }
  212. void TrimString(string & strFuncName, DWORD dwFlag = STRING_TRIM_FLAG_LEFT | STRING_TRIM_FLAG_RIGHT)
  213. {
  214. int i;
  215. if (dwFlag & STRING_TRIM_FLAG_LEFT)
  216. {
  217. // left trim
  218. i = 0;
  219. while ((strFuncName[i] == ' ') && (i < strFuncName.length())) i++;
  220. if ( i > 0)
  221. strFuncName.erase(0,i);
  222. }
  223. if (dwFlag & STRING_TRIM_FLAG_RIGHT)
  224. {
  225. // right trim
  226. i = strFuncName.length() - 1;
  227. while ((strFuncName[i] == ' ') && (i >= 0 )) i--;
  228. if ( i != strFuncName.length() - 1)
  229. strFuncName.erase(i, (strFuncName.length() - i));
  230. }
  231. return;
  232. }
  233. //
  234. // when this function is called, this func must not in the current stack
  235. //
  236. BOOL CPragmaUnsafe_UnsafeFunctionStateStack::AddFunctionIntoStack(const char * strFuncNameGroups, bool fEnabled)
  237. {
  238. BOOL fSuccess = FALSE;
  239. string strFuncName;
  240. istrstream streamFuncNameStream(strFuncNameGroups);
  241. PragmaUnsafe_FUNCTION_STATUS new_func_status;
  242. DWORD CurrentIndex;
  243. if (m_index == 0)
  244. m_index ++;
  245. //
  246. // suppose that the func names are delimited using ;
  247. //
  248. CurrentIndex = m_index -1 ;
  249. for (; getline(streamFuncNameStream, strFuncName, PRAGMA_UNSAFE_DELIMITER_BETWEEN_VALUESTR); )
  250. {
  251. if (strFuncName.empty())
  252. break;
  253. TrimString(strFuncName); // left-trim and right-trim
  254. if (strFuncName.empty())
  255. break;
  256. if (m_UnsafeFuncs.find(strFuncName) != m_UnsafeFuncs.end())
  257. {
  258. //
  259. // If the function has already in the map, we just ignore it.
  260. // This would deal with a header file with "#pragam unsafe(disable: func1)" is included multiple times.
  261. // that is, if the sequence is
  262. // #pragam unsafe(disable: func1)
  263. // #pragam unsafe(push, enable:func1)
  264. // #pragam unsafe(disable:func1) ---> would be ignored, and func1 is still enabled at this moment
  265. // #pragam unsafe(pop)
  266. //
  267. // in this case, a warning message would be issued
  268. //PragmaUnsafe_ReportWarning(PragmaUnsafe_PLUGIN_WARNING_MSG_PREFIX, "%s has already been disabled\n", strFuncName);
  269. PragmaUnsafe_ReportError("%s has already been disabled\n", strFuncName.c_str());
  270. continue;
  271. }
  272. ZeroMemory(&new_func_status, sizeof(new_func_status)); // grow to the same size as all other functions
  273. // set to be "1" for the range of 0..CurrentIndex-1
  274. if (CurrentIndex > sizeof(BYTE) + 1)
  275. {
  276. for (int i = 0 ; i < ((CurrentIndex - 1) / sizeof(BYTE)); i++)
  277. new_func_status[i] = 0xFF;
  278. }
  279. if (fEnabled == true)
  280. {
  281. new_func_status[CurrentIndex / sizeof(BYTE)] = ((1 << ((CurrentIndex % sizeof(BYTE)) + 1)) - 1) & 0xFF;
  282. }
  283. else
  284. {
  285. new_func_status[CurrentIndex / sizeof(BYTE)] = ((1 << (CurrentIndex % sizeof(BYTE))) - 1) & 0xFF;
  286. }
  287. m_UnsafeFuncs.insert(PragmaUnsafe_PRAGMA_UNSAFE_FUNCTIONS::value_type(strFuncName, new_func_status));
  288. }
  289. fSuccess = TRUE;
  290. //Exit:
  291. return fSuccess;
  292. }
  293. VOID CPragmaUnsafe_UnsafeFunctionStateStack::PrintFunctionCurrentStatus(int level)
  294. {
  295. PragmaUnsafe_PRAGMA_UNSAFE_FUNCTIONS::iterator pIter, qIter;
  296. cout << endl << endl << "CurrentStack:" << endl;
  297. cout << "m_index = " << m_index << endl;
  298. //
  299. // for each current item in map, push to preserve its current status
  300. //
  301. if (m_index == 0)
  302. {
  303. return;
  304. }
  305. DWORD CurrentIndex = (m_index - 1);
  306. BYTE x;
  307. for (pIter = m_UnsafeFuncs.begin(); pIter != m_UnsafeFuncs.end(); pIter ++)
  308. {
  309. PragmaUnsafe_FUNCTION_STATUS & FuncStatusRecord = pIter->second; // ref is return...
  310. //
  311. // get current status of each function
  312. //
  313. x = (FuncStatusRecord[CurrentIndex / sizeof(BYTE)] & (1 << (CurrentIndex % sizeof(BYTE)))) >> (CurrentIndex % sizeof(BYTE));
  314. for ( int j = 0 ; j < level; j++)
  315. cout << " ";
  316. cout << pIter->first << ":"<< ((x == 0) ? "Disabled" : "Enabled") << endl;
  317. }
  318. return;
  319. }
  320. //
  321. // this function is only called when the end of file is reached
  322. //
  323. BOOL CPragmaUnsafe_UnsafeFunctionStateStack::CheckIntegrityAtEndOfFile()
  324. {
  325. if (m_index == 1) // should always be 1 since pointer_arithmatic is default
  326. return TRUE;
  327. else
  328. return FALSE;
  329. }
  330. /*
  331. at each file beginning: reset the pragma stack because of its file-range
  332. */
  333. BOOL PragmaUnsafe_OnFileStart()
  334. {
  335. //
  336. // initalize the map structure everytime when prefast start to parse
  337. //
  338. return Sxs_PragmaUnsafedFunctions.ReInitialize();
  339. }
  340. /*
  341. at each file end: verify integrity of the stake
  342. */
  343. BOOL PragmaUnsafe_OnFileEnd()
  344. {
  345. //Sxs_PragmaUnsafedFunctions.PrintFunctionCurrentStatus(0);
  346. return Sxs_PragmaUnsafedFunctions.CheckIntegrityAtEndOfFile();
  347. }
  348. VOID PragmaUnsafe_GetUsafeOperParameters(DWORD dwFlag, const string & strPragmaUnsafeSingleStatement, string & strFuncNameList)
  349. {
  350. // initialize
  351. strFuncNameList.erase();
  352. int iPrefix = 0;
  353. if ( dwFlag == PRAGMA_UNSAFE_GETUSAFEOPERPARAMETERS_DWFLAG_UNSAFE_ENABLE)
  354. iPrefix = strlen(PRAGMA_UNSAFE_KEYWORD_UNSAFE_ENABLE);
  355. else if ( dwFlag == PRAGMA_UNSAFE_GETUSAFEOPERPARAMETERS_DWFLAG_UNSAFE_DISABLE)
  356. iPrefix = strlen(PRAGMA_UNSAFE_KEYWORD_UNSAFE_DISABLE);
  357. if (iPrefix == 0) // error case
  358. {
  359. goto ErrorExit;
  360. }
  361. strFuncNameList.assign(strPragmaUnsafeSingleStatement);
  362. strFuncNameList.erase(0, iPrefix);
  363. TrimString(strFuncNameList);
  364. // should be in the format of [enable|disbale]: func1, func2, func3
  365. if (strFuncNameList[0] != PRAGMA_UNSAFE_DELIMITER_BETWEEN_KEYWORD_AND_VALUESTR)
  366. {
  367. goto ErrorExit;
  368. }
  369. strFuncNameList.erase(0, 1); // get rid :
  370. TrimString(strFuncNameList);
  371. goto Exit;
  372. ErrorExit:
  373. if (!strFuncNameList.empty())
  374. strFuncNameList.erase();
  375. Exit:
  376. return;
  377. }
  378. BOOL PragmaUnsafe_OnPragma(char * str, PRAGMA_STATEMENT & ePragmaUnsafe)
  379. {
  380. BOOL fSuccess = FALSE;
  381. istrstream streamParagmaString(str);
  382. string strPragmaUnsafeSingleStatement;
  383. string strFuncNameList;
  384. ePragmaUnsafe = PRAGMA_NOT_UNSAFE_STATEMENT;
  385. //
  386. // check whether it begins with "unsafe", that is, its prefix is "unsafe:"
  387. // get the first string which is sperate from the left using ' '
  388. //
  389. getline(streamParagmaString, strPragmaUnsafeSingleStatement, ':');
  390. TrimString(strPragmaUnsafeSingleStatement); // void func
  391. if (true == strPragmaUnsafeSingleStatement.empty())
  392. {
  393. ePragmaUnsafe = PRAGMA_NOT_UNSAFE_STATEMENT;
  394. fSuccess = TRUE;
  395. goto Exit;
  396. }
  397. //
  398. // pragam unsafe keyword comparsion is case-sensitive
  399. //
  400. if (strncmp(strPragmaUnsafeSingleStatement.c_str(), PRAGMA_UNSAFE_KEYWORD_UNSAFE, strlen(PRAGMA_UNSAFE_KEYWORD_UNSAFE)) != 0)
  401. {
  402. // not start with Keyword "unsafe"
  403. ePragmaUnsafe = PRAGMA_NOT_UNSAFE_STATEMENT;
  404. fSuccess = TRUE;
  405. goto Exit;
  406. }
  407. // so far, the statement is valid
  408. ePragmaUnsafe = PRAGMA_UNSAFE_STATEMENT_VALID;
  409. for (; getline(streamParagmaString, strPragmaUnsafeSingleStatement, PRAGMA_UNSAFE_DELIMITER_BETWEEN_STATEMENT); )
  410. {
  411. //
  412. // to get a statement begin with "push", or "enable", or "disable", or "pop",
  413. // we deal with push/pop first because they are non-parameter statements
  414. //
  415. TrimString(strPragmaUnsafeSingleStatement);
  416. if (strPragmaUnsafeSingleStatement.compare(PRAGMA_UNSAFE_KEYWORD_UNSAFE_PUSH) == 0)
  417. {
  418. Sxs_PragmaUnsafedFunctions.OnUnsafePush();
  419. }
  420. else
  421. if (strPragmaUnsafeSingleStatement.compare(PRAGMA_UNSAFE_KEYWORD_UNSAFE_POP) == 0)
  422. {
  423. Sxs_PragmaUnsafedFunctions.OnUnsafePop();
  424. }
  425. else
  426. if (strncmp(strPragmaUnsafeSingleStatement.c_str(), PRAGMA_UNSAFE_KEYWORD_UNSAFE_ENABLE, strlen(PRAGMA_UNSAFE_KEYWORD_UNSAFE_ENABLE)) == 0)
  427. {
  428. PragmaUnsafe_GetUsafeOperParameters(PRAGMA_UNSAFE_GETUSAFEOPERPARAMETERS_DWFLAG_UNSAFE_ENABLE, strPragmaUnsafeSingleStatement, strFuncNameList);
  429. if (strFuncNameList.empty())
  430. {
  431. PragmaUnsafe_ReportError("Invalid string for pragma unsafe: %s\n", strPragmaUnsafeSingleStatement.c_str());
  432. goto Exit;
  433. }
  434. else
  435. {
  436. Sxs_PragmaUnsafedFunctions.OnUnsafeEnable(strFuncNameList.c_str());
  437. }
  438. }
  439. else
  440. if (strncmp(strPragmaUnsafeSingleStatement.c_str(), PRAGMA_UNSAFE_KEYWORD_UNSAFE_DISABLE, strlen(PRAGMA_UNSAFE_KEYWORD_UNSAFE_DISABLE)) == 0)
  441. {
  442. PragmaUnsafe_GetUsafeOperParameters(PRAGMA_UNSAFE_GETUSAFEOPERPARAMETERS_DWFLAG_UNSAFE_DISABLE, strPragmaUnsafeSingleStatement, strFuncNameList);
  443. if (strFuncNameList.empty())
  444. {
  445. PragmaUnsafe_ReportError("Invalid string for pragma unsafe: %s\n", strPragmaUnsafeSingleStatement.c_str());
  446. goto Exit;
  447. }
  448. else
  449. {
  450. Sxs_PragmaUnsafedFunctions.OnUnsafeDisable(strFuncNameList.c_str());
  451. }
  452. }
  453. else
  454. {
  455. // invalid string in pragma beginning with "unsafe"
  456. ePragmaUnsafe = PRAGMA_UNSAFE_STATEMENT_INVALID;
  457. PragmaUnsafe_ReportError("Invalid string for pragma unsafe: %s\n", strPragmaUnsafeSingleStatement.c_str());
  458. goto Exit;
  459. }
  460. }
  461. //Sxs_PragmaUnsafedFunctions.PrintFunctionCurrentStatus(0);
  462. fSuccess = TRUE;
  463. Exit:
  464. return fSuccess;
  465. }
  466. BOOL PragmaUnsafe_IsPointerArithmaticEnabled()
  467. {
  468. return Sxs_PragmaUnsafedFunctions.IsFunctionNotUnsafe(POINTER_ARITHMATIC_FUNC);
  469. }
  470. int ReportInternalError(int nLine)
  471. {
  472. _tprintf(TEXT("%hs(%d) : Internal Error Occurred\n"),
  473. __FILE__, nLine);
  474. return 0;
  475. }