> On Sep 23, 2026, at 04:10, Egor Ivkov <[email protected]> wrote:
> 
> Hi,
>  parse_oid() in pg_combinebackup assigns the result of strtoul() to an Oid
> before range-checking it:
>      Oid         oid;
>     ...
>     oid = strtoul(s, &ep, 10);
>     if (errno != 0 || *ep != '\0' || oid < 1 || oid > PG_UINT32_MAX)
>         return false;
>  Since Oid is 32 bits, the value has already been truncated by the time
> "oid > PG_UINT32_MAX" is evaluated, so on platforms where unsigned long is
> wider than 32 bits that test can never fire.  An out-of-range string is
> then accepted as its truncated value rather than being rejected:
> "4294967297" is accepted as OID 1, and "-1" is accepted as OID 4294967295.
>  parse_oid() is only fed directory names found under pg_tblspc, so the
> practical consequence is limited: pg_combinebackup treats a bogus
> directory name as a valid tablespace OID instead of ignoring it.  It still
> seems worth fixing.
>  The attached patch keeps the parsed value in an unsigned long until it has
> been checked and casts to Oid afterwards, matching what
> parse_relfilenumber() in pg_upgrade already does.
>  The patch is against master.  The same code is present unchanged back to
> v17 (dc212340058), and the patch applies cleanly to REL_17_STABLE,
> REL_18_STABLE and REL_19_STABLE.
>  Regards,
> Egor Ivkov<v1-0001-pg_combinebackup-make-the-OID-range-check-in-pars.patch>

+1 on the direction.

I still have one concern about the implementation. On some platforms, unsigned 
long is also 32 bits, so the fix would still accept -1 there.

I see that parse_relfilenumber() checks the first character before calling 
strtoul():
```
static RelFileNumber
parse_relfilenumber(const char *filename)
{
        char       *endp;
        unsigned long n;

        if (filename[0] < '1' || filename[0] > '9')
                return InvalidRelFileNumber;

        errno = 0;
        n = strtoul(filename, &endp, 10);
        if (errno || filename == endp || n <= 0 || n > PG_UINT32_MAX)
                return InvalidRelFileNumber;

        return (RelFileNumber) n;
}
```

Maybe we can use the same approach here.

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






Reply via email to