/* * sepgsql_attribute_post_create * * This routine assigns a default security label on a newly defined * column, using ALTER TABLE ... ADD COLUMN. * Note that this routine is not invoked in the case of CREATE TABLE, * although it also defines columns in addition to table. */ void sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum) { char *scontext = sepgsql_get_client_label(); char *tcontext; char *ncontext; ObjectAddress object; /* * Only attributes within regular relation have individual security * labels. */ if (get_rel_relkind(relOid) != RELKIND_RELATION) return; /* * Compute a default security label when we create a new procedure object * under the specified namespace. */ scontext = sepgsql_get_client_label(); tcontext = sepgsql_get_label(RelationRelationId, relOid, 0); ncontext = sepgsql_compute_create(scontext, tcontext, SEPG_CLASS_DB_COLUMN); /* * Assign the default security label on a new procedure */ object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = attnum; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext); pfree(tcontext); pfree(ncontext); }
/* * sepgsql_schema_post_create * * This routine assigns a default security label on a newly defined * schema. */ void sepgsql_schema_post_create(Oid namespaceId) { char *scontext; char *tcontext; char *ncontext; ObjectAddress object; /* * Compute a default security label when we create a new schema object * under the working database. */ scontext = sepgsql_get_client_label(); tcontext = sepgsql_get_label(DatabaseRelationId, MyDatabaseId, 0); ncontext = sepgsql_compute_create(scontext, tcontext, SEPG_CLASS_DB_SCHEMA); /* * Assign the default security label on a new procedure */ object.classId = NamespaceRelationId; object.objectId = namespaceId; object.objectSubId = 0; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext); pfree(ncontext); pfree(tcontext); }
/* * sepgsql_proc_relabel * * It checks privileges to relabel the supplied function * by the `seclabel'. */ void sepgsql_proc_relabel(Oid functionId, const char *seclabel) { char *scontext = sepgsql_get_client_label(); char *tcontext; char *audit_name; audit_name = get_func_name(functionId); /* * check db_procedure:{setattr relabelfrom} permission */ tcontext = sepgsql_get_label(ProcedureRelationId, functionId, 0); sepgsql_check_perms(scontext, tcontext, SEPG_CLASS_DB_PROCEDURE, SEPG_DB_PROCEDURE__SETATTR | SEPG_DB_PROCEDURE__RELABELFROM, audit_name, true); pfree(tcontext); /* * check db_procedure:{relabelto} permission */ sepgsql_check_perms(scontext, seclabel, SEPG_CLASS_DB_PROCEDURE, SEPG_DB_PROCEDURE__RELABELTO, audit_name, true); pfree(audit_name); }
/* * sepgsql_needs_fmgr_hook * * It informs the core whether the supplied function is trusted procedure, * or not. If true, sepgsql_fmgr_hook shall be invoked at start, end, and * abort time of function invocation. */ static bool sepgsql_needs_fmgr_hook(Oid functionId) { char *old_label; char *new_label; char *function_label; if (next_needs_fmgr_hook && (*next_needs_fmgr_hook)(functionId)) return true; /* * SELinux needs the function to be called via security_definer * wrapper, if this invocation will take a domain-transition. * We call these functions as trusted-procedure, if the security * policy has a rule that switches security label of the client * on execution. */ old_label = sepgsql_get_client_label(); new_label = sepgsql_proc_get_domtrans(functionId); if (strcmp(old_label, new_label) != 0) { pfree(new_label); return true; } pfree(new_label); /* * Even if not a trusted-procedure, this function should not be inlined * unless the client has db_procedure:{execute} permission. * Please note that it shall be actually failed later because of same * reason with ACL_EXECUTE. */ function_label = sepgsql_get_label(ProcedureRelationId, functionId, 0); if (sepgsql_check_perms(sepgsql_get_client_label(), function_label, SEPG_CLASS_DB_PROCEDURE, SEPG_DB_PROCEDURE__EXECUTE, NULL, false) != true) { pfree(function_label); return true; } pfree(function_label); return false; }
/* * sepgsql_proc_post_create * * This routine assigns a default security label on a newly defined * procedure. */ void sepgsql_proc_post_create(Oid functionId) { Relation rel; ScanKeyData skey; SysScanDesc sscan; HeapTuple tuple; Oid namespaceId; ObjectAddress object; char *scontext; char *tcontext; char *ncontext; /* * Fetch namespace of the new procedure. Because pg_proc entry is not * visible right now, we need to scan the catalog using SnapshotSelf. */ rel = heap_open(ProcedureRelationId, AccessShareLock); ScanKeyInit(&skey, ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(functionId)); sscan = systable_beginscan(rel, ProcedureOidIndexId, true, SnapshotSelf, 1, &skey); tuple = systable_getnext(sscan); if (!HeapTupleIsValid(tuple)) elog(ERROR, "catalog lookup failed for proc %u", functionId); namespaceId = ((Form_pg_proc) GETSTRUCT(tuple))->pronamespace; systable_endscan(sscan); heap_close(rel, AccessShareLock); /* * Compute a default security label when we create a new procedure object * under the specified namespace. */ scontext = sepgsql_get_client_label(); tcontext = sepgsql_get_label(NamespaceRelationId, namespaceId, 0); ncontext = sepgsql_compute_create(scontext, tcontext, SEPG_CLASS_DB_PROCEDURE); /* * Assign the default security label on a new procedure */ object.classId = ProcedureRelationId; object.objectId = functionId; object.objectSubId = 0; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext); pfree(tcontext); pfree(ncontext); }
Datum sepgsql_getcon(PG_FUNCTION_ARGS) { char *client_label; if (!sepgsql_is_enabled()) PG_RETURN_NULL(); client_label = sepgsql_get_client_label(); PG_RETURN_TEXT_P(cstring_to_text(client_label)); }
/* * sepgsql_relation_relabel * * It checks privileges to relabel the supplied relation by the `seclabel'. */ void sepgsql_relation_relabel(Oid relOid, const char *seclabel) { char *scontext = sepgsql_get_client_label(); char *tcontext; char *audit_name; char relkind; uint16_t tclass = 0; relkind = get_rel_relkind(relOid); if (relkind == RELKIND_RELATION) tclass = SEPG_CLASS_DB_TABLE; else if (relkind == RELKIND_SEQUENCE) tclass = SEPG_CLASS_DB_SEQUENCE; else if (relkind == RELKIND_VIEW) tclass = SEPG_CLASS_DB_VIEW; else ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot set security labels on relations except " "for tables, sequences or views"))); audit_name = getObjectDescriptionOids(RelationRelationId, relOid); /* * check db_xxx:{setattr relabelfrom} permission */ tcontext = sepgsql_get_label(RelationRelationId, relOid, 0); sepgsql_check_perms(scontext, tcontext, tclass, SEPG_DB_TABLE__SETATTR | SEPG_DB_TABLE__RELABELFROM, audit_name, true); /* * check db_xxx:{relabelto} permission */ sepgsql_check_perms(scontext, seclabel, tclass, SEPG_DB_TABLE__RELABELTO, audit_name, true); pfree(tcontext); pfree(audit_name); }
/* * sepgsql_proc_get_domtrans * * It computes security label of the client that shall be applied when * the current client invokes the supplied function. * This computed label is either same or different from the current one. * If security policy informed the function is a trusted-procedure, * we need to switch security label of the client during execution of * the function. * * Also note that the translated label shall be allocated using palloc(). * So, need to switch memory context, if you want to hold the string in * someone except for CurrentMemoryContext. */ char * sepgsql_proc_get_domtrans(Oid functionId) { char *scontext = sepgsql_get_client_label(); char *tcontext; char *ncontext; tcontext = sepgsql_get_label(ProcedureRelationId, functionId, 0); ncontext = sepgsql_compute_create(scontext, tcontext, SEPG_CLASS_PROCESS); pfree(tcontext); return ncontext; }
/* * sepgsql_set_client_label * * This routine tries to switch the current security label of the client, and * checks related permissions. The supplied new label shall be added to the * client_label_pending list, then saved at transaction-commit time to ensure * transaction-awareness. */ static void sepgsql_set_client_label(const char *new_label) { const char *tcontext; MemoryContext oldcxt; pending_label *plabel; /* Reset to the initial client label, if NULL */ if (!new_label) tcontext = client_label_peer; else { if (security_check_context_raw((security_context_t) new_label) < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("SELinux: invalid security label: \"%s\"", new_label))); tcontext = new_label; } /* Check process:{setcurrent} permission. */ sepgsql_avc_check_perms_label(sepgsql_get_client_label(), SEPG_CLASS_PROCESS, SEPG_PROCESS__SETCURRENT, NULL, true); /* Check process:{dyntransition} permission. */ sepgsql_avc_check_perms_label(tcontext, SEPG_CLASS_PROCESS, SEPG_PROCESS__DYNTRANSITION, NULL, true); /* * Append the supplied new_label on the pending list until the current * transaction is committed. */ oldcxt = MemoryContextSwitchTo(CurTransactionContext); plabel = palloc0(sizeof(pending_label)); plabel->subid = GetCurrentSubTransactionId(); if (new_label) plabel->label = pstrdup(new_label); client_label_pending = lappend(client_label_pending, plabel); MemoryContextSwitchTo(oldcxt); }
/* * sepgsql_attribute_relabel * * It checks privileges to relabel the supplied column * by the `seclabel'. */ void sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum, const char *seclabel) { char *scontext = sepgsql_get_client_label(); char *tcontext; char *audit_name; ObjectAddress object; if (get_rel_relkind(relOid) != RELKIND_RELATION) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot set security label on non-regular columns"))); object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = attnum; audit_name = getObjectDescription(&object); /* * check db_column:{setattr relabelfrom} permission */ tcontext = sepgsql_get_label(RelationRelationId, relOid, attnum); sepgsql_check_perms(scontext, tcontext, SEPG_CLASS_DB_COLUMN, SEPG_DB_COLUMN__SETATTR | SEPG_DB_COLUMN__RELABELFROM, audit_name, true); /* * check db_column:{relabelto} permission */ sepgsql_check_perms(scontext, seclabel, SEPG_CLASS_DB_COLUMN, SEPG_DB_PROCEDURE__RELABELTO, audit_name, true); pfree(tcontext); pfree(audit_name); }
/* * sepgsql_attribute_relabel * * It checks privileges to relabel the supplied column * by the `seclabel'. */ void sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum, const char *seclabel) { char *scontext = sepgsql_get_client_label(); char *tcontext; char audit_name[NAMEDATALEN * 2 + 10]; if (get_rel_relkind(relOid) != RELKIND_RELATION) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot set security label on non-regular columns"))); snprintf(audit_name, sizeof(audit_name), "%s.%s", get_rel_name(relOid), get_attname(relOid, attnum)); /* * check db_column:{setattr relabelfrom} permission */ tcontext = sepgsql_get_label(RelationRelationId, relOid, attnum); sepgsql_check_perms(scontext, tcontext, SEPG_CLASS_DB_COLUMN, SEPG_DB_COLUMN__SETATTR | SEPG_DB_COLUMN__RELABELFROM, audit_name, true); pfree(tcontext); /* * check db_column:{relabelto} permission */ sepgsql_check_perms(scontext, seclabel, SEPG_CLASS_DB_COLUMN, SEPG_DB_PROCEDURE__RELABELTO, audit_name, true); }
/* * sepgsql_attribute_post_create * * This routine assigns a default security label on a newly defined * column, using ALTER TABLE ... ADD COLUMN. * Note that this routine is not invoked in the case of CREATE TABLE, * although it also defines columns in addition to table. */ void sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum) { Relation rel; ScanKeyData skey[2]; SysScanDesc sscan; HeapTuple tuple; char *scontext; char *tcontext; char *ncontext; char audit_name[2 * NAMEDATALEN + 20]; ObjectAddress object; Form_pg_attribute attForm; /* * Only attributes within regular relation have individual security * labels. */ if (get_rel_relkind(relOid) != RELKIND_RELATION) return; /* * Compute a default security label of the new column underlying the * specified relation, and check permission to create it. */ rel = heap_open(AttributeRelationId, AccessShareLock); ScanKeyInit(&skey[0], Anum_pg_attribute_attrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relOid)); ScanKeyInit(&skey[1], Anum_pg_attribute_attnum, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(attnum)); sscan = systable_beginscan(rel, AttributeRelidNumIndexId, true, SnapshotSelf, 2, &skey[0]); tuple = systable_getnext(sscan); if (!HeapTupleIsValid(tuple)) elog(ERROR, "catalog lookup failed for column %d of relation %u", attnum, relOid); attForm = (Form_pg_attribute) GETSTRUCT(tuple); scontext = sepgsql_get_client_label(); tcontext = sepgsql_get_label(RelationRelationId, relOid, 0); ncontext = sepgsql_compute_create(scontext, tcontext, SEPG_CLASS_DB_COLUMN); /* * check db_column:{create} permission */ snprintf(audit_name, sizeof(audit_name), "table %s column %s", get_rel_name(relOid), NameStr(attForm->attname)); sepgsql_avc_check_perms_label(ncontext, SEPG_CLASS_DB_COLUMN, SEPG_DB_COLUMN__CREATE, audit_name, true); /* * Assign the default security label on a new procedure */ object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = attnum; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext); systable_endscan(sscan); heap_close(rel, AccessShareLock); pfree(tcontext); pfree(ncontext); }
/* * sepgsql_relation_post_create * * The post creation hook of relation/attribute */ void sepgsql_relation_post_create(Oid relOid) { Relation rel; ScanKeyData skey; SysScanDesc sscan; HeapTuple tuple; Form_pg_class classForm; ObjectAddress object; uint16 tclass; const char *tclass_text; char *scontext; /* subject */ char *tcontext; /* schema */ char *rcontext; /* relation */ char *ccontext; /* column */ char audit_name[2 * NAMEDATALEN + 20]; /* * Fetch catalog record of the new relation. Because pg_class entry is not * visible right now, we need to scan the catalog using SnapshotSelf. */ rel = heap_open(RelationRelationId, AccessShareLock); ScanKeyInit(&skey, ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relOid)); sscan = systable_beginscan(rel, ClassOidIndexId, true, SnapshotSelf, 1, &skey); tuple = systable_getnext(sscan); if (!HeapTupleIsValid(tuple)) elog(ERROR, "catalog lookup failed for relation %u", relOid); classForm = (Form_pg_class) GETSTRUCT(tuple); /* ignore indexes on toast tables */ if (classForm->relkind == RELKIND_INDEX && classForm->relnamespace == PG_TOAST_NAMESPACE) goto out; /* * check db_schema:{add_name} permission of the namespace */ object.classId = NamespaceRelationId; object.objectId = classForm->relnamespace; object.objectSubId = 0; sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_SCHEMA, SEPG_DB_SCHEMA__ADD_NAME, getObjectDescription(&object), true); switch (classForm->relkind) { case RELKIND_RELATION: tclass = SEPG_CLASS_DB_TABLE; tclass_text = "table"; break; case RELKIND_SEQUENCE: tclass = SEPG_CLASS_DB_SEQUENCE; tclass_text = "sequence"; break; case RELKIND_VIEW: tclass = SEPG_CLASS_DB_VIEW; tclass_text = "view"; break; case RELKIND_INDEX: /* deal with indexes specially; no need for tclass */ sepgsql_index_modify(relOid); goto out; default: /* ignore other relkinds */ goto out; } /* * Compute a default security label when we create a new relation object * under the specified namespace. */ scontext = sepgsql_get_client_label(); tcontext = sepgsql_get_label(NamespaceRelationId, classForm->relnamespace, 0); rcontext = sepgsql_compute_create(scontext, tcontext, tclass); /* * check db_xxx:{create} permission */ snprintf(audit_name, sizeof(audit_name), "%s %s", tclass_text, NameStr(classForm->relname)); sepgsql_avc_check_perms_label(rcontext, tclass, SEPG_DB_DATABASE__CREATE, audit_name, true); /* * Assign the default security label on the new relation */ object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = 0; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, rcontext); /* * We also assigns a default security label on columns of the new regular * tables. */ if (classForm->relkind == RELKIND_RELATION) { Relation arel; ScanKeyData akey; SysScanDesc ascan; HeapTuple atup; Form_pg_attribute attForm; arel = heap_open(AttributeRelationId, AccessShareLock); ScanKeyInit(&akey, Anum_pg_attribute_attrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relOid)); ascan = systable_beginscan(arel, AttributeRelidNumIndexId, true, SnapshotSelf, 1, &akey); while (HeapTupleIsValid(atup = systable_getnext(ascan))) { attForm = (Form_pg_attribute) GETSTRUCT(atup); snprintf(audit_name, sizeof(audit_name), "%s %s column %s", tclass_text, NameStr(classForm->relname), NameStr(attForm->attname)); ccontext = sepgsql_compute_create(scontext, rcontext, SEPG_CLASS_DB_COLUMN); /* * check db_column:{create} permission */ sepgsql_avc_check_perms_label(ccontext, SEPG_CLASS_DB_COLUMN, SEPG_DB_COLUMN__CREATE, audit_name, true); object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = attForm->attnum; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ccontext); pfree(ccontext); } systable_endscan(ascan); heap_close(arel, AccessShareLock); } pfree(rcontext); out: systable_endscan(sscan); heap_close(rel, AccessShareLock); }
/* * sepgsql_database_post_create * * This routine assigns a default security label on a newly defined * database, and check permission needed for its creation. */ void sepgsql_database_post_create(Oid databaseId, const char *dtemplate) { Relation rel; ScanKeyData skey; SysScanDesc sscan; HeapTuple tuple; char *tcontext; char *ncontext; char audit_name[NAMEDATALEN + 20]; ObjectAddress object; Form_pg_database datForm; /* * Oid of the source database is not saved in pg_database catalog, so we * collect its identifier using contextual information. If NULL, its * default is "template1" according to createdb(). */ if (!dtemplate) dtemplate = "template1"; object.classId = DatabaseRelationId; object.objectId = get_database_oid(dtemplate, false); object.objectSubId = 0; tcontext = sepgsql_get_label(object.classId, object.objectId, object.objectSubId); /* * check db_database:{getattr} permission */ snprintf(audit_name, sizeof(audit_name), "database %s", dtemplate); sepgsql_avc_check_perms_label(tcontext, SEPG_CLASS_DB_DATABASE, SEPG_DB_DATABASE__GETATTR, audit_name, true); /* * Compute a default security label of the newly created database based on * a pair of security label of client and source database. * * XXX - uncoming version of libselinux supports to take object name to * handle special treatment on default security label. */ rel = heap_open(DatabaseRelationId, AccessShareLock); ScanKeyInit(&skey, ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(databaseId)); sscan = systable_beginscan(rel, DatabaseOidIndexId, true, SnapshotSelf, 1, &skey); tuple = systable_getnext(sscan); if (!HeapTupleIsValid(tuple)) elog(ERROR, "catalog lookup failed for database %u", databaseId); datForm = (Form_pg_database) GETSTRUCT(tuple); ncontext = sepgsql_compute_create(sepgsql_get_client_label(), tcontext, SEPG_CLASS_DB_DATABASE); /* * check db_database:{create} permission */ snprintf(audit_name, sizeof(audit_name), "database %s", NameStr(datForm->datname)); sepgsql_avc_check_perms_label(ncontext, SEPG_CLASS_DB_DATABASE, SEPG_DB_DATABASE__CREATE, audit_name, true); systable_endscan(sscan); heap_close(rel, AccessShareLock); /* * Assign the default security label on the new database */ object.classId = DatabaseRelationId; object.objectId = databaseId; object.objectSubId = 0; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext); pfree(ncontext); pfree(tcontext); }
/* * sepgsql_schema_post_create * * This routine assigns a default security label on a newly defined * schema. */ void sepgsql_schema_post_create(Oid namespaceId) { Relation rel; ScanKeyData skey; SysScanDesc sscan; HeapTuple tuple; char *tcontext; char *ncontext; const char *nsp_name; ObjectAddress object; Form_pg_namespace nspForm; StringInfoData audit_name; /* * Compute a default security label when we create a new schema object * under the working database. * * XXX - uncoming version of libselinux supports to take object name to * handle special treatment on default security label; such as special * label on "pg_temp" schema. */ rel = heap_open(NamespaceRelationId, AccessShareLock); ScanKeyInit(&skey, ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(namespaceId)); sscan = systable_beginscan(rel, NamespaceOidIndexId, true, SnapshotSelf, 1, &skey); tuple = systable_getnext(sscan); if (!HeapTupleIsValid(tuple)) elog(ERROR, "catalog lookup failed for namespace %u", namespaceId); nspForm = (Form_pg_namespace) GETSTRUCT(tuple); nsp_name = NameStr(nspForm->nspname); if (strncmp(nsp_name, "pg_temp_", 8) == 0) nsp_name = "pg_temp"; else if (strncmp(nsp_name, "pg_toast_temp_", 14) == 0) nsp_name = "pg_toast_temp"; tcontext = sepgsql_get_label(DatabaseRelationId, MyDatabaseId, 0); ncontext = sepgsql_compute_create(sepgsql_get_client_label(), tcontext, SEPG_CLASS_DB_SCHEMA, nsp_name); /* * check db_schema:{create} */ initStringInfo(&audit_name); appendStringInfo(&audit_name, "%s", quote_identifier(nsp_name)); sepgsql_avc_check_perms_label(ncontext, SEPG_CLASS_DB_SCHEMA, SEPG_DB_SCHEMA__CREATE, audit_name.data, true); systable_endscan(sscan); heap_close(rel, AccessShareLock); /* * Assign the default security label on a new procedure */ object.classId = NamespaceRelationId; object.objectId = namespaceId; object.objectSubId = 0; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext); pfree(ncontext); pfree(tcontext); }
/* * sepgsql_proc_post_create * * This routine assigns a default security label on a newly defined * procedure. */ void sepgsql_proc_post_create(Oid functionId) { Relation rel; ScanKeyData skey; SysScanDesc sscan; HeapTuple tuple; char *nsp_name; char *scontext; char *tcontext; char *ncontext; uint32 required; int i; StringInfoData audit_name; ObjectAddress object; Form_pg_proc proForm; /* * Fetch namespace of the new procedure. Because pg_proc entry is not * visible right now, we need to scan the catalog using SnapshotSelf. */ rel = heap_open(ProcedureRelationId, AccessShareLock); ScanKeyInit(&skey, ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(functionId)); sscan = systable_beginscan(rel, ProcedureOidIndexId, true, SnapshotSelf, 1, &skey); tuple = systable_getnext(sscan); if (!HeapTupleIsValid(tuple)) elog(ERROR, "catalog lookup failed for proc %u", functionId); proForm = (Form_pg_proc) GETSTRUCT(tuple); /* * check db_schema:{add_name} permission of the namespace */ object.classId = NamespaceRelationId; object.objectId = proForm->pronamespace; object.objectSubId = 0; sepgsql_avc_check_perms(&object, SEPG_CLASS_DB_SCHEMA, SEPG_DB_SCHEMA__ADD_NAME, getObjectIdentity(&object), true); /* * XXX - db_language:{implement} also should be checked here */ /* * Compute a default security label when we create a new procedure object * under the specified namespace. */ scontext = sepgsql_get_client_label(); tcontext = sepgsql_get_label(NamespaceRelationId, proForm->pronamespace, 0); ncontext = sepgsql_compute_create(scontext, tcontext, SEPG_CLASS_DB_PROCEDURE, NameStr(proForm->proname)); /* * check db_procedure:{create (install)} permission */ initStringInfo(&audit_name); nsp_name = get_namespace_name(proForm->pronamespace); appendStringInfo(&audit_name, "%s(", quote_qualified_identifier(nsp_name, NameStr(proForm->proname))); for (i = 0; i < proForm->pronargs; i++) { if (i > 0) appendStringInfoChar(&audit_name, ','); object.classId = TypeRelationId; object.objectId = proForm->proargtypes.values[i]; object.objectSubId = 0; appendStringInfoString(&audit_name, getObjectIdentity(&object)); } appendStringInfoChar(&audit_name, ')'); required = SEPG_DB_PROCEDURE__CREATE; if (proForm->proleakproof) required |= SEPG_DB_PROCEDURE__INSTALL; sepgsql_avc_check_perms_label(ncontext, SEPG_CLASS_DB_PROCEDURE, required, audit_name.data, true); /* * Assign the default security label on a new procedure */ object.classId = ProcedureRelationId; object.objectId = functionId; object.objectSubId = 0; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext); /* * Cleanup */ systable_endscan(sscan); heap_close(rel, AccessShareLock); pfree(audit_name.data); pfree(tcontext); pfree(ncontext); }
/* * sepgsql_relation_post_create * * The post creation hook of relation/attribute */ void sepgsql_relation_post_create(Oid relOid) { Relation rel; ScanKeyData skey; SysScanDesc sscan; HeapTuple tuple; Form_pg_class classForm; ObjectAddress object; uint16 tclass; char *scontext; /* subject */ char *tcontext; /* schema */ char *rcontext; /* relation */ char *ccontext; /* column */ /* * Fetch catalog record of the new relation. Because pg_class entry is not * visible right now, we need to scan the catalog using SnapshotSelf. */ rel = heap_open(RelationRelationId, AccessShareLock); ScanKeyInit(&skey, ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relOid)); sscan = systable_beginscan(rel, ClassOidIndexId, true, SnapshotSelf, 1, &skey); tuple = systable_getnext(sscan); if (!HeapTupleIsValid(tuple)) elog(ERROR, "catalog lookup failed for relation %u", relOid); classForm = (Form_pg_class) GETSTRUCT(tuple); if (classForm->relkind == RELKIND_RELATION) tclass = SEPG_CLASS_DB_TABLE; else if (classForm->relkind == RELKIND_SEQUENCE) tclass = SEPG_CLASS_DB_SEQUENCE; else if (classForm->relkind == RELKIND_VIEW) tclass = SEPG_CLASS_DB_VIEW; else goto out; /* No need to assign individual labels */ /* * Compute a default security label when we create a new relation object * under the specified namespace. */ scontext = sepgsql_get_client_label(); tcontext = sepgsql_get_label(NamespaceRelationId, classForm->relnamespace, 0); rcontext = sepgsql_compute_create(scontext, tcontext, tclass); /* * Assign the default security label on the new relation */ object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = 0; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, rcontext); /* * We also assigns a default security label on columns of the new regular * tables. */ if (classForm->relkind == RELKIND_RELATION) { AttrNumber index; ccontext = sepgsql_compute_create(scontext, rcontext, SEPG_CLASS_DB_COLUMN); for (index = FirstLowInvalidHeapAttributeNumber + 1; index <= classForm->relnatts; index++) { if (index == InvalidAttrNumber) continue; if (index == ObjectIdAttributeNumber && !classForm->relhasoids) continue; object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = index; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ccontext); } pfree(ccontext); } pfree(rcontext); out: systable_endscan(sscan); heap_close(rel, AccessShareLock); }
/* * sepgsql_attribute_post_create * * This routine assigns a default security label on a newly defined * column, using ALTER TABLE ... ADD COLUMN. * Note that this routine is not invoked in the case of CREATE TABLE, * although it also defines columns in addition to table. */ void sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum) { Relation rel; ScanKeyData skey[2]; SysScanDesc sscan; HeapTuple tuple; char *scontext; char *tcontext; char *ncontext; ObjectAddress object; Form_pg_attribute attForm; StringInfoData audit_name; char relkind = get_rel_relkind(relOid); /* * Only attributes within regular relations or partition relations have * individual security labels. */ if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE) return; /* * Compute a default security label of the new column underlying the * specified relation, and check permission to create it. */ rel = heap_open(AttributeRelationId, AccessShareLock); ScanKeyInit(&skey[0], Anum_pg_attribute_attrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relOid)); ScanKeyInit(&skey[1], Anum_pg_attribute_attnum, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(attnum)); sscan = systable_beginscan(rel, AttributeRelidNumIndexId, true, SnapshotSelf, 2, &skey[0]); tuple = systable_getnext(sscan); if (!HeapTupleIsValid(tuple)) elog(ERROR, "could not find tuple for column %d of relation %u", attnum, relOid); attForm = (Form_pg_attribute) GETSTRUCT(tuple); scontext = sepgsql_get_client_label(); tcontext = sepgsql_get_label(RelationRelationId, relOid, 0); ncontext = sepgsql_compute_create(scontext, tcontext, SEPG_CLASS_DB_COLUMN, NameStr(attForm->attname)); /* * check db_column:{create} permission */ object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = 0; initStringInfo(&audit_name); appendStringInfo(&audit_name, "%s.%s", getObjectIdentity(&object), quote_identifier(NameStr(attForm->attname))); sepgsql_avc_check_perms_label(ncontext, SEPG_CLASS_DB_COLUMN, SEPG_DB_COLUMN__CREATE, audit_name.data, true); /* * Assign the default security label on a new procedure */ object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = attnum; SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext); systable_endscan(sscan); heap_close(rel, AccessShareLock); pfree(tcontext); pfree(ncontext); }