Just as I blame the infrastructure design on the problems of the confused deputy, the Intel 386 posed a security problem to kernels of most designs.

Bit 1 of the page table entry of the 386 memory mapping hardware is called “R/W”. This bit, when 1, allows user mode programs to write into the page defined by this entry. When the bit is 0 user mode code may not write into the page but privileged code can.

Suppose that user code has invoked the kernel to copy data into a buffer where the user code can access it. Innocent user code would designate an area to which it had write access, to receive the data, as the user is indirectly writing there—the kernel acting on behalf of the user. As the 386 is designed the kernel must do an extra check to verify that user has write access to the page or pages to receive the data. This check requires software simulation of the hardware page table lookup. A simple address range check is seldom sufficient if copy-on-write is in effect which causes read-only pages in address ranges to which the user program indeed has valid write access. Such accesses via kernel calls must somehow fall into the write trap code that drives the copy on write logic.

The 486 and Pentium designs superseded the 386 and section 5.11.3 of “Intel 64 and IA-32 Architectures Software Developer’s Manual. Volume 3A: System Programming” says:

This allows the code designed to respond to user mode write protection traps to respond also to the kernel attempting to write on such read-only pages. The extra permission testing in the kernel is thus avoided.

This is an exacerbation of the RAP problem.

Subroutines may usually be thought of as deputies—agents that will do something that you want them to do to forward your goals.

Sometimes invoking the privileged code is of this flavor and performs a function that you could have done for yourself except for not knowing the algorithm or having the space to hold the code to do the job.

More typically, however, you invoke more privileged code to do something that commands in your own program could not have done. There is no way to open a file except to call the FOC (file opening code). FOC, responding to your invocation, will need to wield its extra authority to do the job, yet be sensitive to avoiding actions on your behalf that would exceed your authority. The capability answer to this is for you to pass capabilities that tell the FOC what actions to take on your behalf. FOC need take no extra precautions and merely invoke them in your place. The problem is solved.