Let me work thru a typical capability transaction ...
We consider an application component as it invokes another component within a capability system. We then consider what might be necessary in a Unix system to achieve the same degree of isolation of accountability of these two components that was achieved in the capability system.

Steps that we will suggest are seldom thought necessary in classic (Unix) systems, but perhaps this is largely due to their substantial cost there.

Component B invokes C which runs in another address space. Unix provides several ways of doing this: pipes, exec, and some Unixes have custom means: Solaris has its undocumented “doors” and Linux has “clone”.

B has created about a megabyte of data, X, that C must read to produce about a kilobyte of data to return to B. C will invoke other components unknown to B in this task. The convention between B and C is that B will dispose of the storage holding the response when it is done with it.

In either system we must decide what steps are necessary for B to have access to C. I shall assume in this case that the invocation of C is not to interact with others who invoke C; in effect C is free of side-effects.

With capabilities

B invokes a segment creator for a segment to hold the data X. A segment capability, S, is returned to B in the response. It chooses an address at which to access that segment and maps the new segment there. It creates the data incrementally, storing into the mapped segment. It makes all sorts of references to other facilities during this time.

It comes time to invoke C. B invokes the segment capability S to obtain a read-only capability, R, to the same segment. B “calls” a capability to C passing R. C installs the received capability in its own address space in order to read the data. C creates a segment for the response and installs that segment at another address. C finds from the data that yet another consultant is required for the job and passes R to that sub-sub contractor. The response in this case is an integer which is returned by value. C resumes its work and produces the data required by B. C returns to B passing the segment with the answer. B maps the segment with the response and uses the answer. B then invokes the returned segment to delete it. It may also invoke S to delete it if it is done with S too.

The scenario ends here.

In a system such as Unix

B creates an empty file X. A directory must be chosen in which to register a name for X. This must be a directory in which B may make new entries and from which C may open files. B would not ordinarily have a directory exclusively of its own, but we shall assume here that whatever code launched B also created a directory exclusively for B. B will write the data into X either by classic file writes or by mmap; the choice is private to B. Of course B and C might agree to run concurrently and send the data thru a pipe. Capability systems have similar tricks and that is another interesting scenario which we will not pursue here. We assume that the data format for S is not naturally produced sequentially. When it comes time to invoke C, we shall assume that B will perform the exec system calls “fork” and the child process will perform “execve”. This is the only easy way I know of isolating planning of storage layout between B and C.