I would like to report another current-head `Intra-Object Overflow` in `src/stream.c`, this time in the FTP/HTTP parser used by `openftp()`.
This is not the earlier `stropen(stream->path, path)` issue, and it is also distinct from the already narrower `user -> passwd` parser overflow. The problem here is the password component of the documented FTP path grammar.
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 used by `openftp()` contains:
```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 fields directly:
```c
ftp->local[0] = '\0';
...
decodeftppath(path, ftp->addr, ftp->file, ftp->user, ftp->passwd, ftp->topts);
```
Why I believe this is a real current-head bug:
1. The documented grammar already allows:
```text
STR_FTP [user[:passwd]]@address/file_path[::T=...]
```
2. A caller can keep the total path below `MAXSTRPATH == 1024`, so this report does not depend on the earlier top-level `stream->path` overflow.
3. Even with total path length below `1024`, the parsed password component can still exceed `255`.
4. There is no current-head component-length validation before:
```c
if (passwd) strcpy(passwd, q + 1);
```
5. In `ftp_t`, `passwd[256]` is immediately followed by the live field `local[1024]`.
So an oversized password causes a direct intra-object overwrite from `passwd` into `local`.
A minimal trigger shape is:
```text
u:EEEE...(320 bytes)@host/file
```
This has total length only `332`, so it stays below `MAXSTRPATH`, while the password component itself is `320` bytes.
I also built a reduced source-faithful proof that preserves the exact `ftp_t` member order and the exact `decodeftppath()` logic. Its output is:
```text
path_len=332
distance_passwd_to_local=256
passwd_component_len=320
overflow_bytes_into_local=65
local_prefix_hex=4545454545454545
topts_unchanged=1
```
That result shows:
- the total path remains only `332`
- `passwd[256]` is directly followed by `local[1024]`
- a `320`-byte password writes `65` bytes into the adjacent `local` field
- the overwrite stays localized and does not depend on a larger surrounding object overflow
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->passwd[256] -> ftp->local[1024]`
I think the right fix is to validate parsed component lengths before copying and replace raw `strcpy()` with bounded copies for `user`, `passwd`, `file`, and `addr`.
Best regards
Pengpeng Hou
ISCAS