kernel: HTTPS through wget, half-close, and /proc/<pid>/fd

busybox wget hands TLS to ssl_client over a socketpair and then does
shutdown(SHUT_WR). That cut the AF_UNIX link both ways, so ssl_client's
reply was a SIGPIPE and every https:// download hung. SHUT_WR is now a
half-close: the peer reads EOF and can still answer. TCP sockets get
shutdown() at all (tcp_shutdown for the FIN); it used to do nothing.

- exec keeps ignored signals and the signal mask, as execve(2) says.
- /proc/<pid>/fd: a link per descriptor -- the path it was opened by,
  socket:[n], pipe:[n], anon_inode:[eventpoll]. /proc/self too. The
  global inode bit moves above pid << 8; at 0x10000 it was /proc/256.
- fstat on a socket or pipe answers S_IFSOCK / S_IFIFO instead of EINVAL.
- poll, select and epoll wake as soon as a pipe, socket or input device
  changes, not on the next tick.
- Pipes are 64 KB of lazily allocated pages, copied in blocks, with
  PIPE_BUF atomicity: 300 MB through `yes | head | wc` in 7 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
Nexoniarz 2026-10-24 20:28:03 +02:00
commit 8351e0323b
15 changed files with 434 additions and 71 deletions

View file

@ -1907,6 +1907,50 @@ proc_snapshot_pid(int pid, struct procinfo *out)
return -1;
}
// /proc/<pid>/fd: which descriptors are open, and what one points at. The
// ptable lock keeps the process from being reaped -- exit() closes its files
// first -- and file_describe() holds the file steady itself.
int
proc_fd_mask(int pid, uint64 mask[2])
{
struct proc *p;
int r = -1;
mask[0] = mask[1] = 0;
acquire(&ptable.lock);
for (p = ptable.proc; p < &ptable.proc[NPROC]; p++) {
if (p->state == UNUSED || p->pid != pid)
continue;
for (int fd = 0; fd < NOFILE && fd < 128; fd++)
if (p->ofile[fd])
mask[fd / 64] |= 1ULL << (fd % 64);
r = 0;
break;
}
release(&ptable.lock);
return r;
}
int
proc_fd_link(int pid, int fd, char *buf, int cap)
{
struct proc *p;
int r = -1;
if (fd < 0 || fd >= NOFILE)
return -1;
acquire(&ptable.lock);
for (p = ptable.proc; p < &ptable.proc[NPROC]; p++) {
if (p->state == UNUSED || p->pid != pid)
continue;
if (p->ofile[fd])
r = file_describe(p->ofile[fd], buf, cap);
break;
}
release(&ptable.lock);
return r;
}
int proc_num(void)
{
struct proc *p;