NetSurf: what GTK's images and libcurl's resolver needed

NetSurf (GTK 3) now starts under X and loads pages over HTTPS. Every icon
GTK draws goes gdk-pixbuf -> glycin -> a loader process -> a sealed memfd
-> GMappedFile, and each hop found something missing:

- mkaroot runs Alpine's package triggers in the root under bubblewrap.
  --no-scripts had skipped them, so there was no MIME cache, pixbuf loader
  list, compiled GSettings schemas, GIO module cache, font cache or busybox
  applet links.
- /usr/bin/bwrap is a stand-in that parses bubblewrap's options and runs
  the program with no sandbox: glycin starts its loaders only through bwrap,
  and real bwrap needs namespaces. schos-base replaces bubblewrap for it.
- ioctl: FIOCLEX, FIONCLEX, FIONBIO and FIOASYNC on any descriptor (Rust's
  std uses them; pipes and sockets answered ENOTTY).
- capget/capset: root has every capability, others none.
- socketpair accepts SOCK_DGRAM and SOCK_SEQPACKET, carried as a stream.
- waitpid and setpgid match children against the thread group leader, so a
  thread can wait for the process it spawned (ECHILD before).
- memfd: fstat reports the ftruncate length, not the page-rounded one; file
  seals (F_ADD_SEALS, F_GET_SEALS, MFD_ALLOW_SEALING) are recorded and
  enforced on later writes, truncation and writable mappings; MFD_CLOEXEC
  is honoured; read-only MAP_PRIVATE maps are allowed.
- recvfrom honours O_NONBLOCK and MSG_DONTWAIT. musl's resolver reads its
  socket until EAGAIN and blocked for ever after the first DNS answer.

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-25 04:10:26 +01:00
commit 393bf674f5
11 changed files with 251 additions and 21 deletions

View file

@ -1477,18 +1477,21 @@ waitpid(int pid, int *status, int options, uint64 *ut, uint64 *st)
{
struct proc *p;
int havekids;
// Children belong to the process, not to the thread that made them: any
// thread may wait for them, and their exit wakes the leader's channel.
struct proc *me = proc_leader(myproc());
acquire(&ptable.lock);
for(;;){
havekids = 0;
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
if(p->parent != myproc())
if(p->parent != me)
continue;
// POSIX pid selection: >0 one child, 0 = caller's group,
// -1 = any child, < -1 = the process group with id -pid.
if(pid > 0 && p->pid != pid)
continue;
if(pid == 0 && p->pgid != myproc()->pgid)
if(pid == 0 && p->pgid != me->pgid)
continue;
if(pid < -1 && p->pgid != -pid)
continue;
@ -1503,8 +1506,8 @@ waitpid(int pid, int *status, int options, uint64 *ut, uint64 *st)
// RUSAGE_CHILDREN: the child's own time *and* whatever it had already
// reaped, which is what makes the total transitive down a whole tree
// of processes rather than one generation deep.
myproc()->cutime += p->utime + p->cutime;
myproc()->cstime += p->stime + p->cstime;
me->cutime += p->utime + p->cutime;
me->cstime += p->stime + p->cstime;
reaped_utime += p->utime;
reaped_stime += p->stime;
// wait4()'s fourth argument wants the *child's* usage, not the
@ -1576,7 +1579,7 @@ waitpid(int pid, int *status, int options, uint64 *ut, uint64 *st)
return 0;
}
sleep(myproc(), &ptable.lock);
sleep(me, &ptable.lock);
}
}
@ -2699,7 +2702,7 @@ proc_setpgid(int pid, int pgid)
continue;
// A caller may only move itself or one of its own children, and never
// across a session boundary.
if(p != myproc() && p->parent != myproc())
if(p != myproc() && p->parent != proc_leader(myproc()))
r = -ESRCH;
else if(p->sid != myproc()->sid)
r = -EPERM;