| From: | PG Bug reporting form <noreply(at)postgresql(dot)org> |
|---|---|
| To: | pgsql-bugs(at)lists(dot)postgresql(dot)org |
| Cc: | 1950233439(at)qq(dot)com |
| Subject: | BUG #19673: inetmi_int8 Signed Integer Overflow Returns Wrong IPv6 Address |
| Date: | 2026-09-07 14:12:15 |
| Message-ID: | 19673-3af11c9dfc3e0824@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: 19673
Logged by: Tianyu Shi
Email address: 1950233439(at)qq(dot)com
PostgreSQL version: 19beta3
Operating system: Ubuntu22.04
Description:
### Summary
In `inetmi_int8()` (`src/backend/utils/adt/network.c`, line 1946), the
expression `-addend` triggers signed integer overflow (C11 undefined
behavior) when `addend == INT64_MIN`. On x86-64, the CPU wraps the negation
back to `INT64_MIN`, causing the function to compute `ip - 2^63` instead of
the correct `ip + 2^63`. For IPv6 addresses, the overflow-detection path in
`internal_inetpl()` does not catch this case, so the function silently
returns a completely wrong address rather than raising an error.
Applications that use `inet - int8` to compute IPv6 subnet boundaries may
therefore derive incorrect range endpoints, potentially causing
access-control decisions to accept or reject the wrong addresses.
### PoC
Any unprivileged user can trigger the bug with a single SQL statement using
the `inet - int8` operator and `INT64_MIN` as the subtrahend.
```sql
-- Connect as any normal (non-superuser) role.
-- INT64_MIN must be passed as a string cast to avoid parse-time overflow.
-- Trigger: should compute 8000::1 + 2^63 = 8000::8000:0:0:1, but silently
returns a lower address.
SELECT '8000::1'::inet - '-9223372036854775808'::int8 AS trigger_result;
-- Roundtrip invariant: (X - INT64_MIN) + INT64_MIN must equal X.
SELECT
'8000::1'::inet
AS original,
'8000::1'::inet - '-9223372036854775808'::int8
AS minus_int64min,
('8000::1'::inet - '-9223372036854775808'::int8) +
'-9223372036854775808'::int8 AS roundtrip,
(('8000::1'::inet - '-9223372036854775808'::int8) +
'-9223372036854775808'::int8)
= '8000::1'::inet
AS roundtrip_correct;
-- Direction invariant: subtracting a negative must increase the address.
SELECT
'8000::1'::inet AS
original,
'8000::1'::inet - '-9223372036854775808'::int8 AS
result,
('8000::1'::inet - '-9223372036854775808'::int8) > '8000::1'::inet AS
direction_increased;
```
### Result
Expected: `'8000::1'::inet - INT64_MIN` = `ip + 2^63` = `8000::8000:0:0:1`
(address increases).
Actual: the function returns `7fff:ffff:ffff:ffff:8000::1`, which is *less*
than the original address — the arithmetic went in the wrong direction with
no error raised.
All three semantic invariants are violated:
```
original | minus_int64min | roundtrip |
roundtrip_correct
----------+-----------------------------+------------------------+-------------------
8000::1 | 7fff:ffff:ffff:ffff:8000::1 | 7fff:ffff:ffff:ffff::1 | f
original | result | direction_increased
----------+-----------------------------+---------------------
8000::1 | 7fff:ffff:ffff:ffff:8000::1 | f
```
`roundtrip_correct = f` and `direction_increased = f` confirm that
`inetmi_int8()` computed `ip - 2^63` instead of `ip + 2^63` due to the
signed integer overflow of `-INT64_MIN` on x86-64.
| From | Date | Subject | |
|---|---|---|---|
| Next Message | PG Bug reporting form | 2026-09-07 14:19:49 | BUG #19677: Silent int64→int32 Truncation in timestamp_izone() Produces Wrong Timestamps |
| Previous Message | PG Bug reporting form | 2026-09-07 14:10:42 | BUG #19672: int8shl/int8shr Undefined Behavior on Out-of-Range Shift Amounts |