Dear Maintainer,
I reproduce this on 6.18.10+deb14-amd64 (current nightly d-i),
6.1.0-35-amd64, and 6.7.7-amd64:
$ cat a.c
int main() {
close(0);
open("/proc/self/maps", 0);
char buf[20];
read(0, buf, sizeof(buf));
execlp("cat", "cat", (void *)0);
}
$ cc a.c
$ ./a.out
b3000 r--p 00000000 00:8a 816985 /home/nabijaczleweli/uwu/otp/a.out
$ sed -e 's:read://&:' -e s/cat/wc/ a.c > b.c
$ cc b.c
$ ./a.out
0 0 0
You can reproduce this with bash with wc < /proc/self/maps,
which yields 0 0 0 because bash does fork -> open -> exec.
dash does open -> fork -> exec, and it shows dash's maps.
Arguably bash is more correct, except Linux doesn't implement the file
in a useful way (doesn't implement it correctly(?)).
For non-/self/ I tried:
1$ echo $$
1727476
1$ exec sleep inf # after the sleep below
2$ (sleep 10; wc) < /proc/1727476/maps
0 0 0
and
1$ echo $$
1730151
1$ exec sleep inf # after the sleep below
2$ (head -c 32; sleep 10; wc) < /proc/1730151/maps
55cf54298000-55cf542c7000 r--p 01 4 55
which replicates this directly.
(read()ing a /proc/$pid/maps fd after $pid does exist returns ESRCH,
which is as-expected I think.)
Best,
Opening /proc/$pid/maps gives you a representation of the current memory space of $pid. execve() tears down that memory space and creates a new memory space. The open file is left referring to the old memory space, which is now empty (but won't be freed as long as the file is open). I think it's correct that no more mappings are visible through the open file at this point. What are you proposing would be the correct behaviour? Ben.
I'll be honest with you, I don't really know.
Locking in the memory map on read() instead of on open() seems at least
as bad if not worse.
For read -> exec -> read, the second read yielding the partial
"b3000 r--p 00000000 00:8a 816985 /home/nabijaczleweli/uwu/otp/a.out\n"
isn't pretty, but the alternative is that you get your line truncated
for no reason if your buffer falls mid-line,
which does now sound worse than keeping that as-is.
Of course, the seek behaviour seems obviously wrong as well:
lseek(0, 200, SET) reads empty,
lseek(0, 220, SET) reads the first line skip 20 characters,
lseek(0, 201, SET) reads the first line skip 1 character,
lseek(0, 110, SET) reads the first line skip 10 characters:
(yes, the hundred digit seems meaningless here? 6.1.0-35-amd64)
int main() {
close(0);
open("/proc/self/maps", 0);
lseek(0, (long)110, 0);
execlp("cat", "cat", (void *)0);
}
but that seems tangential.
Best,