00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "postgres.h"
00012
00013 #include "access/htup_details.h"
00014 #include "access/sysattr.h"
00015 #include "access/tupdesc.h"
00016 #include "catalog/catalog.h"
00017 #include "catalog/heap.h"
00018 #include "catalog/dependency.h"
00019 #include "catalog/pg_attribute.h"
00020 #include "catalog/pg_class.h"
00021 #include "catalog/pg_inherits_fn.h"
00022 #include "commands/seclabel.h"
00023 #include "commands/tablecmds.h"
00024 #include "executor/executor.h"
00025 #include "nodes/bitmapset.h"
00026 #include "utils/lsyscache.h"
00027 #include "utils/syscache.h"
00028
00029 #include "sepgsql.h"
00030
00031
00032
00033
00034
00035
00036
00037
00038 static Bitmapset *
00039 fixup_whole_row_references(Oid relOid, Bitmapset *columns)
00040 {
00041 Bitmapset *result;
00042 HeapTuple tuple;
00043 AttrNumber natts;
00044 AttrNumber attno;
00045 int index;
00046
00047
00048 index = InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber;
00049 if (!bms_is_member(index, columns))
00050 return columns;
00051
00052
00053 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
00054 if (!HeapTupleIsValid(tuple))
00055 elog(ERROR, "cache lookup failed for relation %u", relOid);
00056 natts = ((Form_pg_class) GETSTRUCT(tuple))->relnatts;
00057 ReleaseSysCache(tuple);
00058
00059
00060 result = bms_copy(columns);
00061 result = bms_del_member(result, index);
00062
00063 for (attno = 1; attno <= natts; attno++)
00064 {
00065 tuple = SearchSysCache2(ATTNUM,
00066 ObjectIdGetDatum(relOid),
00067 Int16GetDatum(attno));
00068 if (!HeapTupleIsValid(tuple))
00069 continue;
00070
00071 if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped)
00072 continue;
00073
00074 index = attno - FirstLowInvalidHeapAttributeNumber;
00075
00076 result = bms_add_member(result, index);
00077
00078 ReleaseSysCache(tuple);
00079 }
00080 return result;
00081 }
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093 static Bitmapset *
00094 fixup_inherited_columns(Oid parentId, Oid childId, Bitmapset *columns)
00095 {
00096 AttrNumber attno;
00097 Bitmapset *tmpset;
00098 Bitmapset *result = NULL;
00099 char *attname;
00100 int index;
00101
00102
00103
00104
00105 if (parentId == childId)
00106 return columns;
00107
00108 tmpset = bms_copy(columns);
00109 while ((index = bms_first_member(tmpset)) > 0)
00110 {
00111 attno = index + FirstLowInvalidHeapAttributeNumber;
00112
00113
00114
00115
00116 if (attno == InvalidAttrNumber)
00117 {
00118 result = bms_add_member(result, index);
00119 continue;
00120 }
00121
00122 attname = get_attname(parentId, attno);
00123 if (!attname)
00124 elog(ERROR, "cache lookup failed for attribute %d of relation %u",
00125 attno, parentId);
00126 attno = get_attnum(childId, attname);
00127 if (attno == InvalidAttrNumber)
00128 elog(ERROR, "cache lookup failed for attribute %s of relation %u",
00129 attname, childId);
00130
00131 index = attno - FirstLowInvalidHeapAttributeNumber;
00132 result = bms_add_member(result, index);
00133
00134 pfree(attname);
00135 }
00136 bms_free(tmpset);
00137
00138 return result;
00139 }
00140
00141
00142
00143
00144
00145
00146
00147 static bool
00148 check_relation_privileges(Oid relOid,
00149 Bitmapset *selected,
00150 Bitmapset *modified,
00151 uint32 required,
00152 bool abort_on_violation)
00153 {
00154 ObjectAddress object;
00155 char *audit_name;
00156 Bitmapset *columns;
00157 int index;
00158 char relkind = get_rel_relkind(relOid);
00159 bool result = true;
00160
00161
00162
00163
00164
00165
00166 if (sepgsql_getenforce() > 0)
00167 {
00168 Oid relnamespace = get_rel_namespace(relOid);
00169
00170 if (IsSystemNamespace(relnamespace) &&
00171 (required & (SEPG_DB_TABLE__UPDATE |
00172 SEPG_DB_TABLE__INSERT |
00173 SEPG_DB_TABLE__DELETE)) != 0)
00174 ereport(ERROR,
00175 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00176 errmsg("SELinux: hardwired security policy violation")));
00177
00178 if (relkind == RELKIND_TOASTVALUE)
00179 ereport(ERROR,
00180 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00181 errmsg("SELinux: hardwired security policy violation")));
00182 }
00183
00184
00185
00186
00187 object.classId = RelationRelationId;
00188 object.objectId = relOid;
00189 object.objectSubId = 0;
00190 audit_name = getObjectIdentity(&object);
00191 switch (relkind)
00192 {
00193 case RELKIND_RELATION:
00194 result = sepgsql_avc_check_perms(&object,
00195 SEPG_CLASS_DB_TABLE,
00196 required,
00197 audit_name,
00198 abort_on_violation);
00199 break;
00200
00201 case RELKIND_SEQUENCE:
00202 Assert((required & ~SEPG_DB_TABLE__SELECT) == 0);
00203
00204 if (required & SEPG_DB_TABLE__SELECT)
00205 result = sepgsql_avc_check_perms(&object,
00206 SEPG_CLASS_DB_SEQUENCE,
00207 SEPG_DB_SEQUENCE__GET_VALUE,
00208 audit_name,
00209 abort_on_violation);
00210 break;
00211
00212 case RELKIND_VIEW:
00213 result = sepgsql_avc_check_perms(&object,
00214 SEPG_CLASS_DB_VIEW,
00215 SEPG_DB_VIEW__EXPAND,
00216 audit_name,
00217 abort_on_violation);
00218 break;
00219
00220 default:
00221
00222 break;
00223 }
00224 pfree(audit_name);
00225
00226
00227
00228
00229 if (relkind != RELKIND_RELATION)
00230 return true;
00231
00232
00233
00234
00235 selected = fixup_whole_row_references(relOid, selected);
00236 modified = fixup_whole_row_references(relOid, modified);
00237 columns = bms_union(selected, modified);
00238
00239 while ((index = bms_first_member(columns)) >= 0)
00240 {
00241 AttrNumber attnum;
00242 uint32 column_perms = 0;
00243
00244 if (bms_is_member(index, selected))
00245 column_perms |= SEPG_DB_COLUMN__SELECT;
00246 if (bms_is_member(index, modified))
00247 {
00248 if (required & SEPG_DB_TABLE__UPDATE)
00249 column_perms |= SEPG_DB_COLUMN__UPDATE;
00250 if (required & SEPG_DB_TABLE__INSERT)
00251 column_perms |= SEPG_DB_COLUMN__INSERT;
00252 }
00253 if (column_perms == 0)
00254 continue;
00255
00256
00257 attnum = index + FirstLowInvalidHeapAttributeNumber;
00258
00259 object.classId = RelationRelationId;
00260 object.objectId = relOid;
00261 object.objectSubId = attnum;
00262 audit_name = getObjectDescription(&object);
00263
00264 result = sepgsql_avc_check_perms(&object,
00265 SEPG_CLASS_DB_COLUMN,
00266 column_perms,
00267 audit_name,
00268 abort_on_violation);
00269 pfree(audit_name);
00270
00271 if (!result)
00272 return result;
00273 }
00274 return true;
00275 }
00276
00277
00278
00279
00280
00281
00282 bool
00283 sepgsql_dml_privileges(List *rangeTabls, bool abort_on_violation)
00284 {
00285 ListCell *lr;
00286
00287 foreach(lr, rangeTabls)
00288 {
00289 RangeTblEntry *rte = lfirst(lr);
00290 uint32 required = 0;
00291 List *tableIds;
00292 ListCell *li;
00293
00294
00295
00296
00297 if (rte->rtekind != RTE_RELATION)
00298 continue;
00299
00300
00301
00302
00303 if (rte->requiredPerms & ACL_SELECT)
00304 required |= SEPG_DB_TABLE__SELECT;
00305 if (rte->requiredPerms & ACL_INSERT)
00306 required |= SEPG_DB_TABLE__INSERT;
00307 if (rte->requiredPerms & ACL_UPDATE)
00308 {
00309 if (!bms_is_empty(rte->modifiedCols))
00310 required |= SEPG_DB_TABLE__UPDATE;
00311 else
00312 required |= SEPG_DB_TABLE__LOCK;
00313 }
00314 if (rte->requiredPerms & ACL_DELETE)
00315 required |= SEPG_DB_TABLE__DELETE;
00316
00317
00318
00319
00320 if (required == 0)
00321 continue;
00322
00323
00324
00325
00326
00327
00328
00329 if (!rte->inh)
00330 tableIds = list_make1_oid(rte->relid);
00331 else
00332 tableIds = find_all_inheritors(rte->relid, NoLock, NULL);
00333
00334 foreach(li, tableIds)
00335 {
00336 Oid tableOid = lfirst_oid(li);
00337 Bitmapset *selectedCols;
00338 Bitmapset *modifiedCols;
00339
00340
00341
00342
00343
00344 selectedCols = fixup_inherited_columns(rte->relid, tableOid,
00345 rte->selectedCols);
00346 modifiedCols = fixup_inherited_columns(rte->relid, tableOid,
00347 rte->modifiedCols);
00348
00349
00350
00351
00352 if (!check_relation_privileges(tableOid,
00353 selectedCols,
00354 modifiedCols,
00355 required, abort_on_violation))
00356 return false;
00357 }
00358 list_free(tableIds);
00359 }
00360 return true;
00361 }