Skip to content

[Overflow Bug] RTKLIB stream.c: current-head intra-object overflow in proxy-enabled NTRIP URL formatting #792

Description

@neosys007
I would like to report another current-head `Intra-Object Overflow` in `src/stream.c`, this time in the proxy-enabled formatting path inside `openntrip()`.
This is not the earlier `stropen(stream->path, path)` issue, and it is also distinct from the already reported parser-component overflows. The failing sink here is the later `sprintf()` that builds `http://` + `addr:port` into the embedded `url[256]` field.

The relevant current-head object layout is:

```c
typedef struct {
    int state;
    int type;
    int nb;
    char url[256];
    char mntpnt[256];
    char user[256];
    char passwd[256];
    char str[NTRIP_MAXSTR];
    unsigned char buff[NTRIP_MAXRSP];
    tcpcli_t *tcp;
} ntrip_t;
```

The relevant `openntrip()` logic is:

```c
char addr[256] = "", port[256] = "", tpath[MAXSTRPATH];
...
decodetcppath(path, addr, port, ntrip->user, ntrip->passwd, ntrip->mntpnt,
              ntrip->str);
if (!*port) {
    sprintf(port, "%d", type ? NTRIP_CLI_PORT : NTRIP_SVR_PORT);
}
sprintf(tpath, "%s:%s", addr, port);

if (*proxyaddr) {
    sprintf(ntrip->url, "http://%s", tpath);
    strcpy(tpath, proxyaddr);
}
```

And proxy mode itself is enabled through the public API:

```c
extern void strsetproxy(const char *addr)
{
    strcpy(proxyaddr, addr);
}
```

Why I believe this is a real current-head bug:

1. The total NTRIP path can remain far below `MAXSTRPATH == 1024`, so this report does not collapse into the earlier top-level `stream->path` overflow.

2. The parsed address component can also remain below `256`, so this report does not rely on the earlier address-field parser overflow either.

3. The actual failing sink is the later proxy-mode formatter:

```c
sprintf(ntrip->url, "http://%s", tpath);
```

4. In `ntrip_t`, `url[256]` is immediately followed by the live field `mntpnt[256]`.

So when proxy mode is enabled and `tpath` is long enough, the formatted URL overruns `url` and writes into `mntpnt`.

One minimal trigger shape is:

1. call `strsetproxy("proxy:8080")`
2. call `stropen(..., STR_NTRIPCLI, ..., path)` with a path containing a `249`-byte address and no explicit port

With that setup:

- `decodetcppath()` stores the address safely in local `addr[256]`
- the default client port becomes `"2101"`
- `tpath` becomes `254` bytes
- `"http://%s"` writes `262` bytes including the terminating NUL into `url[256]`

That means `6` bytes are written into the adjacent `mntpnt` field.

I also built a reduced source-faithful proof preserving the exact member order and the exact formatting sequence. Its output is:

```text
path_len=249
addr_component_len=249
tpath_len=254
distance_url_to_mntpnt=256
overflow_bytes_into_mntpnt=6
mntpnt_prefix_hex=3A3231303100
user_unchanged=1
```

That result shows:

- the input path remains only `249` bytes long
- the parsed address remains within `addr[256]`
- `url[256]` is directly followed by `mntpnt[256]`
- the overflow bytes are exactly the trailing `":2101\\0"` suffix written into the adjacent field

I am making a narrow claim:

- this is current-head
- it requires proxy mode to be enabled through the documented public API
- it is a real write-side intra-object overflow
- the concrete overwrite is `ntrip->url[256] -> ntrip->mntpnt[256]`

I think the right fix is to validate the formatted length before writing into `url`, or replace the raw `sprintf()` with a bounded formatter and reject truncated results.

Best regards
Pengpeng Hou
ISCAS

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions