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.

hooks.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. /* -------------------------------------------------------------------------
  2. *
  3. * contrib/sepgsql/hooks.c
  4. *
  5. * Entrypoints of the hooks in PostgreSQL, and dispatches the callbacks.
  6. *
  7. * Copyright (c) 2010-2019, PostgreSQL Global Development Group
  8. *
  9. * -------------------------------------------------------------------------
  10. */
  11. #include "postgres.h"
  12. #include "catalog/dependency.h"
  13. #include "catalog/objectaccess.h"
  14. #include "catalog/pg_class.h"
  15. #include "catalog/pg_database.h"
  16. #include "catalog/pg_namespace.h"
  17. #include "catalog/pg_proc.h"
  18. #include "commands/seclabel.h"
  19. #include "executor/executor.h"
  20. #include "fmgr.h"
  21. #include "miscadmin.h"
  22. #include "tcop/utility.h"
  23. #include "utils/guc.h"
  24. #include "utils/queryenvironment.h"
  25. #include "sepgsql.h"
  26. PG_MODULE_MAGIC;
  27. /*
  28. * Declarations
  29. */
  30. void _PG_init(void);
  31. /*
  32. * Saved hook entries (if stacked)
  33. */
  34. static object_access_hook_type next_object_access_hook = NULL;
  35. static ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL;
  36. static ProcessUtility_hook_type next_ProcessUtility_hook = NULL;
  37. /*
  38. * Contextual information on DDL commands
  39. */
  40. typedef struct
  41. {
  42. NodeTag cmdtype;
  43. /*
  44. * Name of the template database given by users on CREATE DATABASE
  45. * command. Elsewhere (including the case of default) NULL.
  46. */
  47. const char *createdb_dtemplate;
  48. } sepgsql_context_info_t;
  49. static sepgsql_context_info_t sepgsql_context_info;
  50. /*
  51. * GUC: sepgsql.permissive = (on|off)
  52. */
  53. static bool sepgsql_permissive;
  54. bool
  55. sepgsql_get_permissive(void)
  56. {
  57. return sepgsql_permissive;
  58. }
  59. /*
  60. * GUC: sepgsql.debug_audit = (on|off)
  61. */
  62. static bool sepgsql_debug_audit;
  63. bool
  64. sepgsql_get_debug_audit(void)
  65. {
  66. return sepgsql_debug_audit;
  67. }
  68. /*
  69. * sepgsql_object_access
  70. *
  71. * Entrypoint of the object_access_hook. This routine performs as
  72. * a dispatcher of invocation based on access type and object classes.
  73. */
  74. static void
  75. sepgsql_object_access(ObjectAccessType access,
  76. Oid classId,
  77. Oid objectId,
  78. int subId,
  79. void *arg)
  80. {
  81. if (next_object_access_hook)
  82. (*next_object_access_hook) (access, classId, objectId, subId, arg);
  83. switch (access)
  84. {
  85. case OAT_POST_CREATE:
  86. {
  87. ObjectAccessPostCreate *pc_arg = arg;
  88. bool is_internal;
  89. is_internal = pc_arg ? pc_arg->is_internal : false;
  90. switch (classId)
  91. {
  92. case DatabaseRelationId:
  93. Assert(!is_internal);
  94. sepgsql_database_post_create(objectId,
  95. sepgsql_context_info.createdb_dtemplate);
  96. break;
  97. case NamespaceRelationId:
  98. Assert(!is_internal);
  99. sepgsql_schema_post_create(objectId);
  100. break;
  101. case RelationRelationId:
  102. if (subId == 0)
  103. {
  104. /*
  105. * The cases in which we want to apply permission
  106. * checks on creation of a new relation correspond
  107. * to direct user invocation. For internal uses,
  108. * that is creation of toast tables, index rebuild
  109. * or ALTER TABLE commands, we need neither
  110. * assignment of security labels nor permission
  111. * checks.
  112. */
  113. if (is_internal)
  114. break;
  115. sepgsql_relation_post_create(objectId);
  116. }
  117. else
  118. sepgsql_attribute_post_create(objectId, subId);
  119. break;
  120. case ProcedureRelationId:
  121. Assert(!is_internal);
  122. sepgsql_proc_post_create(objectId);
  123. break;
  124. default:
  125. /* Ignore unsupported object classes */
  126. break;
  127. }
  128. }
  129. break;
  130. case OAT_DROP:
  131. {
  132. ObjectAccessDrop *drop_arg = (ObjectAccessDrop *) arg;
  133. /*
  134. * No need to apply permission checks on object deletion due
  135. * to internal cleanups; such as removal of temporary database
  136. * object on session closed.
  137. */
  138. if ((drop_arg->dropflags & PERFORM_DELETION_INTERNAL) != 0)
  139. break;
  140. switch (classId)
  141. {
  142. case DatabaseRelationId:
  143. sepgsql_database_drop(objectId);
  144. break;
  145. case NamespaceRelationId:
  146. sepgsql_schema_drop(objectId);
  147. break;
  148. case RelationRelationId:
  149. if (subId == 0)
  150. sepgsql_relation_drop(objectId);
  151. else
  152. sepgsql_attribute_drop(objectId, subId);
  153. break;
  154. case ProcedureRelationId:
  155. sepgsql_proc_drop(objectId);
  156. break;
  157. default:
  158. /* Ignore unsupported object classes */
  159. break;
  160. }
  161. }
  162. break;
  163. case OAT_POST_ALTER:
  164. {
  165. ObjectAccessPostAlter *pa_arg = arg;
  166. bool is_internal = pa_arg->is_internal;
  167. switch (classId)
  168. {
  169. case DatabaseRelationId:
  170. Assert(!is_internal);
  171. sepgsql_database_setattr(objectId);
  172. break;
  173. case NamespaceRelationId:
  174. Assert(!is_internal);
  175. sepgsql_schema_setattr(objectId);
  176. break;
  177. case RelationRelationId:
  178. if (subId == 0)
  179. {
  180. /*
  181. * A case when we don't want to apply permission
  182. * check is that relation is internally altered
  183. * without user's intention. E.g, no need to check
  184. * on toast table/index to be renamed at end of
  185. * the table rewrites.
  186. */
  187. if (is_internal)
  188. break;
  189. sepgsql_relation_setattr(objectId);
  190. }
  191. else
  192. sepgsql_attribute_setattr(objectId, subId);
  193. break;
  194. case ProcedureRelationId:
  195. Assert(!is_internal);
  196. sepgsql_proc_setattr(objectId);
  197. break;
  198. default:
  199. /* Ignore unsupported object classes */
  200. break;
  201. }
  202. }
  203. break;
  204. case OAT_NAMESPACE_SEARCH:
  205. {
  206. ObjectAccessNamespaceSearch *ns_arg = arg;
  207. /*
  208. * If stacked extension already decided not to allow users to
  209. * search this schema, we just stick with that decision.
  210. */
  211. if (!ns_arg->result)
  212. break;
  213. Assert(classId == NamespaceRelationId);
  214. Assert(ns_arg->result);
  215. ns_arg->result
  216. = sepgsql_schema_search(objectId,
  217. ns_arg->ereport_on_violation);
  218. }
  219. break;
  220. case OAT_FUNCTION_EXECUTE:
  221. {
  222. Assert(classId == ProcedureRelationId);
  223. sepgsql_proc_execute(objectId);
  224. }
  225. break;
  226. default:
  227. elog(ERROR, "unexpected object access type: %d", (int) access);
  228. break;
  229. }
  230. }
  231. /*
  232. * sepgsql_exec_check_perms
  233. *
  234. * Entrypoint of DML permissions
  235. */
  236. static bool
  237. sepgsql_exec_check_perms(List *rangeTabls, bool abort)
  238. {
  239. /*
  240. * If security provider is stacking and one of them replied 'false' at
  241. * least, we don't need to check any more.
  242. */
  243. if (next_exec_check_perms_hook &&
  244. !(*next_exec_check_perms_hook) (rangeTabls, abort))
  245. return false;
  246. if (!sepgsql_dml_privileges(rangeTabls, abort))
  247. return false;
  248. return true;
  249. }
  250. /*
  251. * sepgsql_utility_command
  252. *
  253. * It tries to rough-grained control on utility commands; some of them can
  254. * break whole of the things if nefarious user would use.
  255. */
  256. static void
  257. sepgsql_utility_command(PlannedStmt *pstmt,
  258. const char *queryString,
  259. ProcessUtilityContext context,
  260. ParamListInfo params,
  261. QueryEnvironment *queryEnv,
  262. DestReceiver *dest,
  263. char *completionTag)
  264. {
  265. Node *parsetree = pstmt->utilityStmt;
  266. sepgsql_context_info_t saved_context_info = sepgsql_context_info;
  267. ListCell *cell;
  268. PG_TRY();
  269. {
  270. /*
  271. * Check command tag to avoid nefarious operations, and save the
  272. * current contextual information to determine whether we should apply
  273. * permission checks here, or not.
  274. */
  275. sepgsql_context_info.cmdtype = nodeTag(parsetree);
  276. switch (nodeTag(parsetree))
  277. {
  278. case T_CreatedbStmt:
  279. /*
  280. * We hope to reference name of the source database, but it
  281. * does not appear in system catalog. So, we save it here.
  282. */
  283. foreach(cell, ((CreatedbStmt *) parsetree)->options)
  284. {
  285. DefElem *defel = (DefElem *) lfirst(cell);
  286. if (strcmp(defel->defname, "template") == 0)
  287. {
  288. sepgsql_context_info.createdb_dtemplate
  289. = strVal(defel->arg);
  290. break;
  291. }
  292. }
  293. break;
  294. case T_LoadStmt:
  295. /*
  296. * We reject LOAD command across the board on enforcing mode,
  297. * because a binary module can arbitrarily override hooks.
  298. */
  299. if (sepgsql_getenforce())
  300. {
  301. ereport(ERROR,
  302. (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  303. errmsg("SELinux: LOAD is not permitted")));
  304. }
  305. break;
  306. default:
  307. /*
  308. * Right now we don't check any other utility commands,
  309. * because it needs more detailed information to make access
  310. * control decision here, but we don't want to have two parse
  311. * and analyze routines individually.
  312. */
  313. break;
  314. }
  315. if (next_ProcessUtility_hook)
  316. (*next_ProcessUtility_hook) (pstmt, queryString,
  317. context, params, queryEnv,
  318. dest, completionTag);
  319. else
  320. standard_ProcessUtility(pstmt, queryString,
  321. context, params, queryEnv,
  322. dest, completionTag);
  323. }
  324. PG_CATCH();
  325. {
  326. sepgsql_context_info = saved_context_info;
  327. PG_RE_THROW();
  328. }
  329. PG_END_TRY();
  330. sepgsql_context_info = saved_context_info;
  331. }
  332. /*
  333. * Module load/unload callback
  334. */
  335. void
  336. _PG_init(void)
  337. {
  338. /*
  339. * We allow to load the SE-PostgreSQL module on single-user-mode or
  340. * shared_preload_libraries settings only.
  341. */
  342. if (IsUnderPostmaster)
  343. ereport(ERROR,
  344. (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
  345. errmsg("sepgsql must be loaded via shared_preload_libraries")));
  346. /*
  347. * Check availability of SELinux on the platform. If disabled, we cannot
  348. * activate any SE-PostgreSQL features, and we have to skip rest of
  349. * initialization.
  350. */
  351. if (is_selinux_enabled() < 1)
  352. {
  353. sepgsql_set_mode(SEPGSQL_MODE_DISABLED);
  354. return;
  355. }
  356. /*
  357. * sepgsql.permissive = (on|off)
  358. *
  359. * This variable controls performing mode of SE-PostgreSQL on user's
  360. * session.
  361. */
  362. DefineCustomBoolVariable("sepgsql.permissive",
  363. "Turn on/off permissive mode in SE-PostgreSQL",
  364. NULL,
  365. &sepgsql_permissive,
  366. false,
  367. PGC_SIGHUP,
  368. GUC_NOT_IN_SAMPLE,
  369. NULL,
  370. NULL,
  371. NULL);
  372. /*
  373. * sepgsql.debug_audit = (on|off)
  374. *
  375. * This variable allows users to turn on/off audit logs on access control
  376. * decisions, independent from auditallow/auditdeny setting in the
  377. * security policy. We intend to use this option for debugging purpose.
  378. */
  379. DefineCustomBoolVariable("sepgsql.debug_audit",
  380. "Turn on/off debug audit messages",
  381. NULL,
  382. &sepgsql_debug_audit,
  383. false,
  384. PGC_USERSET,
  385. GUC_NOT_IN_SAMPLE,
  386. NULL,
  387. NULL,
  388. NULL);
  389. /* Initialize userspace access vector cache */
  390. sepgsql_avc_init();
  391. /* Initialize security label of the client and related stuff */
  392. sepgsql_init_client_label();
  393. /* Security label provider hook */
  394. register_label_provider(SEPGSQL_LABEL_TAG,
  395. sepgsql_object_relabel);
  396. /* Object access hook */
  397. next_object_access_hook = object_access_hook;
  398. object_access_hook = sepgsql_object_access;
  399. /* DML permission check */
  400. next_exec_check_perms_hook = ExecutorCheckPerms_hook;
  401. ExecutorCheckPerms_hook = sepgsql_exec_check_perms;
  402. /* ProcessUtility hook */
  403. next_ProcessUtility_hook = ProcessUtility_hook;
  404. ProcessUtility_hook = sepgsql_utility_command;
  405. /* init contextual info */
  406. memset(&sepgsql_context_info, 0, sizeof(sepgsql_context_info));
  407. }