Skip to content

Commit

Permalink
Guard against search-path based attacks.
Browse files Browse the repository at this point in the history
Use qualified references to functions and operators in the SQL queries executed by the event triggers to prevent users from defining their own functions or operators to replace them.
  • Loading branch information
shinderuk authored and dwsteele committed Nov 4, 2021
1 parent e6b7eae commit 94309f2
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 6 deletions.
28 changes: 28 additions & 0 deletions expected/pgaudit.out
Expand Up @@ -1152,6 +1152,34 @@ NOTICE: AUDIT: SESSION,68,1,READ,SELECT,TABLE,public.tmp,CREATE TABLE tmp2 AS (
NOTICE: AUDIT: SESSION,68,1,WRITE,INSERT,TABLE,public.tmp2,CREATE TABLE tmp2 AS (SELECT * FROM tmp);,<none>
DROP TABLE tmp;
DROP TABLE tmp2;
--
-- Test that pgaudit event triggers are immune to search-path-based attacks
-- Attempt to capture unqualified references to standard functions
CREATE FUNCTION upper(text) RETURNS text
LANGUAGE SQL AS 'SELECT (1/0)::text';
CREATE FUNCTION lower(text) RETURNS text
LANGUAGE SQL AS 'SELECT (1/0)::text';
CREATE FUNCTION my_ne(text, text) RETURNS bool
LANGUAGE SQL AS 'SELECT (1/0)::bool';
CREATE OPERATOR <> (FUNCTION = my_ne, LEFTARG = text, RIGHTARG = text);
WARNING: operator attribute "function" not recognized
ERROR: operator procedure must be specified
CREATE EXTENSION IF NOT EXISTS pgaudit;
SET pgaudit.log = 'DDL';
-- Put public schema before pg_catalog to capture unqualified references
SET search_path = public, pg_catalog;
-- If there was a vulnerability, these would fail with division by zero error
CREATE TABLE wombat ();
NOTICE: AUDIT: SESSION,69,1,DDL,CREATE TABLE,TABLE,public.wombat,CREATE TABLE wombat ();,<none>
DROP TABLE wombat;
NOTICE: AUDIT: SESSION,70,1,DDL,DROP TABLE,TABLE,public.wombat,DROP TABLE wombat;,<none>
SET pgaudit.log = 'NONE';
DROP EXTENSION pgaudit;
DROP OPERATOR <> (text, text);
ERROR: cannot drop operator <>(text,text) because it is required by the database system
DROP FUNCTION my_ne(text, text);
DROP FUNCTION lower(text);
DROP FUNCTION upper(text);
-- Cleanup
-- Set client_min_messages up to warning to avoid noise
SET client_min_messages = 'warning';
Expand Down
14 changes: 8 additions & 6 deletions pgaudit.c
Expand Up @@ -1521,7 +1521,9 @@ pgaudit_ddl_command_end(PG_FUNCTION_ARGS)
CreateCommandTag(eventData->parsetree);

/* Return objects affected by the (non drop) DDL statement */
query = "SELECT UPPER(object_type), object_identity, UPPER(command_tag)\n"
query = "SELECT pg_catalog.upper(object_type),\n"
" object_identity,\n"
" pg_catalog.upper(command_tag)\n"
" FROM pg_catalog.pg_event_trigger_ddl_commands()";

/* Attempt to connect */
Expand Down Expand Up @@ -1622,11 +1624,11 @@ pgaudit_sql_drop(PG_FUNCTION_ARGS)
contextOld = MemoryContextSwitchTo(contextQuery);

/* Return objects affected by the drop statement */
query = "SELECT UPPER(object_type),\n"
" object_identity\n"
" FROM pg_catalog.pg_event_trigger_dropped_objects()\n"
" WHERE lower(object_type) <> 'type'\n"
" AND schema_name <> 'pg_toast'";
query = "SELECT pg_catalog.upper(object_type),\n"
" object_identity\n"
" FROM pg_catalog.pg_event_trigger_dropped_objects()\n"
" WHERE pg_catalog.lower(object_type) operator(pg_catalog.<>) 'type'\n"
" AND schema_name operator(pg_catalog.<>) 'pg_toast'";

/* Attempt to connect */
result = SPI_connect();
Expand Down
32 changes: 32 additions & 0 deletions sql/pgaudit.sql
Expand Up @@ -788,6 +788,38 @@ CREATE TABLE tmp2 AS (SELECT * FROM tmp);
DROP TABLE tmp;
DROP TABLE tmp2;

--
-- Test that pgaudit event triggers are immune to search-path-based attacks

-- Attempt to capture unqualified references to standard functions
CREATE FUNCTION upper(text) RETURNS text
LANGUAGE SQL AS 'SELECT (1/0)::text';

CREATE FUNCTION lower(text) RETURNS text
LANGUAGE SQL AS 'SELECT (1/0)::text';

CREATE FUNCTION my_ne(text, text) RETURNS bool
LANGUAGE SQL AS 'SELECT (1/0)::bool';

CREATE OPERATOR <> (FUNCTION = my_ne, LEFTARG = text, RIGHTARG = text);

CREATE EXTENSION IF NOT EXISTS pgaudit;
SET pgaudit.log = 'DDL';
-- Put public schema before pg_catalog to capture unqualified references
SET search_path = public, pg_catalog;

-- If there was a vulnerability, these would fail with division by zero error
CREATE TABLE wombat ();
DROP TABLE wombat;

SET pgaudit.log = 'NONE';
DROP EXTENSION pgaudit;

DROP OPERATOR <> (text, text);
DROP FUNCTION my_ne(text, text);
DROP FUNCTION lower(text);
DROP FUNCTION upper(text);

-- Cleanup
-- Set client_min_messages up to warning to avoid noise
SET client_min_messages = 'warning';
Expand Down

0 comments on commit 94309f2

Please sign in to comment.