Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit6550b90

Browse files
committed
Code review for row security.
Buildfarm member tick identified an issue where the policies in therelcache for a relation were were being replaced underneath a runningquery, leading to segfaults while processing the policies to be addedto a query. Similar to how TupleDesc RuleLocks are handled, add in aequalRSDesc() function to check if the policies have actually changedand, if not, swap back the rsdesc field (using the original instead ofthe temporairly built one; the whole structure is swapped and thenspecific fields swapped back). This now passes a CLOBBER_CACHE_ALWAYSfor me and should resolve the buildfarm error.In addition to addressing this, add a new chapter in Data Definitionunder Privileges which explains row security and provides examples ofits usage, change \d to always list policies (even if row security isdisabled- but note that it is disabled, or enabled with no policies),rework check_role_for_policy (it really didn't need the entire policy,but it did need to be using has_privs_of_role()), and change the fieldin pg_class to relrowsecurity from relhasrowsecurity, based onHeikki's suggestion. Also from Heikki, only issue SET ROW_SECURITY inpg_restore when talking to a 9.5+ server, list Bypass RLS in \du, anddocument --enable-row-security options for pg_dump and pg_restore.Lastly, fix a number of minor whitespace and typo issues from Heikki,Dimitri, add a missing #include, per Peter E, fix a few minorvariable-assigned-but-not-used and resource leak issues from Coverityand add tab completion for role attribute bypassrls as well.
1 parent3f6f926 commit6550b90

File tree

24 files changed

+439
-122
lines changed

24 files changed

+439
-122
lines changed

‎doc/src/sgml/catalogs.sgml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1941,8 +1941,9 @@
19411941
</row>
19421942

19431943
<row>
1944-
<entry><structfield>relhasrowsecurity</structfield></entry>
1944+
<entry><structfield>relrowsecurity</structfield></entry>
19451945
<entry><type>bool</type></entry>
1946+
<entry></entry>
19461947
<entry>
19471948
True if table has row-security enabled; see
19481949
<link linkend="catalog-pg-rowsecurity"><structname>pg_rowsecurity</structname></link> catalog
@@ -5415,7 +5416,7 @@
54155416

54165417
<note>
54175418
<para>
5418-
<literal>pg_class.relhasrowsecurity</literal>
5419+
<literal>pg_class.relrowsecurity</literal>
54195420
True if the table has row-security enabled.
54205421
Must be true if the table has a row-security policy in this catalog.
54215422
</para>
@@ -9228,10 +9229,10 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
92289229
<entry>True if table has (or once had) triggers</entry>
92299230
</row>
92309231
<row>
9231-
<entry><structfield>hasrowsecurity</structfield></entry>
9232+
<entry><structfield>rowsecurity</structfield></entry>
92329233
<entry><type>boolean</type></entry>
9233-
<entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.relhasrowsecurity</literal></entry>
9234-
<entry>True iftable hasrow security enabled</entry>
9234+
<entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.relrowsecurity</literal></entry>
9235+
<entry>True if row securityisenabled on the table</entry>
92359236
</row>
92369237
</tbody>
92379238
</tgroup>

‎doc/src/sgml/config.sgml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5457,9 +5457,9 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
54575457

54585458
<para>
54595459
The allowed values of <varname>row_security</> are
5460-
<literal>on</> (apply normally- not to superuser or table owner),
5460+
<literal>on</> (apply normally- not to superuser or table owner),
54615461
<literal>off</> (fail if row security would be applied), and
5462-
<literal>force</> (apply always- even to superuser and table owner).
5462+
<literal>force</> (apply always- even to superuser and table owner).
54635463
</para>
54645464

54655465
<para>

‎doc/src/sgml/ddl.sgml

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,6 +1508,174 @@ REVOKE ALL ON accounts FROM PUBLIC;
15081508
</para>
15091509
</sect1>
15101510

1511+
<sect1 id="ddl-rowsecurity">
1512+
<title>Row Security Policies</title>
1513+
1514+
<indexterm zone="ddl-rowsecurity">
1515+
<primary>rowsecurity</primary>
1516+
</indexterm>
1517+
1518+
<indexterm zone="ddl-rowsecurity">
1519+
<primary>rls</primary>
1520+
</indexterm>
1521+
1522+
<indexterm>
1523+
<primary>policies</primary>
1524+
<see>policy</see>
1525+
</indexterm>
1526+
1527+
<indexterm zone="ddl-rowsecurity">
1528+
<primary>POLICY</primary>
1529+
</indexterm>
1530+
1531+
<para>
1532+
In addition to the <xref linkend="ddl-priv"> system available through
1533+
<xref linkend="sql-grant">, tables can have row security policies
1534+
which limit the rows returned for normal queries and rows which can
1535+
be added through data modification commands. By default, tables do
1536+
not have any policies and all rows are visible and able to be added,
1537+
subject to the regular <xref linkend="ddl-priv"> system. This is
1538+
also known to as Row Level Security.
1539+
</para>
1540+
1541+
<para>
1542+
When row security is enabled on a table with
1543+
<xref linkend="sql-altertable">, all normal access to the table
1544+
(excluding the owner) for selecting rows or adding rows must be through
1545+
a policy. If no policy exists for the table, a default-deny policy is
1546+
used and no rows are visible or can be added. Privileges which operate
1547+
at the whole table level such as <literal>TRUNCATE</>, and
1548+
<literal>REFERENCES</> are not subject to row security.
1549+
</para>
1550+
1551+
<para>
1552+
Row security policies can be specific to commands, or to roles, or to
1553+
both. The commands available are <literal>SELECT</>, <literal>INSERT</>,
1554+
<literal>UPDATE</>, and <literal>DELETE</>. Multiple roles can be
1555+
assigned to a given policy and normal role membership and inheiritance
1556+
rules apply.
1557+
</para>
1558+
1559+
<para>
1560+
To specify which rows are visible and what rows can be added to the
1561+
table with row security, an expression is required which returns a
1562+
boolean result. This expression will be evaluated for each row prior
1563+
to other conditionals or functions which are part of the query. The
1564+
one exception to this rule are <literal>leakproof</literal> functions,
1565+
which are guaranteed to not leak information. Two expressions may be
1566+
specified to provide independent control over the rows which are
1567+
visible and the rows which are allowed to be added. The expression
1568+
is run as part of the query and with the privileges of the user
1569+
running the query, however, security definer functions can be used in
1570+
the expression.
1571+
</para>
1572+
1573+
<para>
1574+
Enabling and disabling row security, as well as adding policies to a
1575+
table, is always the privilege of the owner only.
1576+
</para>
1577+
1578+
<para>
1579+
Policies are created using the <xref linkend="sql-createpolicy">
1580+
command, altered using the <xref linkend="sql-alterpolicy"> command,
1581+
and dropped using the <xref linkend="sql-droppolicy"> command. To
1582+
enable and disable row security for a given table, use the
1583+
<xref linkend="sql-altertable"> command.
1584+
</para>
1585+
1586+
<para>
1587+
The table owners and superusers bypass the row security system when
1588+
querying a table, by default. Row security can be enabled for
1589+
superusers and table owners by setting
1590+
<xref linkend="guc-row-security"> to <literal>force</literal>. Any
1591+
user can request that row security be bypassed by setting
1592+
<xref linkend="guc-row-security"> to <literal>off</literal>. If
1593+
the user does not have privileges to bypass row security when
1594+
querying a given table then an error will be returned instead. Other
1595+
users can be granted the ability to bypass the row security system
1596+
with the <literal>BYPASSRLS</literal> role attribute. This
1597+
attribute can only be set by a superuser.
1598+
</para>
1599+
1600+
<para>
1601+
Each policy has a name and multiple policies can be defined for a
1602+
table. As policies are table-specific, each policy for a table must
1603+
have a unique name. Different tables may have policies with the
1604+
same name.
1605+
</para>
1606+
1607+
<para>
1608+
When multiple policies apply to a given query, they are combined using
1609+
<literal>OR</literal>, similar to how a given role has the privileges
1610+
of all roles which they are a member of.
1611+
</para>
1612+
1613+
<para>
1614+
Referential integrity checks, such as unique or primary key constraints
1615+
and foreign key references, will bypass row security to ensure that
1616+
data integrity is maintained. Care must be taken when developing
1617+
schemas and row level policies to avoid a "covert channel" leak of
1618+
information through these referntial integrity checks.
1619+
</para>
1620+
1621+
<para>
1622+
To enable row security for a table,
1623+
the <command>ALTER TABLE</command> is used. For example, to enable
1624+
row level security for the table accounts, use:
1625+
</para>
1626+
1627+
<programlisting>
1628+
-- Create the table first
1629+
CREATE TABLE accounts (manager text, company text, contact_email text);
1630+
ALTER TABLE accounts ENABLE ROW LEVEL SECURITY;
1631+
</programlisting>
1632+
1633+
<para>
1634+
To create a policy on the account relation to allow the managers role
1635+
to view the rows of their accounts, the <command>CREATE POLICY</command>
1636+
command can be used:
1637+
</para>
1638+
1639+
<programlisting>
1640+
CREATE POLICY account_managers ON accounts TO managers
1641+
USING (manager = current_user);
1642+
</programlisting>
1643+
1644+
<para>
1645+
If no role is specified, or the special <quote>user</quote> name
1646+
<literal>PUBLIC</literal> is used, then the policy applies to all
1647+
users on the system. To allow all users to view their own row in
1648+
a user table, a simple policy can be used:
1649+
</para>
1650+
1651+
<programlisting>
1652+
CREATE POLICY user_policy ON users
1653+
USING (user = current_user);
1654+
</programlisting>
1655+
1656+
<para>
1657+
To use a different policy for rows which are being added to the
1658+
table from those rows which are visible, the WITH CHECK clause
1659+
can be used. This would allow all users to view all rows in the
1660+
users table, but only modify their own:
1661+
</para>
1662+
1663+
<programlisting>
1664+
CREATE POLICY user_policy ON users
1665+
USING (true)
1666+
WITH CHECK (user = current_user);
1667+
</programlisting>
1668+
1669+
<para>
1670+
Row security can be disabled with the <command>ALTER TABLE</command>
1671+
also. Note that disabling row security does not remove the
1672+
policies which are defined on the table, they are simply ignored
1673+
and all rows are visible and able to be added, subject to the
1674+
normal privileges system.
1675+
</para>
1676+
1677+
</sect1>
1678+
15111679
<sect1 id="ddl-schemas">
15121680
<title>Schemas</title>
15131681

‎doc/src/sgml/ref/alter_table.sgml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ ALTER TABLE ALL IN TABLESPACE <replaceable class="PARAMETER">name</replaceable>
429429
These forms control the application of row security policies belonging
430430
to the table. If enabled and no policies exist for the table, then a
431431
default-deny policy is applied. Note that policies can exist for a table
432-
even if row level security is disabled- in this case, the policies will
432+
even if row level security is disabled- in this case, the policies will
433433
NOT be applied and the policies will be ignored.
434434
See also
435435
<xref linkend="SQL-CREATEPOLICY">.

‎doc/src/sgml/ref/create_policy.sgml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
240240
</varlistentry>
241241

242242
<varlistentry id="SQL-CREATEPOLICY-UPDATE">
243-
<term><literal>DELETE</></term>
243+
<term><literal>UPDATE</></term>
244244
<listitem>
245245
<para>
246246
Using <literal>UPDATE</literal> for a policy means that it will apply

‎doc/src/sgml/ref/pg_dump.sgml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,23 @@ PostgreSQL documentation
687687
</listitem>
688688
</varlistentry>
689689

690+
<varlistentry>
691+
<term><option>--enable-row-security</></term>
692+
<listitem>
693+
<para>
694+
This option is relevant only when dumping the contents of a table
695+
which has row security. By default, pg_dump will set
696+
<literal>ROW_SECURITY</literal> to <literal>OFF</literal>, to ensure
697+
that all data is dumped from the table. If the user does not have
698+
sufficient privileges to bypass row security, then an error is thrown.
699+
This parameter instructs <application>pg_dump</application> to set
700+
row_security to 'ON' instead, allowing the user to dump the contents
701+
of the table which they have access to.
702+
</para>
703+
704+
</listitem>
705+
</varlistentry>
706+
690707
<varlistentry>
691708
<term><option>--exclude-table-data=<replaceable class="parameter">table</replaceable></option></term>
692709
<listitem>

‎doc/src/sgml/ref/pg_restore.sgml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,29 @@
490490
</listitem>
491491
</varlistentry>
492492

493+
<varlistentry>
494+
<term><option>--enable-row-security</></term> <listitem>
495+
<para>
496+
This option is relevant only when restoring the contents of a table
497+
which has row security. By default, pg_restore will set
498+
<literal>ROW_SECURITY</literal> to <literal>OFF</literal>, to ensure
499+
that all data is restored in to the table. If the user does not have
500+
sufficient privileges to bypass row security, then an error is thrown.
501+
This parameter instructs <application>pg_restore</application> to set
502+
row_security to 'ON' instead, allowing the user to attempt to restore
503+
the contents of the table with row security enabled. This may still
504+
fail if the user does not have the right to insert the rows from the
505+
dump into the table.
506+
</para>
507+
508+
<para>
509+
Note that this option currently also requires the dump be in INSERT
510+
format as COPY TO does not support row security.
511+
</para>
512+
513+
</listitem>
514+
</varlistentry>
515+
493516
<varlistentry>
494517
<term><option>--if-exists</option></term>
495518
<listitem>

‎src/backend/catalog/heap.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ InsertPgClassTuple(Relation pg_class_desc,
799799
values[Anum_pg_class_relhaspkey-1]=BoolGetDatum(rd_rel->relhaspkey);
800800
values[Anum_pg_class_relhasrules-1]=BoolGetDatum(rd_rel->relhasrules);
801801
values[Anum_pg_class_relhastriggers-1]=BoolGetDatum(rd_rel->relhastriggers);
802-
values[Anum_pg_class_relhasrowsecurity-1]=BoolGetDatum(rd_rel->relhasrowsecurity);
802+
values[Anum_pg_class_relrowsecurity-1]=BoolGetDatum(rd_rel->relrowsecurity);
803803
values[Anum_pg_class_relhassubclass-1]=BoolGetDatum(rd_rel->relhassubclass);
804804
values[Anum_pg_class_relispopulated-1]=BoolGetDatum(rd_rel->relispopulated);
805805
values[Anum_pg_class_relreplident-1]=CharGetDatum(rd_rel->relreplident);

‎src/backend/catalog/system_views.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ CREATE VIEW pg_tables AS
119119
C.relhasindexAS hasindexes,
120120
C.relhasrulesAS hasrules,
121121
C.relhastriggersAS hastriggers,
122-
C.relhasrowsecurityAShasrowsecurity
122+
C.relrowsecurityASrowsecurity
123123
FROM pg_class CLEFT JOIN pg_namespace NON (N.oid=C.relnamespace)
124124
LEFT JOIN pg_tablespace TON (T.oid=C.reltablespace)
125125
WHEREC.relkind='r';

‎src/backend/commands/policy.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ parse_row_security_command(const char *cmd_name)
108108
charcmd;
109109

110110
if (!cmd_name)
111-
elog(ERROR,"Unregonized command.");
111+
elog(ERROR,"unregonized command");
112112

113113
if (strcmp(cmd_name,"all")==0)
114114
cmd=0;
@@ -121,8 +121,7 @@ parse_row_security_command(const char *cmd_name)
121121
elseif (strcmp(cmd_name,"delete")==0)
122122
cmd=ACL_DELETE_CHR;
123123
else
124-
elog(ERROR,"Unregonized command.");
125-
/* error unrecognized command */
124+
elog(ERROR,"unregonized command");
126125

127126
returncmd;
128127
}
@@ -422,8 +421,8 @@ RemovePolicyById(Oid policy_id)
422421
heap_close(rel,AccessExclusiveLock);
423422

424423
/*
425-
* Note that, unlike some of the other flags in pg_class,relhasrowsecurity
426-
* is not just an indication of if policies exist. Whenrelhasrowsecurity
424+
* Note that, unlike some of the other flags in pg_class,relrowsecurity
425+
* is not just an indication of if policies exist. Whenrelrowsecurity
427426
* is set (which can be done directly by the user or indirectly by creating
428427
* a policy on the table), then all access to the relation must be through
429428
* a policy. If no policy is defined for the relation then a default-deny
@@ -484,7 +483,7 @@ CreatePolicy(CreatePolicyStmt *stmt)
484483
if (rseccmd==ACL_INSERT_CHR&&stmt->qual!=NULL)
485484
ereport(ERROR,
486485
(errcode(ERRCODE_SYNTAX_ERROR),
487-
errmsg("Only WITH CHECK expression allowed for INSERT")));
486+
errmsg("only WITH CHECK expression allowed for INSERT")));
488487

489488

490489
/* Collect role ids */
@@ -731,7 +730,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
731730
if (!HeapTupleIsValid(rsec_tuple))
732731
ereport(ERROR,
733732
(errcode(ERRCODE_UNDEFINED_OBJECT),
734-
errmsg("policy'%s' for does not existon table%s",
733+
errmsg("policy\"%s\"on table\"%s\" does not exist",
735734
stmt->policy_name,
736735
RelationGetRelationName(target_table))));
737736

@@ -850,7 +849,7 @@ rename_policy(RenameStmt *stmt)
850849

851850
pg_rowsecurity_rel=heap_open(RowSecurityRelationId,RowExclusiveLock);
852851

853-
/* First pass- check for conflict */
852+
/* First pass -- check for conflict */
854853

855854
/* Add key - row security relation id. */
856855
ScanKeyInit(&skey[0],
@@ -868,7 +867,7 @@ rename_policy(RenameStmt *stmt)
868867
RowSecurityRelidPolnameIndexId, true,NULL,2,
869868
skey);
870869

871-
if (HeapTupleIsValid(rsec_tuple=systable_getnext(sscan)))
870+
if (HeapTupleIsValid(systable_getnext(sscan)))
872871
ereport(ERROR,
873872
(errcode(ERRCODE_DUPLICATE_OBJECT),
874873
errmsg("row-policy \"%s\" for table \"%s\" already exists",

‎src/backend/commands/tablecmds.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10647,7 +10647,7 @@ ATExecEnableRowSecurity(Relation rel)
1064710647
if (!HeapTupleIsValid(tuple))
1064810648
elog(ERROR,"cache lookup failed for relation %u",relid);
1064910649

10650-
((Form_pg_class)GETSTRUCT(tuple))->relhasrowsecurity= true;
10650+
((Form_pg_class)GETSTRUCT(tuple))->relrowsecurity= true;
1065110651
simple_heap_update(pg_class,&tuple->t_self,tuple);
1065210652

1065310653
/* keep catalog indexes current */
@@ -10674,7 +10674,7 @@ ATExecDisableRowSecurity(Relation rel)
1067410674
if (!HeapTupleIsValid(tuple))
1067510675
elog(ERROR,"cache lookup failed for relation %u",relid);
1067610676

10677-
((Form_pg_class)GETSTRUCT(tuple))->relhasrowsecurity= false;
10677+
((Form_pg_class)GETSTRUCT(tuple))->relrowsecurity= false;
1067810678
simple_heap_update(pg_class,&tuple->t_self,tuple);
1067910679

1068010680
/* keep catalog indexes current */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp