Avoid leaking system path from pg_available_extensions

Started by Chao Liabout 1 month ago11 messageshackers
Jump to latest
#1Chao Li
li.evan.chao@gmail.com

Hi,

I just tested “Add paths of extensions to pg_available_extensions”, and found an issue.

This is a simple repro:
```
evantest=# reset extension_control_path;
RESET
evantest=# select * from pg_available_extensions where name = 'plpgsql';
name | default_version | installed_version | location | comment
---------+-----------------+-------------------+----------+------------------------------
plpgsql | 1.0 | 1.0 | $system | PL/pgSQL procedural language
(1 row)

evantest=# set extension_control_path='';
SET
evantest=# select * from pg_available_extensions where name = 'plpgsql';
name | default_version | installed_version | location | comment
---------+-----------------+-------------------+----------------------------------+------------------------------
plpgsql | 1.0 | 1.0 | /usr/local/pgsql/share/extension | PL/pgSQL procedural language
(1 row)
```

When extension_control_path is not set, location shows “$system", which is consistent with what the documentation says:
```
<para>
The default value for this parameter is
<literal>'$system'</literal>. If the value is set to an empty
string, the default <literal>'$system'</literal> is also assumed.
</para>
```

However, as shown above, when I set extension_control_path to an empty string, the absolute system path is displayed. I consider this an information leakage bug.

The fix is straightforward; see the attached patch for details. After the fix, when extension_control_path is an empty string, location shows “$system” now:
```
evantest=# set extension_control_path='';
SET
evantest=# select * from pg_available_extensions where name = 'plpgsql';
name | default_version | installed_version | location | comment
---------+-----------------+-------------------+----------+------------------------------
plpgsql | 1.0 | 1.0 | $system | PL/pgSQL procedural language
(1 row)
```

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

#2Chao Li
li.evan.chao@gmail.com
In reply to: Chao Li (#1)
Re: Avoid leaking system path from pg_available_extensions

On May 20, 2026, at 09:00, Chao Li <li.evan.chao@gmail.com> wrote:

Hi,

I just tested “Add paths of extensions to pg_available_extensions”, and found an issue.

This is a simple repro:
```
evantest=# reset extension_control_path;
RESET
evantest=# select * from pg_available_extensions where name = 'plpgsql';
name | default_version | installed_version | location | comment
---------+-----------------+-------------------+----------+------------------------------
plpgsql | 1.0 | 1.0 | $system | PL/pgSQL procedural language
(1 row)

evantest=# set extension_control_path='';
SET
evantest=# select * from pg_available_extensions where name = 'plpgsql';
name | default_version | installed_version | location | comment
---------+-----------------+-------------------+----------------------------------+------------------------------
plpgsql | 1.0 | 1.0 | /usr/local/pgsql/share/extension | PL/pgSQL procedural language
(1 row)
```

When extension_control_path is not set, location shows “$system", which is consistent with what the documentation says:
```
<para>
The default value for this parameter is
<literal>'$system'</literal>. If the value is set to an empty
string, the default <literal>'$system'</literal> is also assumed.
</para>
```

However, as shown above, when I set extension_control_path to an empty string, the absolute system path is displayed. I consider this an information leakage bug.

The fix is straightforward; see the attached patch for details. After the fix, when extension_control_path is an empty string, location shows “$system” now:
```
evantest=# set extension_control_path='';
SET
evantest=# select * from pg_available_extensions where name = 'plpgsql';
name | default_version | installed_version | location | comment
---------+-----------------+-------------------+----------+------------------------------
plpgsql | 1.0 | 1.0 | $system | PL/pgSQL procedural language
(1 row)
```

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

Oops, forgot the attachment. Here comes it.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

Attachments:

v1-0001-Avoid-leaking-system-path-from-pg_available_exten.patchapplication/octet-stream; name=v1-0001-Avoid-leaking-system-path-from-pg_available_exten.patch; x-unix-mode=0644Download+4-5
#3lu feng
fnlo1995@gmail.com
In reply to: Chao Li (#2)
Re: Avoid leaking system path from pg_available_extensions

Chao Li <li.evan.chao@gmail.com> 于2026年5月20日周三 09:08写道:

On May 20, 2026, at 09:00, Chao Li <li.evan.chao@gmail.com> wrote:

Hi,

I just tested “Add paths of extensions to pg_available_extensions”, and

found an issue.

This is a simple repro:
```
evantest=# reset extension_control_path;
RESET
evantest=# select * from pg_available_extensions where name = 'plpgsql';
name | default_version | installed_version | location |

comment

---------+-----------------+-------------------+----------+------------------------------

plpgsql | 1.0 | 1.0 | $system | PL/pgSQL

procedural language

(1 row)

evantest=# set extension_control_path='';
SET
evantest=# select * from pg_available_extensions where name = 'plpgsql';
name | default_version | installed_version | location

| comment

---------+-----------------+-------------------+----------------------------------+------------------------------

plpgsql | 1.0 | 1.0 |

/usr/local/pgsql/share/extension | PL/pgSQL procedural language

(1 row)
```

When extension_control_path is not set, location shows “$system", which

is consistent with what the documentation says:

```
<para>
The default value for this parameter is
<literal>'$system'</literal>. If the value is set to an empty
string, the default <literal>'$system'</literal> is also assumed.
</para>
```

However, as shown above, when I set extension_control_path to an empty

string, the absolute system path is displayed. I consider this an
information leakage bug.

The fix is straightforward; see the attached patch for details. After

the fix, when extension_control_path is an empty string, location shows
“$system” now:

```
evantest=# set extension_control_path='';
SET
evantest=# select * from pg_available_extensions where name = 'plpgsql';
name | default_version | installed_version | location |

comment

---------+-----------------+-------------------+----------+------------------------------

plpgsql | 1.0 | 1.0 | $system | PL/pgSQL

procedural language

(1 row)
```

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

Oops, forgot the attachment. Here comes it.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

Thanks for the patch. I just reproduced the problem and verified the fix.

So this patch looks good to me.

Regards,
Lu Feng

#4Matheus Alcantara
matheusssilv97@gmail.com
In reply to: Chao Li (#1)
Re: Avoid leaking system path from pg_available_extensions

On 19/05/26 22:00, Chao Li wrote:

I just tested “Add paths of extensions to pg_available_extensions”, and found an issue.

This is a simple repro:
```
evantest=# reset extension_control_path;
RESET
evantest=# select * from pg_available_extensions where name = 'plpgsql';
name | default_version | installed_version | location | comment
---------+-----------------+-------------------+----------+------------------------------
plpgsql | 1.0 | 1.0 | $system | PL/pgSQL procedural language
(1 row)

evantest=# set extension_control_path='';
SET
evantest=# select * from pg_available_extensions where name = 'plpgsql';
name | default_version | installed_version | location | comment
---------+-----------------+-------------------+----------------------------------+------------------------------
plpgsql | 1.0 | 1.0 | /usr/local/pgsql/share/extension | PL/pgSQL procedural language
(1 row)
```

When extension_control_path is not set, location shows “$system", which is consistent with what the documentation says:
```
<para>
The default value for this parameter is
<literal>'$system'</literal>. If the value is set to an empty
string, the default <literal>'$system'</literal> is also assumed.
</para>
```

However, as shown above, when I set extension_control_path to an empty string, the absolute system path is displayed. I consider this an information leakage bug.

The fix is straightforward; see the attached patch for details. After the fix, when extension_control_path is an empty string, location shows “$system” now:
```
evantest=# set extension_control_path='';
SET
evantest=# select * from pg_available_extensions where name = 'plpgsql';
name | default_version | installed_version | location | comment
---------+-----------------+-------------------+----------+------------------------------
plpgsql | 1.0 | 1.0 | $system | PL/pgSQL procedural language
(1 row)
```

Hi, thank you for sharing the bug with the fix.

I've reproduced the issue and the fix looks correct to me.

--
Matheus Alcantara
EDB: https://www.enterprisedb.com

#5Jim Jones
jim.jones@uni-muenster.de
In reply to: Matheus Alcantara (#4)
Re: Avoid leaking system path from pg_available_extensions

On 21/05/2026 17:12, Matheus Alcantara wrote:

I've reproduced the issue and the fix looks correct to me.

same here, +1

I was wondering if creating a constant for it would be, stylistically
speaking, a cleaner solution. For instance:

#define EXTENSION_SYSTEM_MACRO "$system"

I realize that it's used only inside get_extension_control_directories()
but since it is even mentioned in the docs, I guess it wouldn't be a bad
idea.

Thanks!

Best, Jim

#6Matheus Alcantara
matheusssilv97@gmail.com
In reply to: Jim Jones (#5)
Re: Avoid leaking system path from pg_available_extensions

On 22/05/26 04:25, Jim Jones wrote:

On 21/05/2026 17:12, Matheus Alcantara wrote:

I've reproduced the issue and the fix looks correct to me.

same here, +1

Thank you for also testing.

I was wondering if creating a constant for it would be, stylistically
speaking, a cleaner solution. For instance:

#define EXTENSION_SYSTEM_MACRO "$system"

I realize that it's used only inside get_extension_control_directories()
but since it is even mentioned in the docs, I guess it wouldn't be a bad
idea.

I'm not against it but I don't think that it's necessary since as you
mention, only get_extension_control_directories() use.

--
Matheus Alcantara
EDB: https://www.enterprisedb.com

#7Chao Li
li.evan.chao@gmail.com
In reply to: Matheus Alcantara (#6)
Re: Avoid leaking system path from pg_available_extensions

On May 22, 2026, at 23:40, Matheus Alcantara <matheusssilv97@gmail.com> wrote:

On 22/05/26 04:25, Jim Jones wrote:

On 21/05/2026 17:12, Matheus Alcantara wrote:

I've reproduced the issue and the fix looks correct to me.

same here, +1

Thank you for also testing.

I was wondering if creating a constant for it would be, stylistically
speaking, a cleaner solution. For instance:
#define EXTENSION_SYSTEM_MACRO "$system"
I realize that it's used only inside get_extension_control_directories()
but since it is even mentioned in the docs, I guess it wouldn't be a bad
idea.

I'm not against it but I don't think that it's necessary since as you mention, only get_extension_control_directories() use.

--
Matheus Alcantara
EDB: https://www.enterprisedb.com

In theory, I’m not against the idea either. In practice, there are many hard-coded strings in the source tree, and I’m not sure where the right place would be to define this macro.

Since this string is only used in get_extension_control_directories(), and now it is used three times, I defined it at the beginning of the function and undefined it at the end. Let’s see if there are any objections to that.

Please see the attached v2.
Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/

Attachments:

v2-0001-Avoid-leaking-system-path-from-pg_available_exten.patchapplication/octet-stream; name=v2-0001-Avoid-leaking-system-path-from-pg_available_exten.patch; x-unix-mode=0644Download+8-7
#8Jim Jones
jim.jones@uni-muenster.de
In reply to: Chao Li (#7)
Re: Avoid leaking system path from pg_available_extensions

On 26/05/2026 09:14, Chao Li wrote:

In theory, I’m not against the idea either. In practice, there are many hard-coded strings in the source tree, and I’m not sure where the right place would be to define this macro.

Since this string is only used in get_extension_control_directories(), and now it is used three times, I defined it at the beginning of the function and undefined it at the end. Let’s see if there are any objections to that.

I don't feel strongly about it. I only brought it up because hardcoded
strings used in multiple places are usually a recipe for oversights and
painful debugging down the road. That said, as I mentioned, I understand
the argument that this is scoped to a single function, and the fact
they're pretty close to one another also makes it less likely to be
missed, but there is no guarantee it'll stay like that forever.

Thanks for the fix!

Best, Jim

#9Matheus Alcantara
matheusssilv97@gmail.com
In reply to: Chao Li (#7)
Re: Avoid leaking system path from pg_available_extensions

On 26/05/26 04:14, Chao Li wrote:

On May 22, 2026, at 23:40, Matheus Alcantara <matheusssilv97@gmail.com> wrote:

On 22/05/26 04:25, Jim Jones wrote:

On 21/05/2026 17:12, Matheus Alcantara wrote:

I've reproduced the issue and the fix looks correct to me.

same here, +1

Thank you for also testing.

I was wondering if creating a constant for it would be, stylistically
speaking, a cleaner solution. For instance:
#define EXTENSION_SYSTEM_MACRO "$system"
I realize that it's used only inside get_extension_control_directories()
but since it is even mentioned in the docs, I guess it wouldn't be a bad
idea.

I'm not against it but I don't think that it's necessary since as you mention, only get_extension_control_directories() use.

In theory, I’m not against the idea either. In practice, there are many hard-coded strings in the source tree, and I’m not sure where the right place would be to define this macro.

Since this string is only used in get_extension_control_directories(), and now it is used three times, I defined it at the beginning of the function and undefined it at the end. Let’s see if there are any objections to that.

Please see the attached v2.

We have such pattern in other parts of the codebase (e.g
pg_resetwal.c), so it works for me.

Thanks for the patch.

--
Matheus Alcantara
EDB: https://www.enterprisedb.com

#10Andrew Dunstan
andrew@dunslane.net
In reply to: Matheus Alcantara (#9)
Re: Avoid leaking system path from pg_available_extensions

On 2026-05-26 Tu 9:29 AM, Matheus Alcantara wrote:

On 26/05/26 04:14, Chao Li wrote:

On May 22, 2026, at 23:40, Matheus Alcantara
<matheusssilv97@gmail.com> wrote:

On 22/05/26 04:25, Jim Jones wrote:

On 21/05/2026 17:12, Matheus Alcantara wrote:

I've reproduced the issue and the fix looks correct to me.

same here, +1

Thank you for also testing.

I was wondering if creating a constant for it would be, stylistically
speaking, a cleaner solution. For instance:
#define EXTENSION_SYSTEM_MACRO  "$system"
I realize that it's used only inside
get_extension_control_directories()
but since it is even mentioned in the docs, I guess it wouldn't be
a bad
idea.

I'm not against it but I don't think that it's necessary since as
you mention, only get_extension_control_directories() use.

In theory, I’m not against the idea either. In practice, there are
many hard-coded strings in the source tree, and I’m not sure where
the right place would be to define this macro.

Since this string is only used in
get_extension_control_directories(), and now it is used three times,
I defined it at the beginning of the function and undefined it at the
end. Let’s see if there are any objections to that.

Please see the attached v2.

We have such pattern in other parts of the codebase (e.g
pg_resetwal.c), so it works for me.

Thanks for the patch.

Pushed.

cheers

andrew

--
Andrew Dunstan
EDB: https://www.enterprisedb.com

#11Chao Li
li.evan.chao@gmail.com
In reply to: Andrew Dunstan (#10)
Re: Avoid leaking system path from pg_available_extensions

On May 30, 2026, at 21:21, Andrew Dunstan <andrew@dunslane.net> wrote:

On 2026-05-26 Tu 9:29 AM, Matheus Alcantara wrote:

On 26/05/26 04:14, Chao Li wrote:

On May 22, 2026, at 23:40, Matheus Alcantara <matheusssilv97@gmail.com> wrote:

On 22/05/26 04:25, Jim Jones wrote:

On 21/05/2026 17:12, Matheus Alcantara wrote:

I've reproduced the issue and the fix looks correct to me.

same here, +1

Thank you for also testing.

I was wondering if creating a constant for it would be, stylistically
speaking, a cleaner solution. For instance:
#define EXTENSION_SYSTEM_MACRO "$system"
I realize that it's used only inside get_extension_control_directories()
but since it is even mentioned in the docs, I guess it wouldn't be a bad
idea.

I'm not against it but I don't think that it's necessary since as you mention, only get_extension_control_directories() use.

In theory, I’m not against the idea either. In practice, there are many hard-coded strings in the source tree, and I’m not sure where the right place would be to define this macro.

Since this string is only used in get_extension_control_directories(), and now it is used three times, I defined it at the beginning of the function and undefined it at the end. Let’s see if there are any objections to that.

Please see the attached v2.

We have such pattern in other parts of the codebase (e.g pg_resetwal.c), so it works for me.

Thanks for the patch.

Pushed.

cheers

andrew

--
Andrew Dunstan
EDB: https://www.enterprisedb.com

Thanks for pushing.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/