BUG #19523: psql tab-completion shadows pg_db_role_setting

From: PG Bug reporting form <noreply(at)postgresql(dot)org>
To: pgsql-bugs(at)lists(dot)postgresql(dot)org
Cc: digoal(at)126(dot)com
Subject: BUG #19523: psql tab-completion shadows pg_db_role_setting
Date: 2026-06-18 07:06:44
Message-ID: 19523-424457118202f570@postgresql.org
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

The following bug has been logged on the website:

Bug reference: 19523
Logged by: Zhou Digoal
Email address: digoal(at)126(dot)com
PostgreSQL version: 19beta1
Operating system: macOS
Description:

# 🐛 [BUG] psql tab-completion shadows pg_db_role_setting

## Environment

| Item | Value |
| --- | --- |
| OS | macOS 15.7.7 (build 24G720) |
| Kernel | Darwin 24.6.0 |
| Compiler | Apple clang version 17.0.0 (clang-1700.6.4.2) |
| PG version | 19beta1 (`pg_config --version`) |
| Source branch | `master` |
| Source commit | `850b9218c8e4aa7a56f4ec34a542d4a37f9e07eb` |
| `git describe` | `850b921` |
| Build flags | `--enable-debug --enable-cassert --enable-debug-symbols` |
| Configure | `$PGBIN/pg_config --configure` |

---

## Summary

The query that psql tab-completion runs to list database-scoped GUC names
(Query_for_list_of_database_vars in src/bin/psql/tab-complete.c, duplicated
in src/bin/psql/tab-complete.in.c) references the system catalog table
pg_db_role_setting without the pg_catalog. schema qualifier. A user with
CREATE privilege on any schema earlier in search_path than pg_catalog can
therefore shadow the catalog table and influence tab-completion suggestions
for ALTER DATABASE SET.

---

## Commit under test

`850b9218c8e4aa7a56f4ec34a542d4a37f9e07eb` on branch `master`. The full
source HEAD at report
time is `850b9218c8e4aa7a56f4ec34a542d4a37f9e07eb` (`git describe` →
`850b921`).

---

## Reproduction

Repro file: `/tmp/repro_pg_db_role_setting.sql`

```sql
CREATE SCHEMA attacker;
CREATE TABLE attacker.pg_db_role_setting (
setdatabase oid,
setrole oid,
setconfig text[]
);
INSERT INTO attacker.pg_db_role_setting
SELECT oid, 0, ARRAY['custom_var=value', 'session_replication_role=replica']
FROM pg_database WHERE datname = 'postgres';
SET search_path = attacker, pg_catalog;
SELECT conf FROM (
SELECT setdatabase,
pg_catalog.split_part(pg_catalog.unnest(setconfig),'=',1) conf
FROM pg_db_role_setting
) s, pg_database d
WHERE s.setdatabase = d.oid
AND conf LIKE 'c%'
AND d.datname LIKE 'p%';
RESET search_path;
DROP SCHEMA attacker CASCADE;
```

### Actual output

```
Returned one row 'custom_var' that was read from attacker.pg_db_role_setting
rather than from the system catalog (which is empty for this database).
```

### Server log (last lines)

```
CREATE SCHEMA attacker;
CREATE SCHEMA
CREATE TABLE attacker.pg_db_role_setting (
setdatabase oid,
setrole oid,
setconfig text[]
);
CREATE TABLE
INSERT INTO attacker.pg_db_role_setting
SELECT oid, 0, ARRAY['custom_var=value', 'session_replication_role=replica']
FROM pg_database WHERE datname = 'postgres';
INSERT 0 1
SET search_path = attacker, pg_catalog;
SET
SELECT conf FROM (
SELECT setdatabase,
pg_catalog.split_part(pg_catalog.unnest(setconfig),'=',1) conf
FROM pg_db_role_setting
) s, pg_database d
WHERE s.setdatabase = d.oid
AND conf LIKE 'c%'
AND d.datname LIKE 'p%';
conf
------------
custom_var
(1 row)

RESET search_path;
RESET
DROP SCHEMA attacker CASCADE;
psql:/tmp/repro_pg_db_role_setting.sql:48: NOTICE: drop cascades to table
attacker.pg_db_role_setting
DROP SCHEMA
```

### Expected output

```
Zero rows; the query should resolve pg_db_role_setting to the system catalog
table regardless of search_path.
```

---

## Why is this a bug?

Commit bf5206f (psql: Add some missing schema qualifications in describe.c)
fixed the same class of bug for describe.c but missed tab-complete.c and
tab-complete.in.c. A user who can create a table named pg_db_role_setting in
a schema that appears before pg_catalog in search_path can have psql issue
its tab-completion query against the shadow table instead of the real
catalog, returning attacker- controlled GUC names. This violates the
documented psql behavior of suggesting actual database-level GUC settings.

---

## Suggested fix

Qualify the reference in src/bin/psql/tab-complete.in.c (line 1043) and the
generated src/bin/psql/tab-complete.c (line 1064) by changing FROM
pg_db_role_setting to FROM pg_catalog.pg_db_role_setting, then regenerate
tab-complete.c on rebuild.

---

## Severity

**medium** — see Environment block.

Browse pgsql-bugs by date

  From Date Subject
Next Message PG Bug reporting form 2026-06-18 07:52:50 BUG #19524: In `contrib/btree_gist` float4/float8 GiST index operations, handling NaN values with raw C operator
Previous Message Amit Langote 2026-06-18 06:57:20 Re: BUG #19458: OOM killer in jsonb_path_exists_opr (@?) with malformed JSONPath containing non-existent variables