Skip to content

[Overflow Bug]RTKLIB stream.c: overflow in FTP path parsing via oversized username #790

@neosys007

Description

@neosys007
I would like to report a second current-head `Intra-Object Overflow` in `src/stream.c`, this time in the FTP/HTTP path parser used by `openftp()`.

This is again independent of the earlier `stropen(stream->path, path)` issue, because the total path can remain below `MAXSTRPATH` while one parsed component still exceeds the width of the embedded destination field.

The relevant current-head object layout is:

```c
typedef struct {
    int state;
    int proto;
    int error;
    char addr[1024];
    char file[1024];
    char user[256];
    char passwd[256];
    char local[1024];
    int topts[4];
    gtime_t tnext;
    thread_t thread;
} ftp_t;
```

The helper that parses the documented FTP path is:

```c
static void decodeftppath(const char *path, char *addr, char *file, char *user,
                          char *passwd, int *topts)
{
    char buff[MAXSTRPATH], *p, *q;
    ...
    strcpy(buff, path);
    ...
    if ((p = strrchr(buff, '@'))) {
        *p++ = '\0';
        if ((q = strchr(buff, ':'))) {
            *q = '\0';
            if (passwd) strcpy(passwd, q + 1);
        }
        *q = '\0';
        if (user) strcpy(user, buff);
    }
    ...
}
```

And `openftp()` passes the embedded `ftp_t` fields directly:

```c
decodeftppath(path, ftp->addr, ftp->file, ftp->user, ftp->passwd, ftp->topts);
```

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

1. `stropen()` documents FTP paths as:

```text
STR_FTP [user[:passwd]]@address/file_path[::T=...]
```

2. A path such as:

```text
AAAA...(320 bytes):p@host/file
```

has total length only `332`, which stays below `MAXSTRPATH == 1024`.

3. There is no validation that the parsed username component fits into `ftp->user[256]` before:

```c
if (user) strcpy(user, buff);
```

4. In `ftp_t`, `user[256]` is immediately followed by the live field `passwd[256]`.

So an oversized username causes a direct intra-object overwrite from `user` into `passwd`.

I also built a source-faithful reduced proof preserving the exact `ftp_t` field order and the exact `decodeftppath()` copy logic. The output is:

```text
path_len=332
distance_user_to_passwd=256
user_component_len=320
overflow_bytes_into_passwd=65
passwd_prefix_hex=4141414141414141
local_unchanged=1
```

That result shows:

- the total path remains safely below `1024`
- the overflow does not depend on the already-known `stream->path` bug
- `user[256]` is directly followed by `passwd[256]`
- a `320`-byte username overwrites `65` bytes of the adjacent `passwd` field

I am making a narrow claim:

- this is current-head
- it is reachable from the documented FTP path grammar
- it is a real write-side intra-object overflow
- the concrete overwrite is `ftp->user[256] -> ftp->passwd[256]`

I think the right fix is to validate each parsed component against the actual destination field size and replace these raw `strcpy()` calls with bounded copies.

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