diff --git a/en_US.ISO8859-1/books/arch-handbook/boot/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/boot/chapter.sgml
index 9e8ae2ef1c..0e28c6519e 100644
--- a/en_US.ISO8859-1/books/arch-handbook/boot/chapter.sgml
+++ b/en_US.ISO8859-1/books/arch-handbook/boot/chapter.sgml
@@ -1,1023 +1,1024 @@
SergeyLyubkaContributed by Bootstrapping and kernel initializationSynopsisThis chapter is an overview of the boot and system
initialization process, starting from the BIOS (firmware) POST,
to the first user process creation. Since the initial steps of
system startup are very architecture dependent, the IA-32
architecture is used as an example.OverviewA computer running FreeBSD can boot by several methods,
although the most common method, booting from a harddisk where
the OS is installed, will be discussed here. The boot process
is divided into several steps:BIOS POSTboot0 stageboot2 stageloader stagekernel initializationThe boot0 and boot2
stages are also referred to as bootstrap stages 1 and
2 in &man.boot.8; as the first steps in FreeBSD's
3-stage bootstrapping procedure. Various information is printed
on the screen at each stage, so you may visually recognize them
using the table that follows. Please note that the actual data
may differ from machine to machine:may varyBIOS (firmware) messagesF1 FreeBSD
F2 BSD
F5 Disk 2boot0>>FreeBSD/i386 BOOT
Default: 1:ad(1,a)/boot/loader
boot:boot2This
prompt will appear if the user presses a key just after
selecting an OS to boot at the boot0
stage.BTX loader 1.0 BTX version is 1.01
BIOS drive A: is disk0
BIOS drive C: is disk1
BIOS 639kB/64512kB available memory
FreeBSD/i386 bootstrap loader, Revision 0.8
Console internal video/keyboard
(jkh@bento.freebsd.org, Mon Nov 20 11:41:23 GMT 2000)
/kernel text=0x1234 data=0x2345 syms=[0x4+0x3456]
Hit [Enter] to boot immediately, or any other key for command prompt
Booting [kernel] in 9 seconds..._loaderCopyright (c) 1992-2002 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
The Regents of the University of California. All rights reserved.
FreeBSD 4.6-RC #0: Sat May 4 22:49:02 GMT 2002
devnull@kukas:/usr/obj/usr/src/sys/DEVNULL
Timecounter "i8254" frequency 1193182 HzkernelBIOS POSTWhen the PC powers on, the processor's registers are set
to some predefined values. One of the registers is the
instruction pointer register, and its value
after a power on is well defined: it is a 32-bit value of
0xfffffff0. The instruction pointer register points to code to
be executed by the processor. One of the registers is the
cr1 32-bit control register, and its value
just after the reboot is 0. One of the cr1's bits, the bit PE
(Protected Enabled) indicates whether the processor is running
in protected or real mode. Since at boot time this bit is
cleared, the processor boots in real mode. Real mode means,
among other things, that linear and physical addresses are
identical.The value of 0xfffffff0 is slightly less then 4Gb, so unless
the machine has 4Gb physical memory, it cannot point to a valid
memory address. The computer's hardware translates this address
so that it points to a BIOS memory block.BIOS stands for Basic Input Output
System, and it is a chip on the motherboard that has
a relatively small amount of read-only memory (ROM). This
memory contains various low-level routines that are specific to
the hardware supplied with the motherboard. So, the processor
will first jump to the address 0xfffffff0, which really resides
in the BIOS's memory. Usually this address contains a jump
instruction to the BIOS's POST routines.POST stands for Power On Self Test.
This is a set of routines including the memory check, system bus
check and other low-level stuff so that the CPU can initialize
the computer properly. The important step on this stage is
determining the boot device. All modern BIOS's allow the boot
device to be set manually, so you can boot from a floppy,
CD-ROM, harddisk etc.The very last thing in the POST is the INT
0x19 instruction. That instruction reads 512 bytes
from the first sector of boot device into the memory at address
0x7c00. The term first sector originates
from harddrive architecture, where the magnetic plate is divided
to a number of cylindrical tracks. Tracks are numbered, and
every track is divided by a number (usually 64) sectors. Track
number 0 is the outermost on the magnetic plate, and sector 1,
the first sector (tracks, or, cylinders, are numbered starting
from 0, but sectors - starting from 1), has a special meaning.
It is also called Master Boot Record, or MBR. The remaining
sectors on the first track are never used Some
utilities such as &man.disklabel.8; may store the information in
this area, mostly in the second
sector..boot0 stageTake a look at the file /boot/boot0.
This is a small 512-byte file, and it is exactly what FreeBSD's
installation procedure wrote to your harddisk's MBR if you chose
the bootmanager option at installation time.As mentioned previously, the INT 0x19
instruction loads an MBR, i.e. the boot0
content, into the memory at address 0x7c00. Taking a look at
the file sys/boot/i386/boot0/boot0.s can
give a guess at what is happening there - this is the boot
manager, which is an awesome piece of code written by Robert
Nordier.The MBR, or, boot0, has a special
structure starting from offset 0x1be, called the
partition table. It has 4 records of 16
bytes each, called partition records, which
represent how the harddisk(s) are partitioned, or, in FreeBSD's
terminology, sliced. One byte of those 16 says whether a
partition (slice) is bootable or not. Exactly one record must
have that flag set, otherwise boot0's code
will refuse to proceed.A partition record has the following fields:the 1-byte filesystem typethe 1-byte bootable flagthe 6 byte descriptor in CHS formatthe 8 byte descriptor in LBA formatA partition record descriptor has the information about
where exactly the partition resides on the drive. Both
descriptors, LBA and CHS, describe the same information, but in
different ways: LBA (Logical Block Addressing) has the starting
sector for the partition and the partition's length, while CHS
(Cylinder Head Sector) has coordinates for the first and last
sectors of the partition.The boot manager scans the partition table and prints the
menu on the screen so the user can select what disk and what
slice to boot. By pressing an appropriate key,
boot0 performs the following
actions:modifies the bootable flag for the selected partition to
make it bootable, and clears the previoussaves itself to disk to remember what partition (slice)
has been selected so to use it as the default on the next
bootloads the first sector of the selected partition (slice)
into memory and jumps thereWhat kind of data should reside on the very first sector of
a bootable partition (slice), in our case, a FreeBSD slice? As
you may have already guessed, it is
boot2.boot2 stageYou might wonder, why boot2 comes after
boot0, and not boot1. Actually, there is a
512-byte file called boot1 in the directory
/boot as well. It is used for booting from
a floppy. When booting from a floppy,
boot1 plays the same role as
boot0 for a harddisk: it locates
boot2 and runs it.You may have realized that a file
/boot/mbr exists as well. It is a
simplified version of boot0. The code in
mbr does not provide a menu for the user,
it just blindly boots the partition marked active.The code implementing boot2 resides in
sys/boot/i386/boot2/, and the executable
itself is in /boot. The files
boot0 and boot2 that
are in /boot are not used by the bootstrap,
but by utilities such as boot0cfg.
The actual position for boot0 is in the
MBR. For boot2 it is the beginning of a
bootable FreeBSD slice. These locations are not under the
filesystem's control, so they are invisible to commands like
ls.The main task for boot2 is to load the
file /boot/loader, which is the third stage
in the bootstrapping procedure. The code in
boot2 cannot use any services like
open() and read(),
since the kernel is not yet loaded. It must scan the harddisk,
knowing about the filesystem structure, find the file
/boot/loader, read it into memory using a
BIOS service, and then pass the execution to the loader's entry
point.Besides that, boot2 prompts for user
input so the loader can be booted from different disk, unit,
slice and partition.The boot2 binary is created in special
way:sys/boot/i386/boot2/Makefile
boot2: boot2.ldr boot2.bin ${BTX}/btx/btx
btxld -v -E ${ORG2} -f bin -b ${BTX}/btx/btx -l boot2.ldr \
-o boot2.ld -P 1 boot2.binThis Makefile snippet shows that &man.btxld.8; is used to
link the binary. BTX, which stands for BooT eXtender, is a
piece of code that provides a protected mode environment for the
program, called the client, that it is linked with. So
boot2 is a BTX client, i.e. it uses the
service provided by BTX.The btxld utility is the linker.
It links two binaries together. The difference between
&man.btxld.8; and &man.ld.1; is that
ld usually links object files into a
shared object or executable, while
btxld links an object file with the
BTX, producing the binary file suitable to be put on the
beginning of the partition for the system boot.boot0 passes the execution to BTX's entry
point. BTX then switches the processor to protected mode, and
prepares a simple environment before calling the client. This
includes:virtual v86 mode. That means, the BTX is a v86
monitor. Real mode instructions like posh, popf, cli, sti, if
called by the client, will work.Interrupt Descriptor Table (IDT) is set up so
all hardware interrupts are routed to the default BIOS's
handlers, and interrupt 0x30 is set up to be the syscall
gate.Two system calls: exec and
exit, are defined:sys/boot/i386/btx/lib/btxsys.s:
.set INT_SYS,0x30 # Interrupt number
#
# System call: exit
#
__exit: xorl %eax,%eax # BTX system
int $INT_SYS # call 0x0
#
# System call: exec
#
__exec: movl $0x1,%eax # BTX system
int $INT_SYS # call 0x1BTX creates a Global Descriptor Table (GDT):sys/boot/i386/btx/btx/btx.s:
gdt: .word 0x0,0x0,0x0,0x0 # Null entry
.word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
.word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
.word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
.word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
.word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
.word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
.word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSSThe client's code and data start from address MEM_USR
(0xa000), and a selector (SEL_UCODE) points to the client's code
segment. The SEL_UCODE descriptor has Descriptor Privilege
Level (DPL) 3, which is the lowest privilege level. But the
INT 0x30 instruction handler resides in a
segment pointed to by the SEL_SCODE (supervisor code) selector,
as shown from the code that creates an IDT: mov $SEL_SCODE,%dh # Segment selector
init.2: shr %bx # Handle this int?
jnc init.3 # No
mov %ax,(%di) # Set handler offset
mov %dh,0x2(%di) # and selector
mov %dl,0x5(%di) # Set P:DPL:type
add $0x4,%ax # Next handlerSo, when the client calls __exec(), the
code will be executed with the highest privileges. This allows
the kernel to change the protected mode data structures, such as
page tables, GDT, IDT, etc later, if needed.boot2 defines an important structure,
struct bootinfo. This structure is
initialized by boot2 and passed to the
loader, and then further to the kernel. Some nodes of this
structures are set by boot2, the rest by the
loader. This structure, among other information, contains the
kernel filename, BIOS harddisk geometry, BIOS drive number for
boot device, physical memory available, envp
pointer etc. The definition for it is:/usr/include/machine/bootinfo.h
struct bootinfo {
u_int32_t bi_version;
u_int32_t bi_kernelname; /* represents a char * */
u_int32_t bi_nfs_diskless; /* struct nfs_diskless * */
/* End of fields that are always present. */
#define bi_endcommon bi_n_bios_used
u_int32_t bi_n_bios_used;
u_int32_t bi_bios_geom[N_BIOS_GEOM];
u_int32_t bi_size;
u_int8_t bi_memsizes_valid;
u_int8_t bi_bios_dev; /* bootdev BIOS unit number */
u_int8_t bi_pad[2];
u_int32_t bi_basemem;
u_int32_t bi_extmem;
u_int32_t bi_symtab; /* struct symtab * */
u_int32_t bi_esymtab; /* struct symtab * */
/* Items below only from advanced bootloader */
u_int32_t bi_kernend; /* end of kernel space */
u_int32_t bi_envp; /* environment */
u_int32_t bi_modulep; /* preloaded modules */
};boot2 enters into an infinite loop waiting
for user input, then calls load(). If the
user does not press anything, the loop brakes by a timeout, so
load() will load the default file
(/boot/loader). Functions ino_t
lookup(char *filename) and int xfsread(ino_t
inode, void *buf, size_t nbyte) are used to read the
content of a file into memory. /boot/loader
is an ELF binary, but where the ELF header is prepended with
a.out's struct exec structure.
load() scans the loader's ELF header, loading
the content of /boot/loader into memory, and
passing the execution to the loader's entry:sys/boot/i386/boot2/boot2.c:
__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part),
0, 0, 0, VTOP(&bootinfo));loader stageloader is a BTX client as well.
I will not describe it here in detail, there is a comprehensive
manpage written by Mike Smith, &man.loader.8;. The underlying
mechanisms and BTX were discussed above.The main task for the loader is to boot the kernel. When
the kernel is loaded into memory, it is being called by the
loader:sys/boot/common/boot.c:
/* Call the exec handler from the loader matching the kernel */
module_formats[km->m_loader]->l_exec(km);Kernel initializationTo where exactly is the execution passed by the loader,
i.e. what is the kernel's actual entry point. Let us take a
look at the command that links the kernel:sys/conf/Makefile.i386:
ld -elf -Bdynamic -T /usr/src/sys/conf/ldscript.i386 -export-dynamic \
-dynamic-linker /red/herring -o kernel -X locore.o \
<lots of kernel .o files>A few interesting things can be seen in this line. First,
the kernel is an ELF dynamically linked binary, but the dynamic
linker for kernel is /red/herring, which is
definitely a bogus file. Second, taking a look at the file
sys/conf/ldscript.i386 gives an idea about
what ld options are used when
compiling a kernel. Reading through the first few lines, the
stringsys/conf/ldscript.i386:
ENTRY(btext)says that a kernel's entry point is the symbol `btext'.
This symbol is defined in locore.s:sys/i386/i386/locore.s:
.text
/**********************************************************************
*
* This is where the bootblocks start us, set the ball rolling...
*
*/
NON_GPROF_ENTRY(btext)First what is done is the register EFLAGS is set to a
predefined value of 0x00000002, and then all the segment
registers are initialized:sys/i386/i386/locore.s
/* Don't trust what the BIOS gives for eflags. */
pushl $PSL_KERNEL
popfl
/*
* Don't trust what the BIOS gives for %fs and %gs. Trust the bootstrap
* to set %cs, %ds, %es and %ss.
*/
mov %ds, %ax
mov %ax, %fs
mov %ax, %gsbtext calls the routines
recover_bootinfo(),
identify_cpu(),
create_pagetables(), which are also defined
in locore.s. Here is a description of what
they do:recover_bootinfoThis routine parses the parameters to the kernel
passed from the bootstrap. The kernel may have been
booted in 3 ways: by the loader, described above, by the
old disk boot blocks, and by the old diskless boot
procedure. This function determines the booting method,
and stores the struct bootinfo
structure into the kernel memory.identify_cpuThis functions tries to find out what CPU it is
running on, storing the value found in a variable
_cpu.create_pagetablesThis function allocates and fills out a Page Table
Directory at the top of the kernel memory area.
+
The next steps are enabling VME, if the CPU supports
it: testl $CPUID_VME, R(_cpu_feature)
jz 1f
movl %cr4, %eax
orl $CR4_VME, %eax
movl %eax, %cr4Then, enabling paging:/* Now enable paging */
movl R(_IdlePTD), %eax
movl %eax,%cr3 /* load ptd addr into mmu */
movl %cr0,%eax /* get control word */
orl $CR0_PE|CR0_PG,%eax /* enable paging */
movl %eax,%cr0 /* and let's page NOW! */The next three lines of code are because the paging was set,
so the jump is needed to continue the execution in virtualized
address space: pushl $begin /* jump to high virtualized address */
ret
/* now running relocated at KERNBASE where the system is linked to run */
begin:The function init386() is called, with
a pointer to the first free physical page, after that
mi_startup(). init386
is an architecture dependent initialization function, and
mi_startup() is an architecture independent
one (the 'mi_' prefix stands for Machine Independent). The
kernel never returns from mi_startup(), and
by calling it, the kernel finishes booting:sys/i386/i386/locore.s:
movl physfree, %esi
pushl %esi /* value of first for init386(first) */
call _init386 /* wire 386 chip for unix operation */
call _mi_startup /* autoconfiguration, mountroot etc */
hlt /* never returns to here */init386()init386() is defined in
sys/i386/i386/machdep.c and performs
low-level initialization, specific to the i386 chip. The
switch to protected mode was performed by the loader. The
loader has created the very first task, in which the kernel
continues to operate. Before running straight away to the
code, I will enumerate the tasks the processor must complete
to initialize protected mode execution:Initialize the kernel tunable parameters, passed from
the bootstrapping program.Prepare the GDT.Prepare the IDT.Initialize the system console.Initialize the DDB, if it is compiled into
kernel.Initialize the TSS.Prepare the LDT.Setup proc0's pcb.What init386() first does is
initialize the tunable parameters passed from bootstrap. This
is done by setting the environment pointer (envp) and calling
init_param1(). The envp pointer has been
passed from loader in the bootinfo
structure:sys/i386/i386/machdep.c:
kern_envp = (caddr_t)bootinfo.bi_envp + KERNBASE;
/* Init basic tunables, hz etc */
init_param1();init_param1() is defined in
sys/kern/subr_param.c. That file has a
number of sysctls, and two functions,
init_param1() and
init_param2(), that are called from
init386():sys/kern/subr_param.c
hz = HZ;
TUNABLE_INT_FETCH("kern.hz", &hz);TUNABLE_<typename>_FETCH is used to fetch the value
from the environment:/usr/src/sys/sys/kernel.h
#define TUNABLE_INT_FETCH(path, var) getenv_int((path), (var))
Sysctl kern.hz is the system clock tick. Along with
this, the following sysctls are set by
init_param1(): kern.maxswzone,
kern.maxbcache, kern.maxtsiz, kern.dfldsiz, kern.dflssiz,
kern.maxssiz, kern.sgrowsiz.Then init386() prepares the Global
Descriptors Table (GDT). Every task on an x86 is running in
its own virtual address space, and this space is addressed by
a segment:offset pair. Say, for instance, the current
instruction to be executed by the processor lies at CS:EIP,
then the linear virtual address for that instruction would be
the virtual address of code segment CS + EIP. For
convenience, segments begin at virtual address 0 and end at a
4Gb boundary. Therefore, the instruction's linear virtual
address for this example would just be the value of EIP.
Segment registers such as CS, DS etc are the selectors,
i.e. indexes, into GDT (to be more precise, an index is not a
selector itself, but the INDEX field of a selector).
FreeBSD's GDT holds descriptors for 15 selectors per
CPU:sys/i386/i386/machdep.c:
union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */
sys/i386/include/segments.h:
/*
* Entries in the Global Descriptor Table (GDT)
*/
#define GNULL_SEL 0 /* Null Descriptor */
#define GCODE_SEL 1 /* Kernel Code Descriptor */
#define GDATA_SEL 2 /* Kernel Data Descriptor */
#define GPRIV_SEL 3 /* SMP Per-Processor Private Data */
#define GPROC0_SEL 4 /* Task state process slot zero and up */
#define GLDT_SEL 5 /* LDT - eventually one per process */
#define GUSERLDT_SEL 6 /* User LDT */
#define GTGATE_SEL 7 /* Process task switch gate */
#define GBIOSLOWMEM_SEL 8 /* BIOS low memory access (must be entry 8) */
#define GPANIC_SEL 9 /* Task state to consider panic from */
#define GBIOSCODE32_SEL 10 /* BIOS interface (32bit Code) */
#define GBIOSCODE16_SEL 11 /* BIOS interface (16bit Code) */
#define GBIOSDATA_SEL 12 /* BIOS interface (Data) */
#define GBIOSUTIL_SEL 13 /* BIOS interface (Utility) */
#define GBIOSARGS_SEL 14 /* BIOS interface (Arguments) */Note that those #defines are not selectors themselves, but
just a field INDEX of a selector, so they are exactly the
indices of the GDT. for example, an actual selector for the
kernel code (GCODE_SEL) has the value 0x08.The next step is to initialize the Interrupt Descriptor
Table (IDT). This table is to be referenced by the processor
when a software or hardware interrupt occurs. For example, to
make a system call, user application issues the INT
0x80 instruction. This is a software interrupt, so
the processor's hardware looks up a record with index 0x80 in
the IDT. This record points to the routine that handles this
interrupt, in this particular case, this will be the kernel's
syscall gate. The IDT may have a maximum of 256 (0x100)
records. The kernel allocates NIDT records for the IDT, where
NIDT is the maximum (256):sys/i386/i386/machdep.c:
static struct gate_descriptor idt0[NIDT];
struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */
For each interrupt, an appropriate handler is set. The
syscall gate for INT 0x80 is set as
well:sys/i386/i386/machdep.c:
setidt(0x80, &IDTVEC(int0x80_syscall),
SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL));So when a userland application issues the INT
0x80 instruction, control will transfer to the
function _Xint0x80_syscall, which is in
the kernel code segment and will be executed with supervisor
privileges.Console and DDB are then initialized:sys/i386/i386/machdep.c:
cninit();
/* skipped */
#ifdef DDB
kdb_init();
if (boothowto & RB_KDB)
Debugger("Boot flags requested debugger");
#endifThe Task State Segment is another x86 protected mode
structure, the TSS is used by the hardware to store task
information when a task switch occurs.The Local Descriptors Table is used to reference userland
code and data. Several selectors are defined to point to the
LDT, they are the system call gates and the user code and data
selectors:/usr/include/machine/segments.h
#define LSYS5CALLS_SEL 0 /* forced by intel BCS */
#define LSYS5SIGR_SEL 1
#define L43BSDCALLS_SEL 2 /* notyet */
#define LUCODE_SEL 3
#define LSOL26CALLS_SEL 4 /* Solaris >= 2.6 system call gate */
#define LUDATA_SEL 5
/* separate stack, es,fs,gs sels ? */
/* #define LPOSIXCALLS_SEL 5*/ /* notyet */
#define LBSDICALLS_SEL 16 /* BSDI system call gate */
#define NLDT (LBSDICALLS_SEL + 1)
Next, proc0's Process Control Block (struct
pcb) structure is initialized. proc0 is a
struct proc structure that describes a kernel
process. It is always present while the kernel is running,
therefore it is declared as global:sys/kern/kern_init.c:
struct proc proc0;The structure struct pcb is a part of a
proc structure. It is defined in
/usr/include/machine/pcb.h and has a
process's information specific to the i386 architecture, such as
registers values.mi_startup()This function performs a bubble sort of all the system
initialization objects and then calls the entry of each object
one by one:sys/kern/init_main.c:
for (sipp = sysinit; *sipp; sipp++) {
/* ... skipped ... */
/* Call function */
(*((*sipp)->func))((*sipp)->udata);
/* ... skipped ... */
}Although the sysinit framework is described in the
Developers' Handbook, I will discuss the internals of it.Every system initialization object (sysinit object) is
created by calling a SYSINIT() macro. Let us take as example an
announce sysinit object. This object prints
the copyright message:sys/kern/init_main.c:
static void
print_caddr_t(void *data __unused)
{
printf("%s", (char *)data);
}
SYSINIT(announce, SI_SUB_COPYRIGHT, SI_ORDER_FIRST, print_caddr_t, copyright)The subsystem ID for this object is SI_SUB_COPYRIGHT
(0x0800001), which comes right after the SI_SUB_CONSOLE
(0x0800000). So, the copyright message will be printed out
first, just after the console initialization.Let us take a look at what exactly the macro
SYSINIT() does. It expands to a
C_SYSINIT() macro. The
C_SYSINIT() macro then expands to a static
struct sysinit structure declaration with
another DATA_SET macro call:/usr/include/sys/kernel.h:
#define C_SYSINIT(uniquifier, subsystem, order, func, ident) \
static struct sysinit uniquifier ## _sys_init = { \ subsystem, \
order, \ func, \ ident \ }; \ DATA_SET(sysinit_set,uniquifier ##
_sys_init);
#define SYSINIT(uniquifier, subsystem, order, func, ident) \
C_SYSINIT(uniquifier, subsystem, order, \
(sysinit_cfunc_t)(sysinit_nfunc_t)func, (void *)ident)The DATA_SET() macro expands to a
MAKE_SET(), and that macro is the point where
the all sysinit magic is hidden:/usr/include/linker_set.h
#define MAKE_SET(set, sym) \
static void const * const __set_##set##_sym_##sym = &sym; \
__asm(".section .set." #set ",\"aw\""); \
__asm(".long " #sym); \
__asm(".previous")
#endif
#define TEXT_SET(set, sym) MAKE_SET(set, sym)
#define DATA_SET(set, sym) MAKE_SET(set, sym)In our case, the following declaration will occur:static struct sysinit announce_sys_init = {
SI_SUB_COPYRIGHT,
SI_ORDER_FIRST,
(sysinit_cfunc_t)(sysinit_nfunc_t) print_caddr_t,
(void *) copyright
};
static void const *const __set_sysinit_set_sym_announce_sys_init =
&announce_sys_init;
__asm(".section .set.sysinit_set" ",\"aw\"");
__asm(".long " "announce_sys_init");
__asm(".previous");The first __asm instruction will create
an ELF section within the kernel's executable. This will happen
at kernel link time. The section will have the name
.set.sysinit_set. The content of this section is one 32-bit
value, the address of announce_sys_init structure, and that is
what the second __asm is. The third
__asm instruction marks the end of a section.
If a directive with the same section name occurred before, the
content, i.e. the 32-bit value, will be appended to the existing
section, so forming an array of 32-bit pointers.Running objdump on a kernel
binary, you may notice the presence of such small
sections:&prompt.user; objdump -h /kernel
7 .set.cons_set 00000014 c03164c0 c03164c0 002154c0 2**2
CONTENTS, ALLOC, LOAD, DATA
8 .set.kbddriver_set 00000010 c03164d4 c03164d4 002154d4 2**2
CONTENTS, ALLOC, LOAD, DATA
9 .set.scrndr_set 00000024 c03164e4 c03164e4 002154e4 2**2
CONTENTS, ALLOC, LOAD, DATA
10 .set.scterm_set 0000000c c0316508 c0316508 00215508 2**2
CONTENTS, ALLOC, LOAD, DATA
11 .set.sysctl_set 0000097c c0316514 c0316514 00215514 2**2
CONTENTS, ALLOC, LOAD, DATA
12 .set.sysinit_set 00000664 c0316e90 c0316e90 00215e90 2**2
CONTENTS, ALLOC, LOAD, DATAThis screen dump shows that the size of .set.sysinit_set
section is 0x664 bytes, so 0x664/sizeof(void
*) sysinit objects are compiled into the kernel. The
other sections such as .set.sysctl_set
represent other linker sets.By defining a variable of type struct
linker_set the content of
.set.sysinit_set section will be collected
into that variable:sys/kern/init_main.c:
extern struct linker_set sysinit_set; /* XXX */The struct linker_set is defined as
follows:/usr/include/linker_set.h:
struct linker_set {
int ls_length;
void *ls_items[1]; /* really ls_length of them, trailing NULL */
};The first node will be equal to the number of a sysinit
objects, and the second node will be a NULL-terminated array of
pointers to them.Returning to the mi_startup()
discussion, it is must be clear now, how the sysinit objects are
being organized. The mi_startup() function
sorts them and calls each. The very last object is the system
scheduler:/usr/include/sys/kernel.h:
enum sysinit_sub_id {
SI_SUB_DUMMY = 0x0000000, /* not executed; for linker*/
SI_SUB_DONE = 0x0000001, /* processed*/
SI_SUB_CONSOLE = 0x0800000, /* console*/
SI_SUB_COPYRIGHT = 0x0800001, /* first use of console*/
...
SI_SUB_RUN_SCHEDULER = 0xfffffff /* scheduler: no return*/
};The system scheduler sysinit object is defined in the file
sys/vm/vm_glue.c, and the entry point for
that object is scheduler(). That function
is actually an infinite loop, and it represents a process with
PID 0, the swapper process. The proc0 structure, mentioned
before, is used to describe it.The first user process, called init, is
created by the sysinit object init:sys/kern/init_main.c:
static void
create_init(const void *udata __unused)
{
int error;
int s;
s = splhigh();
error = fork1(&proc0, RFFDG | RFPROC, &initproc);
if (error)
panic("cannot fork init: %d\n", error);
initproc->p_flag |= P_INMEM | P_SYSTEM;
cpu_set_fork_handler(initproc, start_init, NULL);
remrunqueue(initproc);
splx(s);
}
SYSINIT(init,SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL)The create_init() allocates a new process
by calling fork1(), but does not mark it
runnable. When this new process is scheduled for execution by the
scheduler, the start_init() will be called.
That function is defined in init_main.c. It
tries to load and exec the init binary,
probing /sbin/init first, then
/sbin/oinit,
/sbin/init.bak, and finally
/stand/sysinstall:sys/kern/init_main.c:
static char init_path[MAXPATHLEN] =
#ifdef INIT_PATH
__XSTRING(INIT_PATH);
#else
"/sbin/init:/sbin/oinit:/sbin/init.bak:/stand/sysinstall";
#endif
diff --git a/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml
index f792cbd338..5bf43c7833 100644
--- a/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml
+++ b/en_US.ISO8859-1/books/arch-handbook/jail/chapter.sgml
@@ -1,597 +1,597 @@
EvanSarmientoevms@cs.bu.edu2001Evan SarmientoThe Jail SubsystemOn most UNIX systems, root has omnipotent power. This promotes
insecurity. If an attacker were to gain root on a system, he would
have every function at his fingertips. In FreeBSD there are
sysctls which dilute the power of root, in order to minimize the
damage caused by an attacker. Specifically, one of these functions
is called secure levels. Similarly, another function which is
present from FreeBSD 4.0 and onward, is a utility called
&man.jail.8;. Jail chroots an
environment and sets certain restrictions on processes which are
forked from within. For example, a jailed process cannot affect
processes outside of the jail, utilize certain system calls, or
inflict any damage on the main computer.Jail is becoming the new security
model. People are running potentially vulnerable servers such as
Apache, BIND, and sendmail within jails, so that if an attacker
gains root within the Jail, it is only
an annoyance, and not a devastation. This article focuses on the
internals (source code) of Jail.
It will also suggest improvements upon the jail code base which
are already being worked on. If you are looking for a how-to on
setting up a Jail, I suggest you look
at my other article in Sys Admin Magazine, May 2001, entitled
"Securing FreeBSD using Jail."ArchitectureJail consists of two realms: the
user-space program, jail, and the code implemented within the
kernel: the jail() system call and associated
restrictions. I will be discussing the user-space program and
then how jail is implemented within the kernel.Userland codeThe source for the user-land jail is located in
/usr/src/usr.sbin/jail, consisting of
one file, jail.c. The program takes these
arguments: the path of the jail, hostname, ip address, and the
command to be executed.Data StructuresIn jail.c, the first thing I would
note is the declaration of an important structure
struct jail j; which was included from
- /usr/include/sys/jail.h.
+ /usr/include/sys/jail.h.The definition of the jail structure is:/usr/include/sys/jail.h:
struct jail {
u_int32_t version;
char *path;
char *hostname;
u_int32_t ip_number;
};As you can see, there is an entry for each of the
arguments passed to the jail program, and indeed, they are
set during it's execution./usr/src/usr.sbin/jail.c
j.version = 0;
j.path = argv[1];
j.hostname = argv[2];NetworkingOne of the arguments passed to the Jail program is an IP
address with which the jail can be accessed over the
network. Jail translates the ip address given into network
byte order and then stores it in j (the jail structure)./usr/src/usr.sbin/jail/jail.c:
struct in.addr in;
...
i = inet.aton(argv[3], );
...
j.ip_number = ntohl(in.s.addr);The
inet_aton3
function "interprets the specified character string as an
Internet address, placing the address into the structure
provided." The ip number node in the jail structure is set
only when the ip address placed onto the in structure by
inet aton is translated into network byte order by
ntohl().Jailing The ProcessFinally, the userland program jails the process, and
executes the command specified. Jail now becomes an
imprisoned process itself and forks a child process which
- then executes the command given using &man.execv.3;
+ then executes the command given using &man.execv.3;/usr/src/sys/usr.sbin/jail/jail.c
i = jail();
...
i = execv(argv[4], argv + 4);As you can see, the jail function is being called, and
its argument is the jail structure which has been filled
with the arguments given to the program. Finally, the
program you specify is executed. I will now discuss how Jail
is implemented within the kernel.Kernel SpaceWe will now be looking at the file
/usr/src/sys/kern/kern_jail.c. This is
the file where the jail system call, appropriate sysctls, and
networking functions are defined.sysctlsIn kern_jail.c, the following
sysctls are defined:/usr/src/sys/kern/kern_jail.c:
int jail_set_hostname_allowed = 1;
SYSCTL_INT(_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
_set_hostname_allowed, 0,
"Processes in jail can set their hostnames");
int jail_socket_unixiproute_only = 1;
SYSCTL_INT(_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
_socket_unixiproute_only, 0,
"Processes in jail are limited to creating UNIX/IPv4/route sockets only
");
int jail_sysvipc_allowed = 0;
SYSCTL_INT(_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
_sysvipc_allowed, 0,
"Processes in jail can use System V IPC primitives");Each of these sysctls can be accessed by the user
through the sysctl program. Throughout the kernel, these
specific sysctls are recognized by their name. For example,
the name of the first sysctl is
jail.set.hostname.allowed.&man.jail.2; system callLike all system calls, the &man.jail.2; system call takes
two arguments, struct proc *p and
struct jail_args
*uap. p is a pointer to a proc
structure which describes the calling process. In this
context, uap is a pointer to a structure which specifies the
arguments given to &man.jail.2; from the userland program
jail.c. When I described the userland
program before, you saw that the &man.jail.2; system call was
given a jail structure as its own argument./usr/src/sys/kern/kern_jail.c:
int
jail(p, uap)
struct proc *p;
struct jail_args /* {
syscallarg(struct jail *) jail;
} */ *uap;Therefore, uap->jail would access the
jail structure which was passed to the system call. Next,
the system call copies the jail structure into kernel space
using the copyin()
function. copyin() takes three arguments:
the data which is to be copied into kernel space,
uap->jail, where to store it,
j and the size of the storage. The jail
structure uap->jail is copied into kernel
space and stored in another jail structure,
j./usr/src/sys/kern/kern_jail.c:
error = copyin(uap->jail, , sizeof j);There is another important structure defined in
jail.h. It is the prison structure
(pr). The prison structure is used
exclusively within kernel space. The &man.jail.2; system call
copies everything from the jail structure onto the prison
structure. Here is the definition of the prison structure./usr/include/sys/jail.h:
struct prison {
int pr_ref;
char pr_host[MAXHOSTNAMELEN];
u_int32_t pr_ip;
void *pr_linux;
};The jail() system call then allocates memory for a
pointer to a prison structure and copies data between the two
structures./usr/src/sys/kern/kern_jail.c:
MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK);
bzero((caddr_t)pr, sizeof *pr);
error = copyinstr(j.hostname, pr_host]]>, sizeof pr->pr_host, 0);
if (error)
goto bail;Finally, the jail system call chroots the path
specified. The chroot function is given two arguments. The
first is p, which represents the calling process, the second
is a pointer to the structure chroot args. The structure
chroot args contains the path which is to be chrooted. As
you can see, the path specified in the jail structure is
copied to the chroot args structure and used./usr/src/sys/kern/kern_jail.c:
ca.path = j.path;
error = chroot(p, );These next three lines in the source are very important,
as they specify how the kernel recognizes a process as
jailed. Each process on a Unix system is described by its
own proc structure. You can see the whole proc structure in
/usr/include/sys/proc.h. For example,
the p argument in any system call is actually a pointer to
that process' proc structure, as stated before. The proc
structure contains nodes which can describe the owner's
identity (p_cred), the process resource
limits (p_limit), and so on. In the
definition of the process structure, there is a pointer to a
prison structure. (p_prison)./usr/include/sys/proc.h:
struct proc {
...
struct prison *p_prison;
...
};In kern_jail.c, the function then
copies the pr structure, which is filled with all the
information from the original jail structure, over to the
p->p_prison structure. It then does a
bitwise OR of p->p_flag with the constant
P_JAILED, meaning that the calling
process is now recognized as jailed. The parent process of
each process, forked within the jail, is the program jail
itself, as it calls the &man.jail.2; system call. When the
program is executed through execve, it inherits the
properties of its parents proc structure, therefore it has
the p->p_flag set, and the
p->p_prison structure is filled./usr/src/sys/kern/kern_jail.c
p->p.prison = pr;
p->p.flag |= P.JAILED;When a process is forked from a parent process, the
&man.fork.2; system call deals differently with imprisoned
processes. In the fork system call, there are two pointers
to a proc structure p1
and p2. p1 points to
the parent's proc structure and p2 points
to the child's unfilled proc
structure. After copying all relevant data between the
structures, &man.fork.2; checks if the structure
p->p_prison is filled on
p2. If it is, it increments the
pr.ref by one, and sets the
p_flag to one on the child process./usr/src/sys/kern/kern_fork.c:
if (p2->p_prison) {
p2->p_prison->pr_ref++;
p2->p_flag |= P_JAILED;
}RestrictionsThroughout the kernel there are access restrictions relating
to jailed processes. Usually, these restrictions only check if
the process is jailed, and if so, returns an error. For
example:if (p->p_prison)
return EPERM;SysV IPCSystem V IPC is based on messages. Processes can send each
other these messages which tell them how to act. The functions
which deal with messages are: msgsys,
msgctl, msgget,
msgsend and msgrcv.
Earlier, I mentioned that there were certain sysctls you could
turn on or off in order to affect the behavior of Jail. One of
these sysctls was jail_sysvipc_allowed. On
most systems, this sysctl is set to 0. If it were set to 1, it
would defeat the whole purpose of having a jail; privleged
users from within the jail would be able to affect processes
outside of the environment. The difference between a message
and a signal is that the message only consists of the signal
number./usr/src/sys/kern/sysv_msg.c:&man.msgget.3;: msgget returns (and possibly
creates) a message descriptor that designates a message queue
for use in other system calls.&man.msgctl.3;: Using this function, a process
can query the status of a message
descriptor.&man.msgsnd.3;: msgsnd sends a message to a
process.&man.msgrcv.3;: a process receives messages using
this functionIn each of these system calls, there is this
conditional:/usr/src/sys/kern/sysv msg.c:
if (!jail.sysvipc.allowed && p->p_prison != NULL)
return (ENOSYS);Semaphore system calls allow processes to synchronize
execution by doing a set of operations atomically on a set of
semaphores. Basically semaphores provide another way for
processes lock resources. However, process waiting on a
semaphore, that is being used, will sleep until the resources
are relinquished. The following semaphore system calls are
blocked inside a jail: semsys,
semget, semctl and
semop./usr/src/sys/kern/sysv_sem.c:&man.semctl.2;(id, num, cmd, arg):
Semctl does the specified cmd on the semaphore queue
indicated by id.&man.semget.2;(key, nsems, flag):
Semget creates an array of semaphores, corresponding to
key.Key and flag take on the same meaning as they
do in msgget.&man.semop.2;(id, ops, num):
Semop does the set of semaphore operations in the array of
structures ops, to the set of semaphores identified by
id.System V IPC allows for processes to share
memory. Processes can communicate directly with each other by
sharing parts of their virtual address space and then reading
and writing data stored in the shared memory. These system
calls are blocked within a jailed environment: shmdt,
shmat, oshmctl, shmctl, shmget, and
shmsys./usr/src/sys/kern/sysv shm.c:&man.shmctl.2;(id, cmd, buf):
shmctl does various control operations on the shared memory
region identified by id.&man.shmget.2;(key, size,
flag): shmget accesses or creates a shared memory
region of size bytes.&man.shmat.2;(id, addr, flag):
shmat attaches a shared memory region identified by id to the
address space of a process.&man.shmdt.2;(addr): shmdt
detaches the shared memory region previously attached at
addr.SocketsJail treats the &man.socket.2; system call and related
lower-level socket functions in a special manner. In order to
determine whether a certain socket is allowed to be created,
it first checks to see if the sysctl
jail.socket.unixiproute.only is set. If
set, sockets are only allowed to be created if the family
specified is either PF_LOCAL,
PF_INET or
PF_ROUTE. Otherwise, it returns an
error./usr/src/sys/kern/uipc_socket.c:
int socreate(dom, aso, type, proto, p)
...
register struct protosw *prp;
...
{
if (p->p_prison && jail_socket_unixiproute_only &&
prp->pr_domain->dom_family != PR_LOCAL && prp->pr_domain->dom_family != PF_INET
&& prp->pr_domain->dom_family != PF_ROUTE)
return (EPROTONOSUPPORT);
...
}Berkeley Packet FilterThe Berkeley Packet Filter provides a raw interface to
data link layers in a protocol independent fashion. The
function bpfopen() opens an Ethernet
device. There is a conditional which disallows any jailed
processes from accessing this function./usr/src/sys/net/bpf.c:
static int bpfopen(dev, flags, fmt, p)
...
{
if (p->p_prison)
return (EPERM);
...
}ProtocolsThere are certain protocols which are very common, such as
TCP, UDP, IP and ICMP. IP and ICMP are on the same level: the
network layer 2. There are certain precautions which are
taken in order to prevent a jailed process from binding a
protocol to a certain port only if the nam
parameter is set. nam is a pointer to a sockaddr structure,
which describes the address on which to bind the service. A
more exact definition is that sockaddr "may be used as a
template for reffering to the identifying tag and length of
each address"[2]. In the function in
pcbbind, sin is a
pointer to a sockaddr.in structure, which contains the port,
address, length and domain family of the socket which is to be
bound. Basically, this disallows any processes from jail to be
able to specify the domain family./usr/src/sys/kern/netinet/in_pcb.c:
int in.pcbbind(int, nam, p)
...
struct sockaddr *nam;
struct proc *p;
{
...
struct sockaddr.in *sin;
...
if (nam) {
sin = (struct sockaddr.in *)nam;
...
if (sin->sin_addr.s_addr != INADDR_ANY)
if (prison.ip(p, 0, ->sin.addr.s_addr))
return (EINVAL);
....
}
...
}You might be wondering what function
prison_ip() does. prison.ip is given three
arguments, the current process (represented by
p), any flags, and an ip address. It
returns 1 if the ip address belongs to a jail or 0 if it does
not. As you can see from the code, if it is indeed an ip
address belonging to a jail, the protcol is not allowed to
bind to a certain port./usr/src/sys/kern/kern_jail.c:
int prison_ip(struct proc *p, int flag, u_int32_t *ip) {
u_int32_t tmp;
if (!p->p_prison)
return (0);
if (flag)
tmp = *ip;
else tmp = ntohl (*ip);
if (tmp == INADDR_ANY) {
if (flag)
*ip = p->p_prison->pr_ip;
else *ip = htonl(p->p_prison->pr_ip);
return (0);
}
if (p->p_prison->pr_ip != tmp)
return (1);
return (0);
}Jailed users are not allowed to bind services to an ip
which does not belong to the jail. The restriction is also
written within the function in_pcbbind:/usr/src/sys/net inet/in_pcb.c
if (nam) {
...
lport = sin->sin.port;
... if (lport) {
...
if (p && p->p_prison)
prison = 1;
if (prison &&
prison_ip(p, 0, ->sin_addr.s_addr))
return (EADDRNOTAVAIL);FilesystemEven root users within the jail are not allowed to set any
file flags, such as immutable, append, and no unlink flags, if
the securelevel is greater than 0./usr/src/sys/ufs/ufs/ufs_vnops.c:
int ufs.setattr(ap)
...
{
if ((cred->cr.uid == 0) && (p->prison == NULL)) {
if ((ip->i_flags
& (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) &&
securelevel > 0)
return (EPERM);
}
diff --git a/en_US.ISO8859-1/books/arch-handbook/mac/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/mac/chapter.sgml
index ccd16eaf70..1946e991c0 100644
--- a/en_US.ISO8859-1/books/arch-handbook/mac/chapter.sgml
+++ b/en_US.ISO8859-1/books/arch-handbook/mac/chapter.sgml
@@ -1,7819 +1,7821 @@
ChrisCostelloTrustedBSD Projectchris@FreeBSD.orgRobertWatsonTrustedBSD Projectrwatson@FreeBSD.orgThe TrustedBSD MAC FrameworkMAC Documentation CopyrightThis documentation was developed for the FreeBSD Project by
Chris Costello at Safeport Network Services and Network
Associates Laboratories, the Security Research Division of
Network Associates, Inc. under DARPA/SPAWAR contract
N66001-01-C-8035 (CBOSS), as part of the DARPA
CHATS research program.Redistribution and use in source (SGML DocBook) and
'compiled' forms (SGML, HTML, PDF, PostScript, RTF and so forth)
with or without modification, are permitted provided that the
following conditions are met:Redistributions of source code (SGML DocBook) must
retain the above copyright notice, this list of conditions
and the following disclaimer as the first lines of this file
unmodified.Redistributions in compiled form (transformed to other
DTDs, converted to PDF, PostScript, RTF and other formats)
must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation
and/or other materials provided with the
distribution.THIS DOCUMENTATION IS PROVIDED BY THE NETWORKS ASSOCIATES
TECHNOLOGY, INC "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL NETWORKS ASSOCIATES TECHNOLOGY,
INC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.SynopsisFreeBSD includes experimental support for several
mandatory access control policies, as well as a framework
for kernel security extensibility, the TrustedBSD MAC
Framework. The MAC Framework provides a pluggable access
control framework, permitting new security policies to
be easily linked into the kernel, loaded at boot, or loaded
dynamically at run-time. The framework provides a variety
of features to make it easier to implement new policies,
including the ability to easily tag security labels (such as
confidentiality information) onto system objects.This chapter introduces the MAC policy framework and
provides documentation for a sample MAC policy module.IntroductionThe TrustedBSD MAC framework provides a mechanism to allow
the compile-time or run-time extension of the kernel access
control model. New system policies may be implemented as
kernel modules and linked to the kernel; if multiple policy
modules are present, their results will be composed. The
MAC Framework provides a variety of access control infrastructure
services to assist policy writers, including support for
transient and persistent policy-agnostic object security
labels. This support is currently considered experimental.Policy BackgroundMandatory Access Control (MAC), refers to a set of
access control policies that are mandatorily enforced on
users by the operating system. MAC policies may be contrasted
with Discretionary Access Control (DAC) protections, by which
non-administrative users may (at their discretion) protect
objects. In traditional UNIX systems, DAC protections include
file permissions and access control lists; MAC protections include
process controls preventing inter-user debugging and firewalls.
A variety of MAC policies have been formulated by operating system
designers and security researches, including the Multi-Level
Security (MLS) confidentiality policy, the Biba integrity policy,
Role-Based Access Control (RBAC), and Type Enforcement (TE). Each
model bases decisions on a variety of factors, including user
identity, role, and security clearance, as well as security labels
on objects representing concepts such as data sensitivity and
integrity.The TrustedBSD MAC Framework is capable of supporting policy
modules that implement all of these policies, as well as a broad
class of system hardening policies. In addition, despite the
name, the MAC Framework can also be used to implement purely
discretionary policies, as policy modules are given substantial
flexibility in how they authorize protections.MAC Framework Kernel ArchitectureThe TrustedBSD MAC Framework permits kernel modules to
extend the operating system security policy, as well as
providing infrastructure functionality required by many
access control modules. If multiple policies are
simultaneously loaded, the MAC Framework will usefully (for
some definition of useful) compose the results of the
policies.Kernel ElementsThe MAC Framework contains a number of kernel elements:Framework management interfacesConcurrency and synchronization
primitives.Policy registrationExtensible security label for kernel
objectsPolicy entry point composition
operatorsLabel management primitivesEntry point API invoked by kernel
servicesEntry point API to policy modulesEntry points implementations (policy life cycle,
object life cycle/label management, access control
checks).Policy-agnostic label-management system
callsmac_syscall() multiplex
system callVarious security policies implemented as MAC
policy modulesManagement InterfacesThe TrustedBSD MAC Framework may be directly managed using
sysctls, loader tunables, and system calls.In most cases, sysctls and loader tunables modify the same
parameters, and control behavior such as enforcement of
protections relating to various kernel subsystems. In addition,
if MAC debugging support is compiled into the kernel, a variety
of counters will be maintained tracking label allocation. In
most cases, it is advised that per-subsystem enforcement
controls not be used to control policy behavior in production
environments, as they broadly impact the operation of all
active policies. Instead, per-policy controls should be
preferred to ensure proper policy operation.Loading and unloading of policy modules is performed
using the system module management system calls and other
system interfaces, including loader variables.Concurrency and SynchronizationAs the set of active policies may change at run-time,
and the invocation of entry points is non-atomic,
synchronization is required to prevent unloading or
loading of new policies while an entry point invocation
is progress, freezing the list of policies for the
duration. This is accomplished by means of a Framework
busy count. Whenever an entry point is entered, the
busy count is incremented; whenever it is exited, the
busy count is decremented. While the busy count is
elevated, policy list changes are not permitted, and
threads attempting to modify the policy list will sleep
until the list is not busy. The busy count is protected
by a mutex, and a condition variable is used to wake up
sleepers waiting on policy list modifications.Various optimizations are used to reduce the overhead
of the busy count, including avoiding the full cost of
incrementing and decrementing if the list is empty or
contains only static entries (policies that are loaded
before the system starts, and cannot be unloaded).Policy RegistrationThe MAC Framework maintains two lists of active
policies: a static list, and a dynamic list. The lists
differ only with regards to their locking semantics: an
elevated reference count is not required to make use of
the static list. When kernel modules containing MAC
Framework policies are loaded, the policy module will
use SYSINIT to invoke a registration
function; when a policy module is unloaded,
SYSINIT will likewise invoke a
de-registration function. Registration may fail if a
policy module is loaded more than once, if insufficient
resources are available for the registration (for
example, the policy might require labeling and
insufficient labeling state might be available), or
other policy prerequisites might not be met (some
policies may only be loaded prior to boot). Likewise,
de-registration may fail if a policy refuses an
unload.Entry PointsKernel services interact with the MAC Framework in two ways:
they invoke a series of APIs to notify the framework of relevant
events, and they a policy-agnostic label structure in
security-relevant objects. This label structure is maintained by
the MAC Framework via label management entry points, and permits
the Framework to offer a labeling service to policy modules
through relatively non-invasive changes to the kernel subsystem
maintaining the object. For example, label structures have been
added to processes, process credentials, sockets, pipes, vnodes,
Mbufs, network interfaces, IP reassembly queues, and a variety
of other security-relevant structures. Kernel services also
invoke the MAC Framework when they perform important security
decisions, permitting policy modules to augment those decisions
based on their own criteria (possibly including data stored in
security labels).Policy CompositionWhen more than one policy module is loaded into the kernel
at a time, the results of the policy modules will be composed
by the framework using a composition operator. This operator
is currently hard-coded, and requires that all active policies
must approve a request for it to occur. As policies may
return a variety of error conditions (success, access denied,
object doesn't exist, ...), a precedence operator selects the
resulting error from the set of errors returned by policies.
While it is not guaranteed that the resulting composition will
be useful or secure, we've found that it is for many useful
selections of policies.Labeling SupportAs many interesting access control extensions rely on
security labels on objects, the MAC Framework provides a set
of policy-agnostic label management system calls covering
a variety of user-exposed objects. Common label types
include partition identifiers, sensitivity labels, integrity
labels, compartments, domains, roles, and types. Policy
modules participate in the internalization and externalization
of string-based labels provides by user applications, and can
expose multiple label elements to applications if desired.In-memory labels are stored in struct
label, which consists of a fixed-length array
of unions, each holding a void * pointer
and a long. Policies registering for
label storage will be assigned a "slot" identifier, which
may be used to dereference the label storage. The semantics
of the storage are left entirely up to the policy module:
modules are provided with a variety of entry points
associated with the kernel object life cycle, including
initialization, association/creation, and destruction. Using
these interfaces, it is possible to implement reference
counting and other storage mechanisms. Direct access to
the kernel object is generally not required by policy
modules to retrieve a label, as the MAC Framework generally
passes both a pointer to the object and a direct pointer
to the object's label into entry points.Initialization entry points frequently include a blocking
disposition flag indicating whether or not an initialization
is permitted to block; if blocking is not permitted, a failure
may be returned to cancel allocation of the label. This may
occur, for example, in the network stack during interrupt
handling, where blocking is not permitted. Due to the
performance cost of maintaining labels on in-flight network
packets (Mbufs), policies must specifically declare a
requirement that Mbuf labels be allocated. Dynamically
loaded policies making use of labels must be able to handle
the case where their init function has not been called on
an object, as objects may already exist when the policy is
loaded.In the case of file system labels, special support is
provided for the persistent storage of security labels in
extended attributes. Where available, EA transactions
are used to permit consistent compound updates of
security labels on vnodes.Currently, if a labeled policy permits dynamic
unloading, its state slot cannot be reclaimed.System CallsThe MAC Framework implements a number of system calls:
most of these calls support the policy-agnostic label
retrieval and manipulation APIs exposed to user
applications.The label management calls accept a label description
structure, struct mac, which
contains a series of MAC label elements. Each element
contains a character string name, and character string
value. Each policy will be given the chance to claim a
particular element name, permitting policies to expose
multiple independent elements if desired. Policy modules
perform the internalization and externalization between
kernel labels and user-provided labels via entry points,
permitting a variety of semantics. Label management system
calls are generally wrapped by user library functions to
perform memory allocation and error handling.In addition, mac_syscall()
permits policy modules to create new system calls without
allocating system calls. mac_execve()
permits an atomic process credential label change when
executing a new image.MAC Policy ArchitectureSecurity policies are either linked directly into the kernel,
or compiled into loadable kernel modules that may be loaded at
boot, or dynamically using the module loading system calls at
runtime. Policy modules interact with the system through a
set of declared entry points, providing access to a stream of
system events and permitting the policy to influence access
control decisions. Each policy contains a number of elements:Optional configuration parameters for
policy.Centralized implementation of the policy
logic and parameters.Optional implementation of policy life cycle
events, such as initialization and destruction.Optional support for initializing, maintaining, and
destroying labels on selected kernel objects.Optional support for user process inspection and
modification of labels on selected objects.Implementation of selected access control
entry points that are of interest to the policy.Declaration of policy identity, module entry
points, and policy properties.Policy DeclarationModules may be declared using the
MAC_POLICY_SET() macro, which names the
policy, provides a reference to the MAC entry point vector,
provides load-time flags determining how the policy framework
should handle the policy, and optionally requests the
allocation of label state by the framework.static struct mac_policy_ops mac_policy_ops =
{
.mpo_destroy = mac_policy_destroy,
.mpo_init = mac_policy_init,
.mpo_init_bpfdesc_label = mac_policy_init_bpfdesc_label,
.mpo_init_cred_label = mac_policy_init_label,
/* ... */
.mpo_check_vnode_setutimes = mac_policy_check_vnode_setutimes,
.mpo_check_vnode_stat = mac_policy_check_vnode_stat,
.mpo_check_vnode_write = mac_policy_check_vnode_write,
};The MAC policy entry point vector,
mac_policy_ops in this example, associates
functions defined in the module with specific entry points. A
complete listing of available entry points and their
prototypes may be found in the MAC entry point reference
section. Of specific interest during module registration are
the .mpo_destroy and .mpo_init
entry points. .mpo_init will be invoked once a
policy is successfully registered with the module framework
but prior to any other entry points becoming active. This
permits the policy to perform any policy-specific allocation
and initialization, such as initialization of any data or
locks. .mpo_destroy will be invoked when a
policy module is unloaded to permit releasing of any allocated
memory and destruction of locks. Currently, these two entry
points are invoked with the MAC policy list mutex held to
prevent any other entry points from being invoked: this will
be changed, but in the mean time, policies should be careful
about what kernel primitives they invoke so as to avoid lock
ordering or sleeping problems.The policy declaration's module name field exists so that
the module may be uniquely identified for the purposes of
module dependencies. An appropriate string should be selected.
The full string name of the policy is displayed to the user
via the kernel log during load and unload events, and also
exported when providing status information to userland
processes.Policy FlagsThe policy declaration flags field permits the module to
provide the framework with information about its capabilities at
the time the module is loaded. Currently, three flags are
defined:MPC_LOADTIME_FLAG_UNLOADOKThis flag indicates that the policy module may be
unloaded. If this flag is not provided, then the policy
framework will reject requests to unload the module.
This flag might be used by modules that allocate label
state and are unable to free that state at
runtime.MPC_LOADTIME_FLAG_NOTLATEThis flag indicates that the policy module
must be loaded and initialized early in the boot
process. If the flag is specified, attempts to register
the module following boot will be rejected. The flag
may be used by policies that require pervasive labeling
of all system objects, and cannot handle objects that
have not been properly initialized by the policy.MPC_LOADTIME_FLAG_LABELMBUFSThis flag indicates that the policy module requires
labeling of Mbufs, and that memory should always be
allocated for the storage of Mbuf labels. By default,
the MAC Framework will not allocate label storage for
Mbufs unless at least one loaded policy has this flag
set. This measurably improves network performance when
policies do not require Mbuf labeling. A kernel option,
MAC_ALWAYS_LABEL_MBUF, exists to
force the MAC Framework to allocate Mbuf label storage
regardless of the setting of this flag, and may be
useful in some environments.Policies using the
MPC_LOADTIME_FLAG_LABELMBUFS without the
MPC_LOADTIME_FLAG_NOTLATE flag set
must be able to correctly handle NULL
Mbuf label pointers passed into entry points. This is necessary
as in-flight Mbufs without label storage may persist after a
policy enabling Mbuf labeling has been loaded. If a policy
is loaded before the network subsystem is active (i.e., the
policy is not being loaded late), then all Mbufs are guaranteed
to have label storage.Policy Entry PointsFour classes of entry points are offered to policies
registered with the framework: entry points associated with
the registration and management of policies, entry points
denoting initialization, creation, destruction, and other life
cycle events for kernel objects, events associated with access
control decisions that the policy module may influence, and
calls associated with the management of labels on objects. In
addition, a mac_syscall() entry point is
provided so that policies may extend the kernel interface
without registering new system calls.Policy module writers should be aware of the kernel
locking strategy, as well as what object locks are available
during which entry points. Writers should attempt to avoid
deadlock scenarios by avoiding grabbing non-leaf locks inside
of entry points, and also follow the locking protocol for
object access and modification. In particular, writers should
be aware that while necessary locks to access objects and
their labels are generally held, sufficient locks to modify an
object or its label may not be present for all entry points.
Locking information for arguments is documented in the MAC
framework entry point document.Policy entry points will pass a reference to the object
label along with the object itself. This permits labeled
policies to be unaware of the internals of the object yet
still make decisions based on the label. The exception to this
is the process credential, which is assumed to be understood
by policies as a first class security object in the kernel.
Policies that do not implement labels on kernel objects will
be passed NULL pointers for label arguments to entry
points.MAC Policy Entry Point ReferenceGeneral-Purpose Module Entry Points&mac.mpo;_initvoid
&mac.mpo;_initstruct mac_policy_conf
*conf
&mac.thead;
confMAC policy definitionPolicy load event. The policy list mutex is held, so
caution should be applied.&mac.mpo;_destroyvoid
&mac.mpo;_destroystruct mac_policy_conf
*conf
&mac.thead;
confMAC policy definitionPolicy load event. The policy list mutex is held, so
caution should be applied.&mac.mpo;_syscallint
&mac.mpo;_syscallstruct thread
*tdint callvoid *arg
&mac.thead;
tdCalling threadcallSyscall numberargPointer to syscall argumentsThis entry point provides a policy-multiplexed system
call so that policies may provide additional services to
user processes without registering specific system calls.
The policy name provided during registration is used to
demux calls from userland, and the arguments will be
forwarded to this entry point. When implementing new
services, security modules should be sure to invoke
appropriate access control checks from the MAC framework as
needed. For example, if a policy implements an augmented
signal functionality, it should call the necessary signal
access control checks to invoke the MAC framework and other
registered policies.Modules must currently perform the
copyin() of the syscall data on their
own.&mac.mpo;_thread_userretvoid
&mac.mpo;_thread_userretstruct thread
*td
&mac.thead;
tdReturning threadThis entry point permits policy modules to perform
MAC-related events when a thread returns to user space.
This is required for policies that have floating process
labels, as it's not always possible to acquire the process
lock at arbitrary points in the stack during system call
processing; process labels might represent traditional
authentication data, process history information, or other
data.Label Operations&mac.mpo;_init_bpfdesc_labelvoid
&mac.mpo;_init_bpfdesc_labelstruct label
*label
&mac.thead;
labelNew label to applyInitialize the label on a newly instantiated bpfdesc (BPF
descriptor)&mac.mpo;_init_cred_labelvoid
&mac.mpo;_init_cred_labelstruct label
*label
&mac.thead;
labelNew label to initializeInitialize the label for a newly instantiated
user credential.&mac.mpo;_init_devfsdirent_labelvoid
&mac.mpo;_init_devfsdirent_labelstruct label
*label
&mac.thead;
labelNew label to applyInitialize the label on a newly instantiated devfs
entry.&mac.mpo;_init_ifnet_labelvoid
&mac.mpo;_init_ifnet_labelstruct label
*label
&mac.thead;
labelNew label to applyInitialize the label on a newly instantiated network
interface.&mac.mpo;_init_ipq_labelvoid
&mac.mpo;_init_ipq_labelstruct label
*labelint flag
&mac.thead;
labelNew label to applyflagBlocking/non-blocking &man.malloc.9;; see
belowInitialize the label on a newly instantiated IP fragment
reassembly queue. The flag field may
be one of M_WAITOK and M_NOWAIT,
and should be employed to avoid performing a blocking
&man.malloc.9; during this initialization call. IP fragment
reassembly queue allocation frequently occurs in performance
sensitive environments, and the implementation should be careful
to avoid blocking or long-lived operations. This entry point
is permitted to fail resulting in the failure to allocate
the IP fragment reassembly queue.&mac.mpo;_init_mbuf_labelvoid
&mac.mpo;_init_mbuf_labelint flagstruct label
*label
&mac.thead;
flagBlocking/non-blocking &man.malloc.9;; see
belowlabelPolicy label to initialize
+ Initialize the label on a newly instantiated mbuf packet
header (mbuf). The
flag field may be one of
M_WAITOK and M_NOWAIT, and
should be employed to avoid performing a blocking
&man.malloc.9; during this initialization call. Mbuf
allocation frequently occurs in performance sensitive
environments, and the implementation should be careful to
avoid blocking or long-lived operations. This entry point
is permitted to fail resulting in the failure to allocate
the mbuf header.&mac.mpo;_init_mount_labelvoid
&mac.mpo;_init_mount_labelstruct label
*mntlabelstruct label
*fslabel
&mac.thead;
mntlabelPolicy label to be initialized for the mount
itselffslabelPolicy label to be initialized for the file
systemInitialize the labels on a newly instantiated mount
point.&mac.mpo;_init_mount_fs_labelvoid
&mac.mpo;_init_mount_fs_labelstruct label
*label
&mac.thead;
labelLabel to be initializedInitialize the label on a newly mounted file
system.&mac.mpo;_init_pipe_labelvoid
&mac.mpo;_init_pipe_labelstruct
label*label
&mac.thead;
labelLabel to be filled in
+ Initialize a label for a newly instantiated pipe.&mac.mpo;_init_socket_labelvoid
&mac.mpo;_init_socket_labelstruct label
*labelint flag
&mac.thead;
labelNew label to initializeflag&man.malloc.9; flagsInitialize a label for a newly instantiated
socket.&mac.mpo;_init_socket_peer_labelvoid
&mac.mpo;_init_socket_peer_labelstruct label
*labelint flag
&mac.thead;
labelNew label to initializeflag&man.malloc.9; flagsInitialize the peer label for a newly instantiated
socket.&mac.mpo;_init_proc_labelvoid
&mac.mpo;_init_proc_labelstruct label
*label
&mac.thead;
labelNew label to initializeInitialize the label for a newly instantiated
process.&mac.mpo;_init_vnode_labelvoid
&mac.mpo;_init_vnode_labelstruct label
*label
&mac.thead;
labelNew label to initializeInitialize the label on a newly instantiated vnode.&mac.mpo;_destroy_bpfdesc_labelvoid
&mac.mpo;_destroy_bpfdesc_labelstruct label
*label
&mac.thead;
labelbpfdesc labelDestroy the label on a BPF descriptor. In this entry
point a policy should free any internal storage associated
with label so that it may be
destroyed.&mac.mpo;_destroy_cred_labelvoid
&mac.mpo;_destroy_cred_labelstruct label
*label
&mac.thead;
labelLabel being destroyedDestroy the label on a credential. In this entry point,
a policy module should free any internal storage associated
with label so that it may be
destroyed.&mac.mpo;_destroy_devfsdirent_labelvoid
&mac.mpo;_destroy_devfsdirent_labelstruct label
*label
&mac.thead;
labelLabel being destroyedDestroy the label on a devfs entry. In this entry
point, a policy module should free any internal storage
associated with label so that it may
be destroyed.&mac.mpo;_destroy_ifnet_labelvoid
&mac.mpo;_destroy_ifnet_labelstruct label
*label
&mac.thead;
labelLabel being destroyedDestroy the label on a removed interface. In this entry
point, a policy module should free any internal storage
associated with label so that it may
be destroyed.&mac.mpo;_destroy_ipq_labelvoid
&mac.mpo;_destroy_ipq_labelstruct label
*label
&mac.thead;
labelLabel being destroyedDestroy the label on an IP fragment queue. In this
entry point, a policy module should free any internal
storage associated with label so that
it may be destroyed.&mac.mpo;_destroy_mbuf_labelvoid
&mac.mpo;_destroy_mbuf_labelstruct label
*label
&mac.thead;
labelLabel being destroyedDestroy the label on an mbuf header. In this entry
point, a policy module should free any internal storage
associated with label so that it may
be destroyed.&mac.mpo;_destroy_mount_labelvoid
&mac.mpo;_destroy_mount_labelstruct label
*label
&mac.thead;
labelMount point label being destroyedDestroy the labels on a mount point. In this entry
point, a policy module should free the internal storage
associated with mntlabel so that they
may be destroyed.&mac.mpo;_destroy_mount_labelvoid
&mac.mpo;_destroy_mount_labelstruct label
*mntlabelstruct label
*fslabel
&mac.thead;
mntlabelMount point label being destroyedfslabel
- File system label being destroyed>
+ File system label being destroyed>Destroy the labels on a mount point. In this entry
point, a policy module should free the internal storage
associated with mntlabel and
fslabel so that they may be
destroyed.&mac.mpo;_destroy_socket_labelvoid
&mac.mpo;_destroy_socket_labelstruct label
*label
&mac.thead;
labelSocket label being destroyedDestroy the label on a socket. In this entry point, a
policy module should free any internal storage associated
with label so that it may be
destroyed.&mac.mpo;_destroy_socket_peer_labelvoid
&mac.mpo;_destroy_socket_peer_labelstruct label
*peerlabel
&mac.thead;
peerlabelSocket peer label being destroyedDestroy the peer label on a socket. In this entry
point, a policy module should free any internal storage
associated with label so that it may
be destroyed.&mac.mpo;_destroy_pipe_labelvoid
&mac.mpo;_destroy_pipe_labelstruct label
*label
&mac.thead;
labelPipe labelDestroy the label on a pipe. In this entry point, a
policy module should free any internal storage associated
with label so that it may be
destroyed.&mac.mpo;_destroy_proc_labelvoid
&mac.mpo;_destroy_proc_labelstruct label
*label
&mac.thead;
labelProcess labelDestroy the label on a process. In this entry point, a
policy module should free any internal storage associated
with label so that it may be
destroyed.&mac.mpo;_destroy_vnode_labelvoid
&mac.mpo;_destroy_vnode_labelstruct label
*label
&mac.thead;
labelProcess labelDestroy the label on a vnode. In this entry point, a
policy module should free any internal storage associated
with label so that it may be
destroyed.&mac.mpo;_copy_mbuf_labelvoid
&mac.mpo;_copy_mbuf_labelstruct label
*srcstruct label
*dest
&mac.thead;
srcSource labeldestDestination labelCopy the label information in
src into
dest.&mac.mpo;_copy_pipe_labelvoid
&mac.mpo;_copy_pipe_labelstruct label
*srcstruct label
*dest
&mac.thead;
srcSource labeldestDestination labelCopy the label information in
src into
dest.&mac.mpo;_copy_vnode_labelvoid
&mac.mpo;_copy_vnode_labelstruct label
*srcstruct label
*dest
&mac.thead;
srcSource labeldestDestination labelCopy the label information in
src into
dest.&mac.mpo;_externalize_cred_labelint
&mac.mpo;_externalize_cred_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_ifnet_labelint
&mac.mpo;_externalize_ifnet_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_pipe_labelint
&mac.mpo;_externalize_pipe_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_socket_labelint
&mac.mpo;_externalize_socket_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_socket_peer_labelint
&mac.mpo;_externalize_socket_peer_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_vnode_labelint
&mac.mpo;_externalize_vnode_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_internalize_cred_labelint
&mac.mpo;_internalize_cred_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
&mac.mpo;_internalize_ifnet_labelint
&mac.mpo;_internalize_ifnet_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
&mac.mpo;_internalize_pipe_labelint
&mac.mpo;_internalize_pipe_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
&mac.mpo;_internalize_socket_labelint
&mac.mpo;_internalize_socket_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
&mac.mpo;_internalize_vnode_labelint
&mac.mpo;_internalize_vnode_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
Label EventsThis class of entry points is used by the MAC framework to
permit policies to maintain label information on kernel
objects. For each labeled kernel object of interest to a MAC
policy, entry points may be registered for relevant life cycle
events. All objects implement initialization, creation, and
destruction hooks. Some objects will also implement
relabeling, allowing user processes to change the labels on
objects. Some objects will also implement object-specific
events, such as label events associated with IP reassembly. A
typical labeled object will have the following life cycle of
entry points:Label initialization o
(object-specific wait) \
Label creation o
\
Relabel events, o--<--.
Various object-specific, | |
Access control events ~-->--o
\
Label destruction oLabel initialization permits policies to allocate memory
and set initial values for labels without context for the use
of the object. The label slot allocated to a policy will be
zeroed by default, so some policies may not need to perform
initialization.Label creation occurs when the kernel structure is
associated with an actual kernel object. For example, Mbufs
may be allocated and remain unused in a pool until they are
required. mbuf allocation causes label initialization on the
mbuf to take place, but mbuf creation occurs when the mbuf is
associated with a datagram. Typically, context will be
provided for a creation event, including the circumstances of
the creation, and labels of other relevant objects in the
creation process. For example, when an mbuf is created from a
socket, the socket and its label will be presented to
registered policies in addition to the new mbuf and its label.
Memory allocation in creation events is discouraged, as it may
occur in performance sensitive ports of the kernel; in
addition, creation calls are not permitted to fail so a
failure to allocate memory cannot be reported.Object specific events do not generally fall into the
other broad classes of label events, but will generally
provide an opportunity to modify or update the label on an
object based on additional context. For example, the label on
an IP fragment reassembly queue may be updated during the
MAC_UPDATE_IPQ entry point as a result of the
acceptance of an additional mbuf to that queue.Access control events are discussed in detail in the
following section.Label destruction permits policies to release storage or
state associated with a label during its association with an
object so that the kernel data structures supporting the
object may be reused or released.In addition to labels associated with specific kernel
objects, an additional class of labels exists: temporary
labels. These labels are used to store update information
submitted by user processes. These labels are initialized and
destroyed as with other label types, but the creation event is
MAC_INTERNALIZE, which accepts a user label
to be converted to an in-kernel representation.File System Object Labeling Event Operations&mac.mpo;_associate_vnode_devfsvoid
&mac.mpo;_associate_vnode_devfsstruct mount
*mpstruct label
*fslabelstruct devfs_dirent
*destruct label
*delabelstruct vnode
*vpstruct label
*vlabel
&mac.thead;
mpDevfs mount pointfslabelDevfs file system label
(mp->mnt_fslabel)deDevfs directory entrydelabelPolicy label associated with
devpvnode associated with
devlabelPolicy label associated with
vpFill in the label (vlabel) for
a newly created devfs vnode based on the devfs directory
entry passed in de and its
label.&mac.mpo;_associate_vnode_extattrint
&mac.mpo;_associate_vnode_extattrstruct mount
*mpstruct label
*fslabelstruct vnode
*vpstruct label
*vlabel
&mac.thead;
mpFile system mount pointfslabelFile system labelvpVnode to labelvlabelPolicy label associated with
vpAttempt to retrieve the label for
vp from the file system extended
attributes. Upon success, the value 0
is returned. Should extended attribute retrieval not be
supported, an accepted fallback is to copy
fslabel into
vlabel. In the event of an error,
an appropriate value for errno should
be returned.&mac.mpo;_associate_vnode_singlelabelvoid
&mac.mpo;_associate_vnode_singlelabelstruct mount
*mpstruct label
*fslabelstruct vnode
*vpstruct label
*vlabel
&mac.thead;
mpFile system mount pointfslabelFile system labelvpVnode to labelvlabelPolicy label associated with
vpOn non-multilabel file systems, this entry point is
called to set the policy label for
vp based on the file system label,
fslabel.&mac.mpo;_create_devfs_devicevoid
&mac.mpo;_create_devfs_devicedev_t devstruct devfs_dirent
*devfs_direntstruct label
*label
&mac.thead;
devDevice corresponding with
devfs_direntdevfs_direntDevfs directory entry to be labeled.labelLabel for devfs_dirent
to be filled in.Fill out the label on a devfs_dirent being created for
the passed device. This call will be made when the device
file system is mounted, regenerated, or a new device is made
available.&mac.mpo;_create_devfs_directoryvoid
&mac.mpo;_create_devfs_directorychar *dirnameint dirnamelenstruct devfs_dirent
*devfs_direntstruct label
*label
&mac.thead;
dirnameName of directory being creatednamelenLength of string
dirnamedevfs_direntDevfs directory entry for directory being
created.Fill out the label on a devfs_dirent being created for
the passed directory. This call will be made when the device
file system is mounted, regenerated, or a new device
requiring a specific directory hierarchy is made
available.&mac.mpo;_create_devfs_symlinkvoid
&mac.mpo;_create_devfs_symlinkstruct ucred
*credstruct mount
*mpstruct devfs_dirent
*ddstruct label
*ddlabelstruct devfs_dirent
*destruct label
*delabel
&mac.thead;
credSubject credentialmpDevfs mount pointddLink destinationddlabelLabel associated with
dddeSymlink entrydelabelLabel associated with
deFill in the label (delabel) for
a newly created &man.devfs.5; symbolic link entry.&mac.mpo;_create_vnode_extattrint
&mac.mpo;_create_vnode_extattrstruct ucred
*credstruct mount
*mpstruct label
*fslabelstruct vnode
*dvpstruct label
*dlabelstruct vnode
*vpstruct label
*vlabelstruct componentname
*cnp
&mac.thead;
credSubject credentialmountFile system mount pointlabelFile system labeldvpParent directory vnodedlabelLabel associated with
dvpvpNewly created vnodevlabelPolicy label associated with
vpcnpComponent name for
vpWrite out the label for vp to
the appropriate extended attribute. If the write
succeeds, fill in vlabel with the
label, and return 0. Otherwise,
return an appropriate error.&mac.mpo;_create_mountvoid
&mac.mpo;_create_mountstruct ucred
*credstruct mount
*mpstruct label
*mntstruct label
*fslabel
&mac.thead;
credSubject credentialmpObject; file system being mountedmntlabelPolicy label to be filled in for
mpfslabelPolicy label for the file system
mp mounts.Fill out the labels on the mount point being created by
the passed subject credential. This call will be made when
a new file system is mounted.&mac.mpo;_create_root_mountvoid
&mac.mpo;_create_root_mountstruct ucred
*credstruct mount
*mpstruct label
*mntlabelstruct label
*fslabel
&mac.thead;
See .Fill out the labels on the mount point being created by
the passed subject credential. This call will be made when
the root file system is mounted, after
&mac.mpo;_create_mount;.&mac.mpo;_relabel_vnodevoid
&mac.mpo;_relabel_vnodestruct ucred
*credstruct vnode
*vpstruct label
*vnodelabelstruct label
*newlabel
&mac.thead;
credSubject credentialvpvnode to relabelvnodelabelExisting policy label for
vpnewlabelNew, possibly partial label to replace
vnodelabelUpdate the label on the passed vnode given the passed
update vnode label and the passed subject credential.&mac.mpo;_setlabel_vnode_extattrint
&mac.mpo;_setlabel_vnode_extattrstruct ucred
*credstruct vnode
*vpstruct label
*vlabelstruct label
*intlabel
&mac.thead;
credSubject credentialvpVnode for which the label is being
writtenvlabelPolicy label associated with
vpintlabelLabel to write outWrite out the policy from
intlabel to an extended
attribute. This is called from
vop_stdcreatevnode_ea.&mac.mpo;_update_devfsdirentvoid
&mac.mpo;_update_devfsdirentstruct devfs_dirent
*devfs_direntstruct label
*direntlabelstruct vnode
*vpstruct label
*vnodelabel
&mac.thead;
devfs_direntObject; devfs directory entrydirentlabelPolicy label for
devfs_dirent to be
updated.vpParent vnodeLockedvnodelabelPolicy label for
vpUpdate the devfs_dirent label
from the passed devfs vnode label. This call will be made
when a devfs vnode has been successfully relabeled to commit
the label change such that it lasts even if the vnode is
recycled. It will also be made when when a symlink is
created in devfs, following a call to
mac_vnode_create_from_vnode to
initialize the vnode label.IPC Object Labeling Event Operations&mac.mpo;_create_mbuf_from_socketvoid
&mac.mpo;_create_mbuf_from_socketstruct socket
*sostruct label
*socketlabelstruct mbuf *mstruct label
*mbuflabel
&mac.thead;
socketSocketSocket locking WIPsocketlabelPolicy label for
socketmObject; mbufmbuflabelPolicy label to fill in for
mSet the label on a newly created mbuf header from the
passed socket label. This call is made when a new datagram
or message is generated by the socket and stored in the
passed mbuf.&mac.mpo;_create_pipevoid
&mac.mpo;_create_pipestruct ucred
*credstruct pipe
*pipestruct label
*pipelabel
&mac.thead;
credSubject credentialpipePipepipelabelPolicy label associated with
pipeSet the label on a newly created pipe from the passed
subject credential. This call is made when a new pipe is
created.&mac.mpo;_create_socketvoid
&mac.mpo;_create_socketstruct ucred
*credstruct socket
*sostruct label
*socketlabel
&mac.thead;
credSubject credentialImmutablesoObject; socket to labelsocketlabelLabel to fill in for
soSet the label on a newly created socket from the passed
subject credential. This call is made when a socket is
created.&mac.mpo;_create_socket_from_socketvoid
&mac.mpo;_create_socket_from_socketstruct socket
*oldsocketstruct label
*oldsocketlabelstruct socket
*newsocketstruct label
*newsocketlabel
&mac.thead;
oldsocketListening socketoldsocketlabelPolicy label associated with
oldsocketnewsocketNew socketnewsocketlabelPolicy label associated with
newsocketlabelLabel a socket, newsocket,
newly &man.accept.2;ed, based on the &man.listen.2;
socket, oldsocket.&mac.mpo;_relabel_pipevoid
&mac.mpo;_relabel_pipestruct ucred
*credstruct pipe
*pipestruct label
*oldlabelstruct label
*newlabel
&mac.thead;
credSubject credentialpipePipeoldlabelCurrent policy label associated with
pipenewlabelPolicy label update to apply to
pipeApply a new label, newlabel, to
pipe.&mac.mpo;_relabel_socketvoid
&mac.mpo;_relabel_socketstruct ucred
*credstruct socket
*sostruct label
*oldlabelstruct label
*newlabel
&mac.thead;
credSubject credentialImmutablesoObject; socketoldlabelCurrent label for
sonewlabelLabel update for
soUpdate the label on a socket from the passed socket
label update.&mac.mpo;_set_socket_peer_from_mbufvoid
&mac.mpo;_set_socket_peer_from_mbufstruct mbuf
*mbufstruct label
*mbuflabelstruct label
*oldlabelstruct label
*newlabel
&mac.thead;
mbufFirst datagram received over socketmbuflabelLabel for mbufoldlabelCurrent label for the socketnewlabelPolicy label to be filled out for the
socketSet the peer label on a stream socket from the passed
mbuf label. This call will be made when the first datagram
is received by the stream socket, with the exception of Unix
domain sockets.&mac.mpo;_set_socket_peer_from_socketvoid
&mac.mpo;_set_socket_peer_from_socketstruct socket
*oldsocketstruct label
*oldsocketlabelstruct socket
*newsocketstruct label
*newsocketpeerlabel
&mac.thead;
oldsocketLocal socketoldsocketlabelPolicy label for
oldsocketnewsocketPeer socketnewsocketpeerlabelPolicy label to fill in for
newsocketSet the peer label on a stream UNIX domain socket from
the passed remote socket endpoint. This call will be made
when the socket pair is connected, and will be made for both
endpoints.Network Object Labeling Event Operations&mac.mpo;_create_bpfdescvoid
&mac.mpo;_create_bpfdescstruct ucred
*credstruct bpf_d
*bpf_dstruct label
*bpflabel
&mac.thead;
credSubject credentialImmutablebpf_dObject; bpf descriptorbpfPolicy label to be filled in for
bpf_dSet the label on a newly created BPF descriptor from the
passed subject credential. This call will be made when a
BPF device node is opened by a process with the passed
subject credential.&mac.mpo;_create_ifnetvoid
&mac.mpo;_create_ifnetstruct ifnet
*ifnetstruct label
*ifnetlabel
&mac.thead;
ifnetNetwork interfaceifnetlabelPolicy label to fill in for
ifnetSet the label on a newly created interface. This call
may be made when a new physical interface becomes available
to the system, or when a pseudo-interface is instantiated
during the boot or as a result of a user action.&mac.mpo;_create_ipqvoid
&mac.mpo;_create_ipqstruct mbuf
*fragmentstruct label
*fragmentlabelstruct ipq
*ipqstruct label
*ipqlabel
&mac.thead;
fragmentFirst received IP fragmentfragmentlabelPolicy label for
fragmentipqIP reassembly queue to be labeledipqlabelPolicy label to be filled in for
ipqSet the label on a newly created IP fragment reassembly
queue from the mbuf header of the first received
fragment.&mac.mpo;_create_datagram_from_ipqvoid
&mac.mpo;_create_create_datagram_from_ipqstruct ipq
*ipqstruct label
*ipqlabelstruct mbuf
*datagramstruct label
*datagramlabel
&mac.thead;
ipqIP reassembly queueipqlabelPolicy label for
ipqdatagramDatagram to be labeleddatagramlabelPolicy label to be filled in for
datagramlabelSet the label on a newly reassembled IP datagram from
the IP fragment reassembly queue from which it was
generated.&mac.mpo;_create_fragmentvoid
&mac.mpo;_create_fragmentstruct mbuf
*datagramstruct label
*datagramlabelstruct mbuf
*fragmentstruct label
*fragmentlabel
&mac.thead;
datagramDatagramdatagramlabelPolicy label for
datagramfragmentFragment to be labeledfragmentlabelPolicy label to be filled in for
datagramSet the label on the mbuf header of a newly created IP
fragment from the label on the mbuf header of the datagram
it was generate from.&mac.mpo;_create_mbuf_from_mbufvoid
&mac.mpo;_create_mbuf_from_mbufstruct mbuf
*oldmbufstruct label
*oldmbuflabelstruct mbuf
*newmbufstruct label
*newmbuflabel
&mac.thead;
oldmbufExisting (source) mbufoldmbuflabelPolicy label for
oldmbufnewmbufNew mbuf to be labelednewmbuflabelPolicy label to be filled in for
newmbufSet the label on the mbuf header of a newly created
datagram from the mbuf header of an existing datagram. This
call may be made in a number of situations, including when
an mbuf is re-allocated for alignment purposes.&mac.mpo;_create_mbuf_linklayervoid
&mac.mpo;_create_mbuf_linklayerstruct ifnet
*ifnetstruct label
*ifnetlabelstruct mbuf
*mbufstruct label
*mbuflabel
&mac.thead;
ifnetNetwork interfaceifnetlabelPolicy label for
ifnetmbufmbuf header for new datagrammbuflabelPolicy label to be filled in for
mbufSet the label on the mbuf header of a newly created
datagram generated for the purposes of a link layer response
for the passed interface. This call may be made in a number
of situations, including for ARP or ND6 responses in the
IPv4 and IPv6 stacks.&mac.mpo;_create_mbuf_from_bpfdescvoid
&mac.mpo;_create_mbuf_from_bpfdescstruct bpf_d
*bpf_dstruct label
*bpflabelstruct mbuf
*mbufstruct label
*mbuflabel
&mac.thead;
bpf_dBPF descriptorbpflabelPolicy label for
bpflabelmbufNew mbuf to be labeledmbuflabelPolicy label to fill in for
mbufSet the label on the mbuf header of a newly created
datagram generated using the passed BPF descriptor. This
call is made when a write is performed to the BPF device
associated with the passed BPF descriptor.&mac.mpo;_create_mbuf_from_ifnetvoid
&mac.mpo;_create_mbuf_from_ifnetstruct ifnet
*ifnetstruct label
*ifnetlabelstruct mbuf
*mbufstruct label
*mbuflabel
&mac.thead;
ifnetNetwork interfaceifnetlabelPolicy label for
ifnetlabelmbufmbuf header for new datagrammbuflabelPolicy label to be filled in for
mbufSet the label on the mbuf header of a newly created
datagram generated from the passed network interface.&mac.mpo;_create_mbuf_multicast_encapvoid
&mac.mpo;_create_mbuf_multicast_encapstruct mbuf
*oldmbufstruct label
*oldmbuflabelstruct ifnet
*ifnetstruct label
*ifnetlabelstruct mbuf
*newmbufstruct label
*newmbuflabel
&mac.thead;
oldmbufmbuf header for existing datagramoldmbuflabelPolicy label for
oldmbufifnetNetwork interfaceifnetlabelPolicy label for
ifnetnewmbufmbuf header to be labeled for new
datagramnewmbuflabelPolicy label to be filled in for
newmbufSet the label on the mbuf header of a newly created
datagram generated from the existing passed datagram when it
is processed by the passed multicast encapsulation
interface. This call is made when an mbuf is to be
delivered using the virtual interface.&mac.mpo;_create_mbuf_netlayervoid
&mac.mpo;_create_mbuf_netlayerstruct mbuf
*oldmbufstruct label
*oldmbuflabelstruct mbuf
*newmbufstruct label
*newmbuflabel
&mac.thead;
oldmbufReceived datagramoldmbuflabelPolicy label for
oldmbufnewmbufNewly created datagramnewmbuflabelPolicy label for
newmbufSet the label on the mbuf header of a newly created
datagram generated by the IP stack in response to an
existing received datagram (oldmbuf).
This call may be made in a number of situations, including
when responding to ICMP request datagrams.&mac.mpo;_fragment_matchint
&mac.mpo;_fragment_matchstruct mbuf
*fragmentstruct label
*fragmentlabelstruct ipq
*ipqstruct label
*ipqlabel
&mac.thead;
fragmentIP datagram fragmentfragmentlabelPolicy label for
fragmentipqIP fragment reassembly queueipqlabelPolicy label for
ipqDetermine whether an mbuf header containing an IP
datagram (fragment) fragment matches
the label of the passed IP fragment reassembly queue
(ipq). Return
(1) for a successful match, or
(0) for no match. This call is
made when the IP stack attempts to find an existing fragment
reassembly queue for a newly received fragment; if this
fails, a new fragment reassembly queue may be instantiated
for the fragment. Policies may use this entry point to
prevent the reassembly of otherwise matching IP fragments if
policy does not permit them to be reassembled based on the
label or other information.&mac.mpo;_relabel_ifnetvoid
&mac.mpo;_relabel_ifnetstruct ucred
*credstruct ifnet
*ifnetstruct label
*ifnetlabelstruct label
*newlabel
&mac.thead;
credSubject credentialifnetObject; Network interfaceifnetlabelPolicy label for
ifnetnewlabelLabel update to apply to
ifnetUpdate the label of network interface,
ifnet, based on the passed update
label, newlabel, and the passed
subject credential, cred.&mac.mpo;_update_ipqvoid
&mac.mpo;_update_ipqstruct mbuf
*fragmentstruct label
*fragmentlabelstruct ipq
*ipqstruct label
*ipqlabel
&mac.thead;
mbufIP fragmentmbuflabelPolicy label for
mbufipqIP fragment reassembly queueipqlabelPolicy label to be updated for
ipqUpdate the label on an IP fragment reassembly queue
(ipq) based on the acceptance of the
passed IP fragment mbuf header
(mbuf).Process Labeling Event Operations&mac.mpo;_create_credvoid
&mac.mpo;_create_credstruct ucred
*parent_credstruct ucred
*child_cred
&mac.thead;
parent_credParent subject credentialchild_credChild subject credentialSet the label of a newly created subject credential from
the passed subject credential. This call will be made when
&man.crcopy.9; is invoked on a newly created struct
ucred. This call should not be confused with a
process forking or creation event.&mac.mpo;_execve_transitionvoid
&mac.mpo;_execve_transitionstruct ucred
*oldstruct ucred
*newstruct vnode
*vpstruct label
*vnodelabel
&mac.thead;
oldExisting subject credentialImmutablenewNew subject credential to be labeledvpFile to executeLockedvnodelabelPolicy label for
vpUpdate the label of a newly created subject credential
(new) from the passed existing
subject credential (old) based on a
label transition caused by executing the passed vnode
(vp). This call occurs when a
process executes the passed vnode and one of the policies
returns a success from the
mpo_execve_will_transition entry point.
Policies may choose to implement this call simply by
invoking mpo_create_cred and passing
the two subject credentials so as not to implement a
transitioning event. Policies should not leave this entry
point unimplemented if they implement
mpo_create_cred, even if they do not
implement
mpo_execve_will_transition.&mac.mpo;_execve_will_transitionint
&mac.mpo;_execve_will_transitionstruct ucred
*oldstruct vnode
*vpstruct label
*vnodelabel
&mac.thead;
oldSubject credential prior to
&man.execve.2;ImmutablevpFile to executevnodelabelPolicy label for
vpDetermine whether the policy will want to perform a
transition event as a result of the execution of the passed
vnode by the passed subject credential. Return
1 if a transition is required,
0 if not. Even if a policy
returns 0, it should behave
correctly in the presence of an unexpected invocation of
mpo_execve_transition, as that call may
happen as a result of another policy requesting a
transition.&mac.mpo;_create_proc0void
&mac.mpo;_create_proc0struct ucred
*cred
&mac.thead;
credSubject credential to be filled inCreate the subject credential of process 0, the parent
of all kernel processes.&mac.mpo;_create_proc1void
&mac.mpo;_create_proc1struct ucred
*cred
&mac.thead;
credSubject credential to be filled inCreate the subject credential of process 1, the parent
of all user processes.&mac.mpo;_relabel_credvoid
&mac.mpo;_relabel_credstruct ucred
*credstruct label
*newlabel
&mac.thead;
credSubject credentialnewlabelLabel update to apply to
credUpdate the label on a subject credential from the passed
update label.Access Control ChecksAccess control entry points permit policy modules to
influence access control decisions made by the kernel.
Generally, although not always, arguments to an access control
entry point will include one or more authorizing credentials,
information (possibly including a label) for any other objects
involved in the operation. An access control entry point may
return 0 to permit the operation, or an &man.errno.2; error
value. The results of invoking the entry point across various
registered policy modules will be composed as follows: if all
modules permit the operation to succeed, success will be
returned. If one or modules returns a failure, a failure will
be returned. If more than one module returns a failure, the
errno value to return to the user will be selected using the
following precedence, implemented by the
error_select() function in
kern_mac.c:Most precedenceEDEADLKEINVALESRCHEACCESLeast precedenceEPERMIf none of the error values returned by all modules are
listed in the precedence chart then an arbitrarily selected
value from the set will be returned. In general, the rules
provide precedence to errors in the following order: kernel
failures, invalid arguments, object not present, access not
permitted, other.&mac.mpo;_check_bpfdesc_receiveint
&mac.mpo;_check_bpfdesc_receivestruct bpf_d
*bpf_dstruct label
*bpflabelstruct ifnet
*ifnetstruct label
*ifnetlabel
&mac.thead;
bpf_dSubject; BPF descriptorbpflabelPolicy label for
bpf_difnetObject; network interfaceifnetlabelPolicy label for
ifnetDetermine whether the MAC framework should permit
datagrams from the passed interface to be delivered to the
buffers of the passed BPF descriptor. Return
(0) for success, or an
errno value for failure Suggested
failure: EACCES for label mismatches,
EPERM for lack of privilege.&mac.mpo;_check_kenv_dumpint
&mac.mpo;_check_kenv_dumpstruct ucred
*cred
&mac.thead;
credSubject credentialDetermine whether the subject should be allowed to
retrieve the kernel environment (see &man.kenv.2;).&mac.mpo;_check_kenv_getint
&mac.mpo;_check_kenv_getstruct ucred
*credchar *name
&mac.thead;
credSubject credentialnameKernel environment variable nameDetermine whether the subject should be allowed to
retrieve the value of the specified kernel environment
variable.&mac.mpo;_check_kenv_setint
&mac.mpo;_check_kenv_setstruct ucred
*credchar *name
&mac.thead;
credSubject credentialnameKernel environment variable nameDetermine whether the subject should be allowed to set
the specified kernel environment variable.&mac.mpo;_check_kenv_unsetint
&mac.mpo;_check_kenv_unsetstruct ucred
*credchar *name
&mac.thead;
credSubject credentialnameKernel environment variable nameDetermine whether the subject should be allowed to unset
the specified kernel environment variable.&mac.mpo;_check_kld_loadint
&mac.mpo;_check_kld_loadstruct ucred
*credstruct vnode
*vpstruct label
*vlabel
&mac.thead;
credSubject credentialvpKernel module vnodevlabelLabel associated with
vpDetermine whether the subject should be allowed to load
the specified module file.&mac.mpo;_check_kld_statint
&mac.mpo;_check_kld_statstruct ucred
*cred
&mac.thead;
credSubject credentialDetermine whether the subject should be allowed to
retrieve a list of loaded kernel module files and associated
statistics.&mac.mpo;_check_kld_unloadint
&mac.mpo;_check_kld_unloadstruct ucred
*cred
&mac.thead;
credSubject credentialDetermine whether the subject should be allowed to
unload a kernel module.&mac.mpo;_check_pipe_ioctlint
&mac.mpo;_check_pipe_ioctlstruct ucred
*credstruct pipe
*pipestruct label
*pipelabelunsigned long
cmdvoid *data
&mac.thead;
credSubject credentialpipePipepipelabelPolicy label associated with
pipecmd&man.ioctl.2; commanddata&man.ioctl.2; dataDetermine whether the subject should be allowed to make
the specified &man.ioctl.2; call.&mac.mpo;_check_pipe_pollint
&mac.mpo;_check_pipe_pollstruct ucred
*credstruct pipe
*pipestruct label
*pipelabel
&mac.thead;
credSubject credentialpipePipepipelabelPolicy label associated with
pipeDetermine whether the subject should be allowed to poll
pipe.&mac.mpo;_check_pipe_readint
&mac.mpo;_check_pipe_readstruct ucred
*credstruct pipe
*pipestruct label
*pipelabel
&mac.thead;
credSubject credentialpipePipepipelabelPolicy label associated with
pipeDetermine whether the subject should be allowed read
access to pipe.&mac.mpo;_check_pipe_relabelint
&mac.mpo;_check_pipe_relabelstruct ucred
*credstruct pipe
*pipestruct label
*pipelabelstruct label
*newlabel
&mac.thead;
credSubject credentialpipePipepipelabelCurrent policy label associated with
pipenewlabelLabel update to
pipelabelDetermine whether the subject should be allowed to
relabel pipe.&mac.mpo;_check_pipe_statint
&mac.mpo;_check_pipe_statstruct ucred
*credstruct pipe
*pipestruct label
*pipelabel
&mac.thead;
credSubject credentialpipePipepipelabelPolicy label associated with
pipeDetermine whether the subject should be allowed to
retrieve statistics related to
pipe.&mac.mpo;_check_pipe_writeint
&mac.mpo;_check_pipe_writestruct ucred
*credstruct pipe
*pipestruct label
*pipelabel
&mac.thead;
credSubject credentialpipePipepipelabelPolicy label associated with
pipeDetermine whether the subject should be allowed to write
to pipe.&mac.mpo;_check_socket_bindint
&mac.mpo;_check_socket_bindstruct ucred
*credstruct socket
*socketstruct label
*socketlabelstruct sockaddr
*sockaddr
&mac.thead;
credSubject credentialsocketSocket to be boundsocketlabelPolicy label for
socketsockaddrAddress of
socket&mac.mpo;_check_socket_connectint
&mac.mpo;_check_socket_connectstruct ucred
*credstruct socket
*socketstruct label
*socketlabelstruct sockaddr
*sockaddr
&mac.thead;
credSubject credentialsocketSocket to be connectedsocketlabelPolicy label for
socketsockaddrAddress of
socketDetermine whether the subject credential
(cred) can connect the passed socket
(socket) to the passed socket address
(sockaddr). Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches,
EPERM for lack of privilege.&mac.mpo;_check_socket_receiveint
&mac.mpo;_check_socket_receivestruct ucred
*credstruct socket
*sostruct label
*socketlabel
&mac.thead;
credSubject credentialsoSocketsocketlabelPolicy label associated with
soDetermine whether the subject should be allowed to
receive information from the socket
so.&mac.mpo;_check_socket_sendint
&mac.mpo;_check_socket_sendstruct ucred
*credstruct socket
*sostruct label
*socketlabel
&mac.thead;
credSubject credentialsoSocketsocketlabelPolicy label associated with
soDetermine whether the subject should be allowed to send
information across the socket
so.&mac.mpo;_check_cred_visibleint
&mac.mpo;_check_cred_visiblestruct ucred
*u1struct ucred
*u2
&mac.thead;
u1Subject credentialu2Object credentialDetermine whether the subject credential
u1 can see other
subjects with the passed subject credential
u2. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches,
EPERM for lack of privilege, or
ESRCH to hide visibility. This call
may be made in a number of situations, including
inter-process status sysctls used by ps,
and in procfs lookups.&mac.mpo;_check_socket_visibleint
&mac.mpo;_check_socket_visiblestruct ucred
*credstruct socket
*socketstruct label
*socketlabel
&mac.thead;
credSubject credentialsocketObject; socketsocketlabelPolicy label for
socket&mac.mpo;_check_ifnet_relabelint
&mac.mpo;_check_ifnet_relabelstruct ucred
*credstruct ifnet
*ifnetstruct label
*ifnetlabelstruct label
*newlabel
&mac.thead;
credSubject credentialifnetObject; network interfaceifnetlabelExisting policy label for
ifnetnewlabelPolicy label update to later be applied to
ifnetDetermine whether the subject credential can relabel the
passed network interface to the passed label update.&mac.mpo;_check_socket_relabelint
&mac.mpo;_check_socket_relabelstruct ucred
*credstruct socket
*socketstruct label
*socketlabelstruct label
*newlabel
&mac.thead;
credSubject credentialsocketObject; socketsocketlabelExisting policy label for
socketnewlabelLabel update to later be applied to
socketlabelDetermine whether the subject credential can relabel the
passed socket to the passed label update.&mac.mpo;_check_cred_relabelint
&mac.mpo;_check_cred_relabelstruct ucred
*credstruct label
*newlabel
&mac.thead;
credSubject credentialnewlabelLabel update to later be applied to
credDetermine whether the subject credential can relabel
itself to the passed label update.&mac.mpo;_check_vnode_relabelint
&mac.mpo;_check_vnode_relabelstruct ucred
*credstruct vnode
*vpstruct label
*vnodelabelstruct label
*newlabel
&mac.thead;
credSubject credentialImmutablevpObject; vnodeLockedvnodelabelExisting policy label for
vpnewlabelPolicy label update to later be applied to
vpDetermine whether the subject credential can relabel the
passed vnode to the passed label update.&mac.mpo;_check_mount_statint &mac.mpo;_check_mount_statstruct ucred
*credstruct mount
*mpstruct label
*mountlabel
&mac.thead;
credSubject credentialmpObject; file system mountmountlabelPolicy label for
mpDetermine whether the subject credential can see the
results of a statfs performed on the file system. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches
or EPERM for lack of privilege. This
call may be made in a number of situations, including during
invocations of &man.statfs.2; and related calls, as well as to
determine what file systems to exclude from listings of file
systems, such as when &man.getfsstat.2; is invoked. &mac.mpo;_check_proc_debugint
&mac.mpo;_check_proc_debugstruct ucred
*credstruct proc
*proc
&mac.thead;
credSubject credentialImmutableprocObject; processDetermine whether the subject credential can debug the
passed process. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, EPERM for lack of
privilege, or ESRCH to hide
visibility of the target. This call may be made in a number
of situations, including use of the &man.ptrace.2; and
&man.ktrace.2; APIs, as well as for some types of procfs
operations.&mac.mpo;_check_vnode_accessint
&mac.mpo;_check_vnode_accessstruct ucred
*credstruct vnode
*vpstruct label
*labelint flags
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vpflags&man.access.2; flagsDetermine how invocations of &man.access.2; and related
calls by the subject credential should return when performed
on the passed vnode using the passed access flags. This
should generally be implemented using the same semantics
used in &mac.mpo;_check_vnode_open.
Return 0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_chdirint
&mac.mpo;_check_vnode_chdirstruct ucred
*credstruct vnode
*dvpstruct label
*dlabel
&mac.thead;
credSubject credentialdvpObject; vnode to &man.chdir.2; intodlabelPolicy label for
dvpDetermine whether the subject credential can change the
process working directory to the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_chrootint
&mac.mpo;_check_vnode_chrootstruct ucred
*credstruct vnode
*dvpstruct label
*dlabel
&mac.thead;
credSubject credentialdvpDirectory vnodedlabelPolicy label associated with
dvpDetermine whether the subject should be allowed to
&man.chroot.2; into the specified directory
(dvp).&mac.mpo;_check_vnode_createint
&mac.mpo;_check_vnode_createstruct ucred
*credstruct vnode
*dvpstruct label
*dlabelstruct componentname
*cnpstruct vattr
*vap
&mac.thead;
credSubject credentialdvpObject; vnodedlabelPolicy label for
dvpcnpComponent name for
dvpvapvnode attributes for vapDetermine whether the subject credential can create a
vnode with the passed parent directory, passed name
information, and passed attribute information. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES. for label mismatch,
or EPERM for lack of privilege.
This call may be made in a number of situations, including
as a result of calls to &man.open.2; with
O_CREAT, &man.mknod.2;, &man.mkfifo.2;, and
others.&mac.mpo;_check_vnode_deleteint
&mac.mpo;_check_vnode_deletestruct ucred
*credstruct vnode
*dvpstruct label
*dlabelstruct vnode
*vpvoid *labelstruct componentname
*cnp
&mac.thead;
credSubject credentialdvpParent directory vnodedlabelPolicy label for
dvpvpObject; vnode to deletelabelPolicy label for
vpcnpComponent name for
vpDetermine whether the subject credential can delete a
vnode from the passed parent directory and passed name
information. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege. This call may be made in a number of situations,
including as a result of calls to &man.unlink.2; and
&man.rmdir.2;. Policies implementing this entry point
should also implement
mpo_check_rename_to to authorize
deletion of objects as a result of being the target of a
rename.&mac.mpo;_check_vnode_deleteaclint
&mac.mpo;_check_vnode_deleteaclstruct ucred *credstruct vnode *vpstruct label *labelacl_type_t type
&mac.thead;
credSubject credentialImmutablevpObject; vnodeLockedlabelPolicy label for
vptypeACL typeDetermine whether the subject credential can delete the
ACL of passed type from the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_execint
&mac.mpo;_check_vnode_execstruct ucred
*credstruct vnode
*vpstruct label
*label
&mac.thead;
credSubject credentialvpObject; vnode to executelabelPolicy label for
vpDetermine whether the subject credential can execute the
passed vnode. Determination of execute privilege is made
separately from decisions about any transitioning event.
Return 0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_getaclint
&mac.mpo;_check_vnode_getaclstruct ucred
*credstruct vnode
*vpstruct label
*labelacl_type_t
type
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vptypeACL typeDetermine whether the subject credential can retrieve
the ACL of passed type from the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_getextattrint
&mac.mpo;_check_vnode_getextattrstruct ucred
*credstruct vnode
*vpstruct label
*labelint
attrnamespaceconst char
*namestruct uio
*uio
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vpattrnamespaceExtended attribute namespacenameExtended attribute nameuioI/O structure pointer; see &man.uio.9;Determine whether the subject credential can retrieve
the extended attribute with the passed namespace and name
from the passed vnode. Policies implementing labeling using
extended attributes may be interested in special handling of
operations on those extended attributes. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_linkint
&mac.mpo;_check_vnode_linkstruct ucred
*credstruct vnode
*dvpstruct label
*dlabelstruct vnode
*vpstruct label
*labelstruct componentname
*cnp
&mac.thead;
credSubject credentialdvpDirectory vnodedlabelPolicy label associated with
dvpvpLink destination vnodelabelPolicy label associated with
vpcnpComponent name for the link being createdDetermine whether the subject should be allowed to
create a link to the vnode vp with
the name specified by cnp.&mac.mpo;_check_vnode_mmapint
&mac.mpo;_check_vnode_mmapstruct ucred
*credstruct vnode
*vpstruct label
*labelint prot
&mac.thead;
credSubject credentialvpVnode to maplabelPolicy label associated with
vpprotMmap protections (see &man.mmap.2;)Determine whether the subject should be allowed to map
the vnode vp with the protections
specified in prot.&mac.mpo;_check_vnode_mmap_downgradevoid
&mac.mpo;_check_vnode_mmap_downgradestruct ucred
*credstruct vnode
*vpstruct label
*labelint *prot
&mac.thead;
credSee
.vplabelprotMmap protections to be downgradedDowngrade the mmap protections based on the subject and
object labels.&mac.mpo;_check_vnode_mprotectint
&mac.mpo;_check_vnode_mprotectstruct ucred
*credstruct vnode
*vpstruct label
*labelint prot
&mac.thead;
credSubject credentialvpMapped vnodeprotMemory protectionsDetermine whether the subject should be allowed to
set the specified memory protections on memory mapped from
the vnode vp.&mac.mpo;_check_vnode_pollint
&mac.mpo;_check_vnode_pollstruct ucred
*active_credstruct ucred
*file_credstruct vnode
*vpstruct label
*label
&mac.thead;
active_credSubject credentialfile_credCredential associated with the struct
filevpPolled vnodelabelPolicy label associated with
vpDetermine whether the subject should be allowed to poll
the vnode vp.&mac.mpo;_check_vnode_rename_fromint
&mac.mpo;_vnode_rename_fromstruct ucred
*credstruct vnode
*dvpstruct label
*dlabelstruct vnode
*vpstruct label
*labelstruct componentname
*cnp
&mac.thead;
credSubject credentialdvpDirectory vnodedlabelPolicy label associated with
dvpvpVnode to be renamedlabelPolicy label associated with
vpcnpComponent name for
vpDetermine whether the subject should be allowed to
rename the vnode vp to something
else.&mac.mpo;_check_vnode_rename_toint
&mac.mpo;_check_vnode_rename_tostruct ucred
*credstruct vnode
*dvpstruct label
*dlabelstruct vnode
*vpstruct label
*labelint samedirstruct componentname
*cnp
&mac.thead;
credSubject credentialdvpDirectory vnodedlabelPolicy label associated with
dvpvpOverwritten vnodelabelPolicy label associated with
vpsamedirBoolean; 1 if the source and
destination directories are the samecnpDestination component nameDetermine whether the subject should be allowed to
rename to the vnode vp, into the
directory dvp, or to the name
represented by cnp. If there is no
existing file to overwrite, vp and
label will be NULL.&mac.mpo;_check_socket_listenint
&mac.mpo;_check_socket_listenstruct ucred
*credstruct socket
*socketstruct label
*socketlabel
&mac.thead;
credSubject credentialsocketObject; socketsocketlabelPolicy label for
socketDetermine whether the subject credential can listen on
the passed socket. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege.&mac.mpo;_check_vnode_lookupint
&mac.mpo;_check_vnode_lookupstruct ucred
*credstruct vnode
*dvpstruct label
*dlabelstruct componentname
*cnp
&mac.thead;
credSubject credentialdvpObject; vnodedlabelPolicy label for
dvpcnpComponent name being looked upDetermine whether the subject credential can perform a
lookup in the passed directory vnode for the passed name.
Return 0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_openint
&mac.mpo;_check_vnode_openstruct ucred
*credstruct vnode
*vpstruct label
*labelint
acc_mode
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vpacc_mode&man.open.2; access modeDetermine whether the subject credential can perform an
open operation on the passed vnode with the passed access
mode. Return 0 for success, or
an errno value for failure. Suggested failure:
EACCES for label mismatch, or
EPERM for lack of privilege.&mac.mpo;_check_vnode_readdirint
&mac.mpo;_check_vnode_readdirstruct ucred
*credstruct vnode
*dvpstruct label
*dlabel
&mac.thead;
credSubject credentialdvpObject; directory vnodedlabelPolicy label for
dvpDetermine whether the subject credential can perform a
readdir operation on the passed
directory vnode. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege.&mac.mpo;_check_vnode_readlinkint
&mac.mpo;_check_vnode_readlinkstruct ucred
*credstruct vnode
*vpstruct label
*label
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vpDetermine whether the subject credential can perform a
readlink operation on the passed
symlink vnode. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege. This call may be made in a number of situations,
including an explicit readlink call by
the user process, or as a result of an implicit
readlink during a name lookup by the
process.&mac.mpo;_check_vnode_revokeint
&mac.mpo;_check_vnode_revokestruct ucred
*credstruct vnode
*vpstruct label
*label
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vpDetermine whether the subject credential can revoke
access to the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_setaclint
&mac.mpo;_check_vnode_setaclstruct ucred
*credstruct vnode
*vpstruct label
*labelacl_type_t
typestruct acl
*acl
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vptypeACL typeaclACLDetermine whether the subject credential can set the
passed ACL of passed type on the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_setextattrint
&mac.mpo;_check_vnode_setextattrstruct ucred
*credstruct vnode
*vpstruct label
*labelint
attrnamespaceconst char
*namestruct uio
*uio
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for vpattrnamespaceExtended attribute namespacenameExtended attribute nameuioI/O structure pointer; see &man.uio.9;Determine whether the subject credential can set the
extended attribute of passed name and passed namespace on
the passed vnode. Policies implementing security labels
backed into extended attributes may want to provide
additional protections for those attributes. Additionally,
policies should avoid making decisions based on the data
referenced from uio, as there is a
potential race condition between this check and the actual
operation. The uio may also be
NULL if a delete operation is being
performed. Return 0 for success,
or an errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_setflagsint
&mac.mpo;_check_vnode_setflagsstruct ucred
*credstruct vnode
*vpstruct label
*labelu_long flags
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vpflagsFile flags; see &man.chflags.2;Determine whether the subject credential can set the
passed flags on the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_setmodeint
&mac.mpo;_check_vnode_setmodestruct ucred
*credstruct vnode
*vpstruct label
*labelmode_t mode
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for vpmodeFile mode; see &man.chmod.2;Determine whether the subject credential can set the
passed mode on the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_setownerint
&mac.mpo;_check_vnode_setownerstruct ucred
*credstruct vnode
*vpstruct label
*labeluid_t uidgid_t gid
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for vpuidUser IDgidGroup IDDetermine whether the subject credential can set the
passed uid and passed gid as file uid and file gid on the
passed vnode. The IDs may be set to (-1)
to request no update. Return 0
for success, or an errno value for
failure. Suggested failure: EACCES
for label mismatch, or EPERM for lack
of privilege.&mac.mpo;_check_vnode_setutimesint
&mac.mpo;_check_vnode_setutimesstruct ucred
*credstruct vnode
*vpstruct label
*labelstruct timespec
atimestruct timespec
mtime
&mac.thead;
credSubject credentialvpObject; vplabelPolicy label for
vpatimeAccess time; see &man.utimes.2;mtimeModification time; see &man.utimes.2;Determine whether the subject credential can set the
passed access timestamps on the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_proc_schedint
&mac.mpo;_check_proc_schedstruct ucred
*ucredstruct proc
*proc
&mac.thead;
credSubject credentialprocObject; processDetermine whether the subject credential can change the
scheduling parameters of the passed process. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
EPERM for lack of privilege, or
ESRCH to limit visibility.See &man.setpriority.2; for more information.&mac.mpo;_check_proc_signalint
&mac.mpo;_check_proc_signalstruct ucred
*credstruct proc
*procint signal
&mac.thead;
credSubject credentialprocObject; processsignalSignal; see &man.kill.2;Determine whether the subject credential can deliver the
passed signal to the passed process. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
EPERM for lack of privilege, or
ESRCH to limit visibility.&mac.mpo;_check_vnode_statint
&mac.mpo;_check_vnode_statstruct ucred
*credstruct vnode
*vpstruct label
*label
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vpDetermine whether the subject credential can
stat the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.See &man.stat.2; for more information.&mac.mpo;_check_ifnet_transmitint
&mac.mpo;_check_ifnet_transmitstruct ucred
*credstruct ifnet
*ifnetstruct label
*ifnetlabelstruct mbuf
*mbufstruct label
*mbuflabel
&mac.thead;
credSubject credentialifnetNetwork interfaceifnetlabelPolicy label for
ifnetmbufObject; mbuf to be sentmbuflabelPolicy label for
mbufDetermine whether the network interface can transmit the
passed mbuf. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege.&mac.mpo;_check_socket_deliverint
&mac.mpo;_check_socket_deliverstruct ucred
*credstruct ifnet
*ifnetstruct label
*ifnetlabelstruct mbuf
*mbufstruct label
*mbuflabel
&mac.thead;
credSubject credentialifnetNetwork interfaceifnetlabelPolicy label for
ifnetmbufObject; mbuf to be deliveredmbuflabelPolicy label for
mbufDetermine whether the socket may receive the datagram
stored in the passed mbuf header. Return
0 for success, or an
errno value for failure. Suggested
failures: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_socket_visibleint
&mac.mpo;_check_socket_visiblestruct ucred
*credstruct socket
*sostruct label
*socketlabel
&mac.thead;
credSubject credentialImmutablesoObject; socketsocketlabelPolicy label for
soDetermine whether the subject credential cred can "see"
the passed socket (socket) using
system monitoring functions, such as those employed by
&man.netstat.8; and &man.sockstat.1;. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches,
EPERM for lack of privilege, or
ESRCH to hide visibility.&mac.mpo;_check_system_acctint
&mac.mpo;_check_system_acctstruct ucred
*ucredstruct vnode
*vpstruct label
*vlabel
&mac.thead;
ucredSubject credentialvpAccounting file; &man.acct.5;vlabelLabel associated with
vpDetermine whether the subject should be allowed to
enable accounting, based on its label and the label of the
accounting log file.&mac.mpo;_check_system_nfsdint
&mac.mpo;_check_system_nfsdstruct ucred
*cred
&mac.thead;
credSubject credentialDetermine whether the subject should be allowed to call
&man.nfssvc.2;.&mac.mpo;_check_system_rebootint
&mac.mpo;_check_system_rebootstruct ucred
*credint howto
&mac.thead;
credSubject credentialhowtohowto parameter from
&man.reboot.2;Determine whether the subject should be allowed to
reboot the system in the specified manner.&mac.mpo;_check_system_settimeint
&mac.mpo;_check_system_settimestruct ucred
*cred
&mac.thead;
credSubject credentialDetermine whether the user should be allowed to set the
system clock.&mac.mpo;_check_system_swaponint
&mac.mpo;_check_system_swaponstruct ucred
*credstruct vnode
*vpstruct label
*vlabel
&mac.thead;
credSubject credentialvpSwap devicevlabelLabel associated with
vpDetermine whether the subject should be allowed to add
vp as a swap device.&mac.mpo;_check_system_sysctlint
&mac.mpo;_check_system_sysctlstruct ucred
*credint *nameu_int *namelenvoid *oldsize_t
*oldlenpint inkernelvoid *newsize_t newlen
&mac.thead;
credSubject credentialnameSee &man.sysctl.3;namelenoldoldlenpinkernelBoolean; 1 if called from
kernelnewSee &man.sysctl.3;newlenDetermine whether the subject should be allowed to make
the specified &man.sysctl.3; transaction.Label Management CallsRelabel events occur when a user process has requested
that the label on an object be modified. A two-phase update
occurs: first, an access control check will be performed to
determine if the update is both valid and permitted, and then
the update itself is performed via a separate entry point.
Relabel entry points typically accept the object, object label
reference, and an update label submitted by the process.
Memory allocation during relabel is discouraged, as relabel
calls are not permitted to fail (failure should be reported
earlier in the relabel check).Userland ArchitectureThe TrustedBSD MAC Framework includes a number of
policy-agnostic elements, including MAC library interfaces
for abstractly managing labels, modifications to the system
credential management and login libraries to support the
assignment of MAC labels to users, and a set of tools to
monitor and modify labels on processes, files, and network
interfaces. More details on the user architecture will
be added to this section in the near future.APIs for Policy-Agnostic Label ManagementThe TrustedBSD MAC Framework provides a number of
library and system calls permitting applications to
manage MAC labels on objects using a policy-agnostic
interface. This permits applications to manipulate
labels for a variety of policies without being
written to support specific policies. These interfaces
are used by general-purpose tools such as &man.ifconfig.8;,
&man.ls.1; and &man.ps.1; to view labels on network
interfaces, files, and processes. The APIs also support
MAC management tools including &man.getfmac.8;,
&man.getpmac.8;, &man.setfmac.8;, &man.setfsmac.8;,
and &man.setpmac.8;. The MAC APIs are documented in
&man.mac.3;.Applications handle MAC labels in two forms: an
internalized form used to return and set labels on
processes and objects (mac_t),
and externalized form based on C strings appropriate for
storage in configuration files, display to the user, or
input from the user. Each MAC label contains a number of
elements, each consisting of a name and value pair.
Policy modules in the kernel bind to specific names
and interpret the values in policy-specific ways. In
the externalized string form, labels are represented
by a comma-delimited list of name and value pairs separated
by the / character. Labels may be
directly converted to and from text using provided APIs;
when retrieving labels from the kernel, internalized
label storage must first be prepared for the desired
label element set. Typically, this is done in one of
two ways: using &man.mac.prepare.3; and an arbitrary
list of desired label elements, or one of the variants
of the call that loads a default element set from the
&man.mac.conf.5; configuration file. Per-object
defaults permit application writers to usefully display
labels associated with objects without being aware of
the policies present in the system.Currently, direct manipulation of label elements
other than by conversion to a text string, string editing,
and conversion back to an internalized label is not supported
by the MAC library. Such interfaces may be added in the
future if they prove necessary for application
writers.Binding of Labels to UsersThe standard user context management interface,
&man.setusercontext.3;, has been modified to retrieve
MAC labels associated with a user's class from
&man.login.conf.5;. These labels are then set along
with other user context when either
LOGIN_SETALL is specified, or when
LOGIN_SETMAC is explicitly
specified.It is expected that, in a future version of FreeBSD,
the MAC label database will be separated from the
login.conf user class abstraction,
and be maintained in a separate database. However, the
&man.setusercontext.3; API should remain the same
following such a change.ConclusionThe TrustedBSD MAC framework permits kernel modules to
augment the system security policy in a highly integrated
manner. They may do this based on existing object properties,
or based on label data that is maintained with the assistance of
the MAC framework. The framework is sufficiently flexible to
implement a variety of policy types, including information flow
security policies such as MLS and Biba, as well as policies
based on existing BSD credentials or file protections. Policy
authors may wish to consult this documentation as well as
existing security modules when implementing a new security
service.
diff --git a/en_US.ISO8859-1/books/arch-handbook/newbus/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/newbus/chapter.sgml
index 4fda867ee6..c20617c4fc 100644
--- a/en_US.ISO8859-1/books/arch-handbook/newbus/chapter.sgml
+++ b/en_US.ISO8859-1/books/arch-handbook/newbus/chapter.sgml
@@ -1,360 +1,360 @@
JeroenRuigrok van der Werven (asmodai)asmodai@FreeBSD.orgWritten by HitenPandyahiten@uk.FreeBSD.orgNewbusSpecial thanks to Matthew N. Dodd, Warner Losh, Bill Paul,
Doug Rabson, Mike Smith, Peter Wemm and Scott Long.This chapter explains the Newbus device framework in detail.Device DriversPurpose of a Device DriverA device driver is a software component which provides the
interface between the kernel's generic view of a peripheral
(e.g. disk, network adapter) and the actual implementation of the
peripheral. The device driver interface (DDI) is
the defined interface between the kernel and the device driver component.
Types of Device DriversThere used to be days in &unix;, and thus FreeBSD, in which there
were four types of devices defined:block device driverscharacter device driversnetwork device driverspseudo-device driversBlock devices performed in way that used
fixed size blocks [of data]. This type of driver depended on the
so called buffer cache, which had the purpose
to cache accessed blocks of data in a dedicated part of the memory.
Often this buffer cache was based on write-behind, which meant that when
data was modified in memory it got synced to disk whenever the system
did its periodical disk flushing, thus optimizing writes.Character devicesHowever, in the versions of FreeBSD 4.0 and onward the
distinction between block and character devices became non-existent.
Overview of NewbusNewbus is the implementation of a new bus
architecture based on abstraction layers which saw its introduction in
FreeBSD 3.0 when the Alpha port was imported into the source tree. It was
not until 4.0 before it became the default system to use for device
drivers. Its goals are to provide a more object oriented means of
interconnecting the various busses and devices which a host system
provides to the Operating System.Its main features include amongst others:dynamic attachingeasy modularization of driverspseudo-bussesOne of the most prominent changes is the migration from the flat and
ad-hoc system to a device tree lay-out.At the top level resides the root
device which is the parent to hang all other devices on. For each
architecture, there is typically a single child of root
which has such things as host-to-PCI bridges, etc.
attached to it. For x86, this root device is the
nexus device and for Alpha, various
different different models of Alpha have different top-level devices
corresponding to the different hardware chipsets, including
lca, apecs,
cia and tsunami.A device in the Newbus context represents a single hardware entity
in the system. For instance each PCI device is represented by a Newbus
device. Any device in the system can have children; a device which has
children is often called a bus.
Examples of common busses in the system are ISA and PCI which manage lists
of devices attached to ISA and PCI busses respectively.Often, a connection between different kinds of bus is represented by
a bridge device which normally has one
child for the attached bus. An example of this is a
PCI-to-PCI bridge which is represented by a device
pcibN on the parent PCI bus
and has a child pciN for the
attached bus. This layout simplifies the implementation of the PCI bus
tree, allowing common code to be used for both top-level and bridged
busses.Each device in the Newbus architecture asks its parent to map its
resources. The parent then asks its own parent until the nexus is
reached. So, basically the nexus is the only part of the Newbus system
which knows about all resources.An ISA device might want to map its IO port at
0x230, so it asks its parent, in this case the ISA
bus. The ISA bus hands it over to the PCI-to-ISA bridge which in its turn
asks the PCI bus, which reaches the host-to-PCI bridge and finally the
nexus. The beauty of this transition upwards is that there is room to
translate the requests. For example, the 0x230 IO port
request might become memory-mapped at 0xb0000230 on a
MIPS box by the PCI bridge.Resource allocation can be controlled at any place in the device
tree. For instance on many Alpha platforms, ISA interrupts are managed
separately from PCI interrupts and resource allocations for ISA interrupts
are managed by the Alpha's ISA bus device. On IA-32, ISA and PCI
interrupts are both managed by the top-level nexus device. For both
ports, memory and port address space is managed by a single entity - nexus
for IA-32 and the relevant chipset driver on Alpha (e.g. CIA or tsunami).
In order to normalize access to memory and port mapped resources,
Newbus integrates the bus_space APIs from NetBSD.
These provide a single API to replace inb/outb and direct memory
reads/writes. The advantage of this is that a single driver can easily
use either memory-mapped registers or port-mapped registers
(some hardware supports both).This support is integrated into the resource allocation mechanism.
When a resource is allocated, a driver can retrieve the associated
bus_space_tag_t and
bus_space_handle_t from the resource.Newbus also allows for definitions of interface methods in files
dedicated to this purpose. These are the .m files
that are found under the src/sys hierarchy.The core of the Newbus system is an extensible
object-based programming model. Each device in the system
has a table of methods which it supports. The system and other devices
uses those methods to control the device and request services. The
different methods supported by a device are defined by a number of
interfaces. An interface is simply a group
of related methods which can be implemented by a device.In the Newbus system, the methods for a device are provided by the
various device drivers in the system. When a device is attached to a
driver during auto-configuration, it uses the method
table declared by the driver. A device can later
detach from its driver and
re-attach to a new driver with a new method table.
This allows dynamic replacement of drivers which can be useful for driver
development.The interfaces are described by an interface definition language
similar to the language used to define vnode operations for file systems.
The interface would be stored in a methods file (which would normally named
foo_if.m).Newbus Methods
# Foo subsystem/driver (a comment...)
INTERFACE foo
METHOD int doit {
device_t dev;
};
# DEFAULT is the method that will be used, if a method was not
# provided via: DEVMETHOD()
METHOD void doit_to_child {
device_t dev;
driver_t child;
} DEFAULT doit_generic_to_child;
When this interface is compiled, it generates a header file
foo_if.h which contains function
declarations:
int FOO_DOIT(device_t dev);
int FOO_DOIT_TO_CHILD(device_t dev, device_t child);
A source file, foo_if.c is
also created to accompany the automatically generated header file; it
contains implementations of those functions which look up the location
of the relevant functions in the object's method table and call that
function.The system defines two main interfaces. The first fundamental
interface is called device and
includes methods which are relevant to all devices. Methods in the
device interface include
probe,
attach and
detach to control detection of
hardware and shutdown,
suspend and
resume for critical event
notification.The second, more complex interface is
bus. This interface contains
methods suitable for devices which have children, including methods to
access bus specific per-device information
&man.bus.generic.read.ivar.9; and
&man.bus.generic.write.ivar.9;, event notification
(child_detached,
driver_added) and resource
management (alloc_resource,
activate_resource,
deactivate_resource,
- release_resource).
+ release_resource).Many methods in the bus interface are performing
services for some child of the bus device. These methods would normally
use the first two arguments to specify the bus providing the service
and the child device which is requesting the service. To simplify
driver code, many of these methods have accessor functions which
lookup the parent and call a method on the parent. For instance the
method
BUS_TEARDOWN_INTR(device_t dev, device_t child, ...)
can be called using the function
bus_teardown_intr(device_t child, ...).Some bus types in the system define additional interfaces to
provide access to bus-specific functionality. For instance, the PCI
bus driver defines the pci interface which has two
methods read_config and
write_config for accessing the
configuration registers of a PCI device.Newbus APIAs the Newbus API is huge, this section makes some effort at
documenting it. More information to come in the next revision of this
document.Important locations in the source hierarchysrc/sys/[arch]/[arch] - Kernel code for a
specific machine architecture resides in this directory. for example,
the i386 architecture, or the
SPARC64 architecture.src/sys/dev/[bus] - device support for a
specific [bus] resides in this directory.src/sys/dev/pci - PCI bus support code
resides in this directory.src/sys/[isa|pci] - PCI/ISA device drivers
reside in this directory. The PCI/ISA bus support code used to exist
in this directory in FreeBSD version 4.0.Important structures and type definitionsdevclass_t - This is a type definition of a
pointer to a struct devclass.device_method_t - This is same as
kobj_method_t (see
src/sys/kobj.h).device_t - This is a type definition of a
pointer to a struct device.
device_t represents a device in the system. It is
a kernel object. See src/sys/sys/bus_private.h
for implementation details.driver_t - This is a type definition which,
references struct driver. The
driver struct is a class of the
device kernel object; it also holds data private
to for the driver.driver_t implementation
struct driver {
KOBJ_CLASS_FIELDS;
void *priv; /* driver private data */
};
A device_state_t type, which is
an enumeration, device_state. It contains
the possible states of a Newbus device before and after the
autoconfiguration process.Device statesdevice_state_t
/*
* src/sys/sys/bus.h
*/
typedef enum device_state {
DS_NOTPRESENT, /* not probed or probe failed */
DS_ALIVE, /* probe succeeded */
DS_ATTACHED, /* attach method called */
DS_BUSY /* device is open */
} device_state_t;
diff --git a/en_US.ISO8859-1/books/arch-handbook/sound/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/sound/chapter.sgml
index aeb4656017..0a107812fa 100644
--- a/en_US.ISO8859-1/books/arch-handbook/sound/chapter.sgml
+++ b/en_US.ISO8859-1/books/arch-handbook/sound/chapter.sgml
@@ -1,687 +1,690 @@
Jean-FrancoisDockesContributed by Sound subsystemIntroductionThe FreeBSD sound subsystem cleanly separates generic sound
handling issues from device-specific ones. This makes it easier
to add support for new hardware.The &man.pcm.4; framework is the central piece of the sound
subsystem. It mainly implements the following elements:A system call interface (read, write, ioctls) to
digitized sound and mixer functions. The ioctl command set
is compatible with the legacy OSS or
Voxware interface, allowing common
multimedia applications to be ported without
modification.
+ Common code for processing sound data (format
conversions, virtual channels).A uniform software interface to hardware-specific audio
interface modules.Additional support for some common hardware interfaces
(ac97), or shared hardware-specific code (ex: ISA DMA
routines).The support for specific sound cards is implemented by
hardware-specific drivers, which provide channel and mixer interfaces
to plug into the generic pcm code.In this chapter, the term pcm will
refer to the central, common part of the sound driver, as
opposed to the hardware-specific modules.The prospective driver writer will of course want to start
from an existing module and use the code as the ultimate
reference. But, while the sound code is nice and clean, it is
also mostly devoid of comments. This document tries to give an
overview of the framework interface and answer some questions
that may arise while adapting the existing code.As an alternative, or in addition to starting from a working
example, you can find a commented driver template at
http://people.FreeBSD.org/~cg/template.cFilesAll the relevant code currently (FreeBSD 4.4) lives in
/usr/src/sys/dev/sound/, except for the
public ioctl interface definitions, found in
/usr/src/sys/sys/soundcard.hUnder /usr/src/sys/dev/sound/, the
pcm/ directory holds the central code,
while the isa/ and
pci/ directories have the drivers for ISA
and PCI boards.Probing, attaching, etc.Sound drivers probe and attach in almost the same way as any
hardware driver module. You might want to look at the ISA or PCI specific sections of the handbook for
more information.However, sound drivers differ in some ways:They declare themselves as pcm
class devices, with a struct
snddev_info device private structure: static driver_t xxx_driver = {
"pcm",
xxx_methods,
sizeof(struct snddev_info)
};
DRIVER_MODULE(snd_xxxpci, pci, xxx_driver, pcm_devclass, 0, 0);
MODULE_DEPEND(snd_xxxpci, snd_pcm, PCM_MINVER, PCM_PREFVER,PCM_MAXVER);Most sound drivers need to store additional private
information about their device. A private data structure is
usually allocated in the attach routine. Its address is
passed to pcm by the calls to
pcm_register() and
mixer_init().
pcm later passes back this address
as a parameter in calls to the sound driver
interfaces.The sound driver attach routine should declare its MIXER
or AC97 interface to pcm by calling
mixer_init(). For a MIXER interface,
this causes in turn a call to
xxxmixer_init().The sound driver attach routine declares its general
CHANNEL configuration to pcm by
calling pcm_register(dev, sc, nplay,
nrec), where sc is the address
for the device data structure, used in further calls from
pcm, and nplay
and nrec are the number of play and
record channels.The sound driver attach routine declares each of its
channel objects by calls to
pcm_addchan(). This sets up the
channel glue in pcm and causes in
turn a call to
xxxchannel_init().The sound driver detach routine should call
pcm_unregister() before releasing its
resources.There are two possible methods to handle non-PnP devices:Use a device_identify() method
(example: sound/isa/es1888.c). The
device_identify() method probes for the
hardware at known addresses and, if it finds a supported
device, creates a new pcm device which is then passed to
probe/attach.Use a custom kernel configuration with appropriate hints
for pcm devices (example:
sound/isa/mss.c).pcm drivers should implement
device_suspend,
device_resume and
device_shutdown routines, so that power
management and module unloading function correctly.InterfacesThe interface between the pcm core
and the sound drivers is defined in terms of kernel objects.There are two main interfaces that a sound driver will
usually provide: CHANNEL and either
MIXER or AC97.The AC97 interface is a very small
hardware access (register read/write) interface, implemented by
drivers for hardware with an AC97 codec. In this case, the
actual MIXER interface is provided by the shared AC97 code in
pcm.The CHANNEL interfaceCommon notes for function parametersSound drivers usually have a private data structure to
describe their device, and one structure for each play and
record data channel that it supports.For all CHANNEL interface functions, the first parameter
is an opaque pointer.The second parameter is a pointer to the private
channel data structure, except for
channel_init() which has a pointer to the
private device structure (and returns the channel pointer
for further use by pcm).Overview of data transfer operationsFor sound data transfers, the
pcm core and the sound drivers
communicate through a shared memory area, described by a
struct snd_dbuf.struct snd_dbuf is private to
pcm, and sound drivers obtain
values of interest by calls to accessor functions
(sndbuf_getxxx()).The shared memory area has a size of
sndbuf_getsize() and is divided into
fixed size blocks of sndbuf_getblksz()
bytes.When playing, the general transfer mechanism is as
follows (reverse the idea for recording):pcm initially fills up the
buffer, then calls the sound driver's
xxxchannel_trigger()
function with a parameter of PCMTRIG_START.The sound driver then arranges to repeatedly
transfer the whole memory area
(sndbuf_getbuf(),
sndbuf_getsize()) to the device, in
blocks of sndbuf_getblksz() bytes.
It calls back the chn_intr()pcm function for each
transferred block (this will typically happen at
interrupt time).chn_intr() arranges to copy new
data to the area that was transferred to the device (now
free), and make appropriate updates to the
snd_dbuf structure.
+
+
channel_initxxxchannel_init() is called to
initialize each of the play or record channels. The calls
are initiated from the sound driver attach routine. (See
the probe and attach
section). static void *
xxxchannel_init(kobj_t obj, void *data,
struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct xxx_info *sc = data;
struct xxx_chinfo *ch;
...
return ch;
}b is the address for the channel
struct snd_dbuf. It should be
initialized in the function by calling
sndbuf_alloc(). The buffer size to
use is normally a small multiple of the 'typical' unit
transfer size for your device.c is the
pcm channel control structure
pointer. This is an opaque object. The function should
store it in the local channel structure, to be used in
later calls to pcm (ie:
chn_intr(c)).dir indicates the channel
direction (PCMDIR_PLAY or
PCMDIR_REC).The function should return a pointer to the private
area used to control this channel. This will be passed
as a parameter to other channel interface calls.channel_setformatxxxchannel_setformat() should set
up the hardware for the specified channel for the specified
sound format. static int
xxxchannel_setformat(kobj_t obj, void *data, u_int32_t format)
{
struct xxx_chinfo *ch = data;
...
return 0;
}format is specified as an
AFMT_XXX value
(soundcard.h).channel_setspeedxxxchannel_setspeed() sets up the
channel hardware for the specified sampling speed, and
returns the possibly adjusted speed. static int
xxxchannel_setspeed(kobj_t obj, void *data, u_int32_t speed)
{
struct xxx_chinfo *ch = data;
...
return speed;
}channel_setblocksizexxxchannel_setblocksize() sets the
block size, which is the size of unit transactions between
pcm and the sound driver, and
between the sound driver and the device. Typically, this
would be the number of bytes transferred before an interrupt
occurs. During a transfer, the sound driver should call
pcm's
chn_intr() every time this size has
been transferred.Most sound drivers only take note of the block size
here, to be used when an actual transfer will be
started. static int
xxxchannel_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
struct xxx_chinfo *ch = data;
...
return blocksize;
}The function returns the possibly adjusted block
size. In case the block size is indeed changed,
sndbuf_resize() should be called to
adjust the buffer.channel_triggerxxxchannel_trigger() is called by
pcm to control data transfer
operations in the driver. static int
xxxchannel_trigger(kobj_t obj, void *data, int go)
{
struct xxx_chinfo *ch = data;
...
return 0;
}go defines the action for the
current call. The possible values are:PCMTRIG_START: the driver
should start a data transfer from or to the channel
buffer. If needed, the buffer base and size can be
retrieved through
sndbuf_getbuf() and
sndbuf_getsize().PCMTRIG_EMLDMAWR /
PCMTRIG_EMLDMARD: this tells the
driver that the input or output buffer may have been
updated. Most drivers just ignore these
calls.PCMTRIG_STOP /
PCMTRIG_ABORT: the driver should
stop the current transfer.If the driver uses ISA DMA,
sndbuf_isadma() should be called before
performing actions on the device, and will take care of the
DMA chip side of things.channel_getptrxxxchannel_getptr() returns the
current offset in the transfer buffer. This will typically
be called by chn_intr(), and this is how
pcm knows where it can transfer
new data.channel_freexxxchannel_free() is called to free
up channel resources, for example when the driver is
unloaded, and should be implemented if the channel data
structures are dynamically allocated or if
sndbuf_alloc() was not used for buffer
allocation.channel_getcaps struct pcmchan_caps *
xxxchannel_getcaps(kobj_t obj, void *data)
{
return &xxx_caps;
}The routine returns a pointer to a (usually
statically-defined) pcmchan_caps
structure (defined in
sound/pcm/channel.h. The structure holds
the minimum and maximum sampling frequencies, and the
accepted sound formats. Look at any sound driver for an
example.More functionschannel_reset(),
channel_resetdone(), and
channel_notify() are for special purposes
and should not be implemented in a driver without discussing
it with the authorities (&a.cg;).channel_setdir() is deprecated.The MIXER interfacemixer_initxxxmixer_init() initializes the
hardware and tells pcm what mixer
devices are available for playing and recording static int
xxxmixer_init(struct snd_mixer *m)
{
struct xxx_info *sc = mix_getdevinfo(m);
u_int32_t v;
[Initialize hardware]
[Set appropriate bits in v for play mixers]
mix_setdevs(m, v);
[Set appropriate bits in v for record mixers]
mix_setrecdevs(m, v)
return 0;
}Set bits in an integer value and call
mix_setdevs() and
mix_setrecdevs() to tell
pcm what devices exist.Mixer bits definitions can be found in
soundcard.h
(SOUND_MASK_XXX values and
SOUND_MIXER_XXX bit shifts).mixer_setxxxmixer_set() sets the volume
level for one mixer device. static int
xxxmixer_set(struct snd_mixer *m, unsigned dev,
unsigned left, unsigned right)
{
struct sc_info *sc = mix_getdevinfo(m);
[set volume level]
return left | (right << 8);
}The device is specified as a SOUND_MIXER_XXX
valueThe volume values are specified in
range [0-100]. A value of zero should mute the
device.As the hardware levels probably won't match the
input scale, and some rounding will occur, the routine
returns the actual level values (in range 0-100) as
shown.mixer_setrecsrcxxxmixer_setrecsrc() sets the
recording source device. static int
xxxmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
{
struct xxx_info *sc = mix_getdevinfo(m);
[look for non zero bit(s) in src, set up hardware]
[update src to reflect actual action]
return src;
}The desired recording devices are specified as a
bit fieldThe actual devices set for recording are returned.
Some drivers can only set one device for recording. The
function should return -1 if an error occurs.mixer_uninit, mixer_reinitxxxmixer_uninit() should ensure
that all sound is muted and if possible mixer hardware
should be powered down xxxmixer_reinit() should ensure
that the mixer hardware is powered up and any settings not
controlled by mixer_set() or
mixer_setrecsrc() are restored.The AC97 interfaceThe AC97 interface is implemented
by drivers with an AC97 codec. It only has three methods:xxxac97_init() returns
the number of ac97 codecs found.ac97_read() and
ac97_write() read or write a specified
register.The AC97 interface is used by the
AC97 code in pcm to perform higher
level operations. Look at
sound/pci/maestro3.c or many others under
sound/pci/ for an example.
diff --git a/en_US.ISO8859-1/books/developers-handbook/boot/chapter.sgml b/en_US.ISO8859-1/books/developers-handbook/boot/chapter.sgml
index 9e8ae2ef1c..0e28c6519e 100644
--- a/en_US.ISO8859-1/books/developers-handbook/boot/chapter.sgml
+++ b/en_US.ISO8859-1/books/developers-handbook/boot/chapter.sgml
@@ -1,1023 +1,1024 @@
SergeyLyubkaContributed by Bootstrapping and kernel initializationSynopsisThis chapter is an overview of the boot and system
initialization process, starting from the BIOS (firmware) POST,
to the first user process creation. Since the initial steps of
system startup are very architecture dependent, the IA-32
architecture is used as an example.OverviewA computer running FreeBSD can boot by several methods,
although the most common method, booting from a harddisk where
the OS is installed, will be discussed here. The boot process
is divided into several steps:BIOS POSTboot0 stageboot2 stageloader stagekernel initializationThe boot0 and boot2
stages are also referred to as bootstrap stages 1 and
2 in &man.boot.8; as the first steps in FreeBSD's
3-stage bootstrapping procedure. Various information is printed
on the screen at each stage, so you may visually recognize them
using the table that follows. Please note that the actual data
may differ from machine to machine:may varyBIOS (firmware) messagesF1 FreeBSD
F2 BSD
F5 Disk 2boot0>>FreeBSD/i386 BOOT
Default: 1:ad(1,a)/boot/loader
boot:boot2This
prompt will appear if the user presses a key just after
selecting an OS to boot at the boot0
stage.BTX loader 1.0 BTX version is 1.01
BIOS drive A: is disk0
BIOS drive C: is disk1
BIOS 639kB/64512kB available memory
FreeBSD/i386 bootstrap loader, Revision 0.8
Console internal video/keyboard
(jkh@bento.freebsd.org, Mon Nov 20 11:41:23 GMT 2000)
/kernel text=0x1234 data=0x2345 syms=[0x4+0x3456]
Hit [Enter] to boot immediately, or any other key for command prompt
Booting [kernel] in 9 seconds..._loaderCopyright (c) 1992-2002 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
The Regents of the University of California. All rights reserved.
FreeBSD 4.6-RC #0: Sat May 4 22:49:02 GMT 2002
devnull@kukas:/usr/obj/usr/src/sys/DEVNULL
Timecounter "i8254" frequency 1193182 HzkernelBIOS POSTWhen the PC powers on, the processor's registers are set
to some predefined values. One of the registers is the
instruction pointer register, and its value
after a power on is well defined: it is a 32-bit value of
0xfffffff0. The instruction pointer register points to code to
be executed by the processor. One of the registers is the
cr1 32-bit control register, and its value
just after the reboot is 0. One of the cr1's bits, the bit PE
(Protected Enabled) indicates whether the processor is running
in protected or real mode. Since at boot time this bit is
cleared, the processor boots in real mode. Real mode means,
among other things, that linear and physical addresses are
identical.The value of 0xfffffff0 is slightly less then 4Gb, so unless
the machine has 4Gb physical memory, it cannot point to a valid
memory address. The computer's hardware translates this address
so that it points to a BIOS memory block.BIOS stands for Basic Input Output
System, and it is a chip on the motherboard that has
a relatively small amount of read-only memory (ROM). This
memory contains various low-level routines that are specific to
the hardware supplied with the motherboard. So, the processor
will first jump to the address 0xfffffff0, which really resides
in the BIOS's memory. Usually this address contains a jump
instruction to the BIOS's POST routines.POST stands for Power On Self Test.
This is a set of routines including the memory check, system bus
check and other low-level stuff so that the CPU can initialize
the computer properly. The important step on this stage is
determining the boot device. All modern BIOS's allow the boot
device to be set manually, so you can boot from a floppy,
CD-ROM, harddisk etc.The very last thing in the POST is the INT
0x19 instruction. That instruction reads 512 bytes
from the first sector of boot device into the memory at address
0x7c00. The term first sector originates
from harddrive architecture, where the magnetic plate is divided
to a number of cylindrical tracks. Tracks are numbered, and
every track is divided by a number (usually 64) sectors. Track
number 0 is the outermost on the magnetic plate, and sector 1,
the first sector (tracks, or, cylinders, are numbered starting
from 0, but sectors - starting from 1), has a special meaning.
It is also called Master Boot Record, or MBR. The remaining
sectors on the first track are never used Some
utilities such as &man.disklabel.8; may store the information in
this area, mostly in the second
sector..boot0 stageTake a look at the file /boot/boot0.
This is a small 512-byte file, and it is exactly what FreeBSD's
installation procedure wrote to your harddisk's MBR if you chose
the bootmanager option at installation time.As mentioned previously, the INT 0x19
instruction loads an MBR, i.e. the boot0
content, into the memory at address 0x7c00. Taking a look at
the file sys/boot/i386/boot0/boot0.s can
give a guess at what is happening there - this is the boot
manager, which is an awesome piece of code written by Robert
Nordier.The MBR, or, boot0, has a special
structure starting from offset 0x1be, called the
partition table. It has 4 records of 16
bytes each, called partition records, which
represent how the harddisk(s) are partitioned, or, in FreeBSD's
terminology, sliced. One byte of those 16 says whether a
partition (slice) is bootable or not. Exactly one record must
have that flag set, otherwise boot0's code
will refuse to proceed.A partition record has the following fields:the 1-byte filesystem typethe 1-byte bootable flagthe 6 byte descriptor in CHS formatthe 8 byte descriptor in LBA formatA partition record descriptor has the information about
where exactly the partition resides on the drive. Both
descriptors, LBA and CHS, describe the same information, but in
different ways: LBA (Logical Block Addressing) has the starting
sector for the partition and the partition's length, while CHS
(Cylinder Head Sector) has coordinates for the first and last
sectors of the partition.The boot manager scans the partition table and prints the
menu on the screen so the user can select what disk and what
slice to boot. By pressing an appropriate key,
boot0 performs the following
actions:modifies the bootable flag for the selected partition to
make it bootable, and clears the previoussaves itself to disk to remember what partition (slice)
has been selected so to use it as the default on the next
bootloads the first sector of the selected partition (slice)
into memory and jumps thereWhat kind of data should reside on the very first sector of
a bootable partition (slice), in our case, a FreeBSD slice? As
you may have already guessed, it is
boot2.boot2 stageYou might wonder, why boot2 comes after
boot0, and not boot1. Actually, there is a
512-byte file called boot1 in the directory
/boot as well. It is used for booting from
a floppy. When booting from a floppy,
boot1 plays the same role as
boot0 for a harddisk: it locates
boot2 and runs it.You may have realized that a file
/boot/mbr exists as well. It is a
simplified version of boot0. The code in
mbr does not provide a menu for the user,
it just blindly boots the partition marked active.The code implementing boot2 resides in
sys/boot/i386/boot2/, and the executable
itself is in /boot. The files
boot0 and boot2 that
are in /boot are not used by the bootstrap,
but by utilities such as boot0cfg.
The actual position for boot0 is in the
MBR. For boot2 it is the beginning of a
bootable FreeBSD slice. These locations are not under the
filesystem's control, so they are invisible to commands like
ls.The main task for boot2 is to load the
file /boot/loader, which is the third stage
in the bootstrapping procedure. The code in
boot2 cannot use any services like
open() and read(),
since the kernel is not yet loaded. It must scan the harddisk,
knowing about the filesystem structure, find the file
/boot/loader, read it into memory using a
BIOS service, and then pass the execution to the loader's entry
point.Besides that, boot2 prompts for user
input so the loader can be booted from different disk, unit,
slice and partition.The boot2 binary is created in special
way:sys/boot/i386/boot2/Makefile
boot2: boot2.ldr boot2.bin ${BTX}/btx/btx
btxld -v -E ${ORG2} -f bin -b ${BTX}/btx/btx -l boot2.ldr \
-o boot2.ld -P 1 boot2.binThis Makefile snippet shows that &man.btxld.8; is used to
link the binary. BTX, which stands for BooT eXtender, is a
piece of code that provides a protected mode environment for the
program, called the client, that it is linked with. So
boot2 is a BTX client, i.e. it uses the
service provided by BTX.The btxld utility is the linker.
It links two binaries together. The difference between
&man.btxld.8; and &man.ld.1; is that
ld usually links object files into a
shared object or executable, while
btxld links an object file with the
BTX, producing the binary file suitable to be put on the
beginning of the partition for the system boot.boot0 passes the execution to BTX's entry
point. BTX then switches the processor to protected mode, and
prepares a simple environment before calling the client. This
includes:virtual v86 mode. That means, the BTX is a v86
monitor. Real mode instructions like posh, popf, cli, sti, if
called by the client, will work.Interrupt Descriptor Table (IDT) is set up so
all hardware interrupts are routed to the default BIOS's
handlers, and interrupt 0x30 is set up to be the syscall
gate.Two system calls: exec and
exit, are defined:sys/boot/i386/btx/lib/btxsys.s:
.set INT_SYS,0x30 # Interrupt number
#
# System call: exit
#
__exit: xorl %eax,%eax # BTX system
int $INT_SYS # call 0x0
#
# System call: exec
#
__exec: movl $0x1,%eax # BTX system
int $INT_SYS # call 0x1BTX creates a Global Descriptor Table (GDT):sys/boot/i386/btx/btx/btx.s:
gdt: .word 0x0,0x0,0x0,0x0 # Null entry
.word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE
.word 0xffff,0x0,0x9200,0xcf # SEL_SDATA
.word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
.word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
.word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
.word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
.word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSSThe client's code and data start from address MEM_USR
(0xa000), and a selector (SEL_UCODE) points to the client's code
segment. The SEL_UCODE descriptor has Descriptor Privilege
Level (DPL) 3, which is the lowest privilege level. But the
INT 0x30 instruction handler resides in a
segment pointed to by the SEL_SCODE (supervisor code) selector,
as shown from the code that creates an IDT: mov $SEL_SCODE,%dh # Segment selector
init.2: shr %bx # Handle this int?
jnc init.3 # No
mov %ax,(%di) # Set handler offset
mov %dh,0x2(%di) # and selector
mov %dl,0x5(%di) # Set P:DPL:type
add $0x4,%ax # Next handlerSo, when the client calls __exec(), the
code will be executed with the highest privileges. This allows
the kernel to change the protected mode data structures, such as
page tables, GDT, IDT, etc later, if needed.boot2 defines an important structure,
struct bootinfo. This structure is
initialized by boot2 and passed to the
loader, and then further to the kernel. Some nodes of this
structures are set by boot2, the rest by the
loader. This structure, among other information, contains the
kernel filename, BIOS harddisk geometry, BIOS drive number for
boot device, physical memory available, envp
pointer etc. The definition for it is:/usr/include/machine/bootinfo.h
struct bootinfo {
u_int32_t bi_version;
u_int32_t bi_kernelname; /* represents a char * */
u_int32_t bi_nfs_diskless; /* struct nfs_diskless * */
/* End of fields that are always present. */
#define bi_endcommon bi_n_bios_used
u_int32_t bi_n_bios_used;
u_int32_t bi_bios_geom[N_BIOS_GEOM];
u_int32_t bi_size;
u_int8_t bi_memsizes_valid;
u_int8_t bi_bios_dev; /* bootdev BIOS unit number */
u_int8_t bi_pad[2];
u_int32_t bi_basemem;
u_int32_t bi_extmem;
u_int32_t bi_symtab; /* struct symtab * */
u_int32_t bi_esymtab; /* struct symtab * */
/* Items below only from advanced bootloader */
u_int32_t bi_kernend; /* end of kernel space */
u_int32_t bi_envp; /* environment */
u_int32_t bi_modulep; /* preloaded modules */
};boot2 enters into an infinite loop waiting
for user input, then calls load(). If the
user does not press anything, the loop brakes by a timeout, so
load() will load the default file
(/boot/loader). Functions ino_t
lookup(char *filename) and int xfsread(ino_t
inode, void *buf, size_t nbyte) are used to read the
content of a file into memory. /boot/loader
is an ELF binary, but where the ELF header is prepended with
a.out's struct exec structure.
load() scans the loader's ELF header, loading
the content of /boot/loader into memory, and
passing the execution to the loader's entry:sys/boot/i386/boot2/boot2.c:
__exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part),
0, 0, 0, VTOP(&bootinfo));loader stageloader is a BTX client as well.
I will not describe it here in detail, there is a comprehensive
manpage written by Mike Smith, &man.loader.8;. The underlying
mechanisms and BTX were discussed above.The main task for the loader is to boot the kernel. When
the kernel is loaded into memory, it is being called by the
loader:sys/boot/common/boot.c:
/* Call the exec handler from the loader matching the kernel */
module_formats[km->m_loader]->l_exec(km);Kernel initializationTo where exactly is the execution passed by the loader,
i.e. what is the kernel's actual entry point. Let us take a
look at the command that links the kernel:sys/conf/Makefile.i386:
ld -elf -Bdynamic -T /usr/src/sys/conf/ldscript.i386 -export-dynamic \
-dynamic-linker /red/herring -o kernel -X locore.o \
<lots of kernel .o files>A few interesting things can be seen in this line. First,
the kernel is an ELF dynamically linked binary, but the dynamic
linker for kernel is /red/herring, which is
definitely a bogus file. Second, taking a look at the file
sys/conf/ldscript.i386 gives an idea about
what ld options are used when
compiling a kernel. Reading through the first few lines, the
stringsys/conf/ldscript.i386:
ENTRY(btext)says that a kernel's entry point is the symbol `btext'.
This symbol is defined in locore.s:sys/i386/i386/locore.s:
.text
/**********************************************************************
*
* This is where the bootblocks start us, set the ball rolling...
*
*/
NON_GPROF_ENTRY(btext)First what is done is the register EFLAGS is set to a
predefined value of 0x00000002, and then all the segment
registers are initialized:sys/i386/i386/locore.s
/* Don't trust what the BIOS gives for eflags. */
pushl $PSL_KERNEL
popfl
/*
* Don't trust what the BIOS gives for %fs and %gs. Trust the bootstrap
* to set %cs, %ds, %es and %ss.
*/
mov %ds, %ax
mov %ax, %fs
mov %ax, %gsbtext calls the routines
recover_bootinfo(),
identify_cpu(),
create_pagetables(), which are also defined
in locore.s. Here is a description of what
they do:recover_bootinfoThis routine parses the parameters to the kernel
passed from the bootstrap. The kernel may have been
booted in 3 ways: by the loader, described above, by the
old disk boot blocks, and by the old diskless boot
procedure. This function determines the booting method,
and stores the struct bootinfo
structure into the kernel memory.identify_cpuThis functions tries to find out what CPU it is
running on, storing the value found in a variable
_cpu.create_pagetablesThis function allocates and fills out a Page Table
Directory at the top of the kernel memory area.
+
The next steps are enabling VME, if the CPU supports
it: testl $CPUID_VME, R(_cpu_feature)
jz 1f
movl %cr4, %eax
orl $CR4_VME, %eax
movl %eax, %cr4Then, enabling paging:/* Now enable paging */
movl R(_IdlePTD), %eax
movl %eax,%cr3 /* load ptd addr into mmu */
movl %cr0,%eax /* get control word */
orl $CR0_PE|CR0_PG,%eax /* enable paging */
movl %eax,%cr0 /* and let's page NOW! */The next three lines of code are because the paging was set,
so the jump is needed to continue the execution in virtualized
address space: pushl $begin /* jump to high virtualized address */
ret
/* now running relocated at KERNBASE where the system is linked to run */
begin:The function init386() is called, with
a pointer to the first free physical page, after that
mi_startup(). init386
is an architecture dependent initialization function, and
mi_startup() is an architecture independent
one (the 'mi_' prefix stands for Machine Independent). The
kernel never returns from mi_startup(), and
by calling it, the kernel finishes booting:sys/i386/i386/locore.s:
movl physfree, %esi
pushl %esi /* value of first for init386(first) */
call _init386 /* wire 386 chip for unix operation */
call _mi_startup /* autoconfiguration, mountroot etc */
hlt /* never returns to here */init386()init386() is defined in
sys/i386/i386/machdep.c and performs
low-level initialization, specific to the i386 chip. The
switch to protected mode was performed by the loader. The
loader has created the very first task, in which the kernel
continues to operate. Before running straight away to the
code, I will enumerate the tasks the processor must complete
to initialize protected mode execution:Initialize the kernel tunable parameters, passed from
the bootstrapping program.Prepare the GDT.Prepare the IDT.Initialize the system console.Initialize the DDB, if it is compiled into
kernel.Initialize the TSS.Prepare the LDT.Setup proc0's pcb.What init386() first does is
initialize the tunable parameters passed from bootstrap. This
is done by setting the environment pointer (envp) and calling
init_param1(). The envp pointer has been
passed from loader in the bootinfo
structure:sys/i386/i386/machdep.c:
kern_envp = (caddr_t)bootinfo.bi_envp + KERNBASE;
/* Init basic tunables, hz etc */
init_param1();init_param1() is defined in
sys/kern/subr_param.c. That file has a
number of sysctls, and two functions,
init_param1() and
init_param2(), that are called from
init386():sys/kern/subr_param.c
hz = HZ;
TUNABLE_INT_FETCH("kern.hz", &hz);TUNABLE_<typename>_FETCH is used to fetch the value
from the environment:/usr/src/sys/sys/kernel.h
#define TUNABLE_INT_FETCH(path, var) getenv_int((path), (var))
Sysctl kern.hz is the system clock tick. Along with
this, the following sysctls are set by
init_param1(): kern.maxswzone,
kern.maxbcache, kern.maxtsiz, kern.dfldsiz, kern.dflssiz,
kern.maxssiz, kern.sgrowsiz.Then init386() prepares the Global
Descriptors Table (GDT). Every task on an x86 is running in
its own virtual address space, and this space is addressed by
a segment:offset pair. Say, for instance, the current
instruction to be executed by the processor lies at CS:EIP,
then the linear virtual address for that instruction would be
the virtual address of code segment CS + EIP. For
convenience, segments begin at virtual address 0 and end at a
4Gb boundary. Therefore, the instruction's linear virtual
address for this example would just be the value of EIP.
Segment registers such as CS, DS etc are the selectors,
i.e. indexes, into GDT (to be more precise, an index is not a
selector itself, but the INDEX field of a selector).
FreeBSD's GDT holds descriptors for 15 selectors per
CPU:sys/i386/i386/machdep.c:
union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */
sys/i386/include/segments.h:
/*
* Entries in the Global Descriptor Table (GDT)
*/
#define GNULL_SEL 0 /* Null Descriptor */
#define GCODE_SEL 1 /* Kernel Code Descriptor */
#define GDATA_SEL 2 /* Kernel Data Descriptor */
#define GPRIV_SEL 3 /* SMP Per-Processor Private Data */
#define GPROC0_SEL 4 /* Task state process slot zero and up */
#define GLDT_SEL 5 /* LDT - eventually one per process */
#define GUSERLDT_SEL 6 /* User LDT */
#define GTGATE_SEL 7 /* Process task switch gate */
#define GBIOSLOWMEM_SEL 8 /* BIOS low memory access (must be entry 8) */
#define GPANIC_SEL 9 /* Task state to consider panic from */
#define GBIOSCODE32_SEL 10 /* BIOS interface (32bit Code) */
#define GBIOSCODE16_SEL 11 /* BIOS interface (16bit Code) */
#define GBIOSDATA_SEL 12 /* BIOS interface (Data) */
#define GBIOSUTIL_SEL 13 /* BIOS interface (Utility) */
#define GBIOSARGS_SEL 14 /* BIOS interface (Arguments) */Note that those #defines are not selectors themselves, but
just a field INDEX of a selector, so they are exactly the
indices of the GDT. for example, an actual selector for the
kernel code (GCODE_SEL) has the value 0x08.The next step is to initialize the Interrupt Descriptor
Table (IDT). This table is to be referenced by the processor
when a software or hardware interrupt occurs. For example, to
make a system call, user application issues the INT
0x80 instruction. This is a software interrupt, so
the processor's hardware looks up a record with index 0x80 in
the IDT. This record points to the routine that handles this
interrupt, in this particular case, this will be the kernel's
syscall gate. The IDT may have a maximum of 256 (0x100)
records. The kernel allocates NIDT records for the IDT, where
NIDT is the maximum (256):sys/i386/i386/machdep.c:
static struct gate_descriptor idt0[NIDT];
struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */
For each interrupt, an appropriate handler is set. The
syscall gate for INT 0x80 is set as
well:sys/i386/i386/machdep.c:
setidt(0x80, &IDTVEC(int0x80_syscall),
SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL));So when a userland application issues the INT
0x80 instruction, control will transfer to the
function _Xint0x80_syscall, which is in
the kernel code segment and will be executed with supervisor
privileges.Console and DDB are then initialized:sys/i386/i386/machdep.c:
cninit();
/* skipped */
#ifdef DDB
kdb_init();
if (boothowto & RB_KDB)
Debugger("Boot flags requested debugger");
#endifThe Task State Segment is another x86 protected mode
structure, the TSS is used by the hardware to store task
information when a task switch occurs.The Local Descriptors Table is used to reference userland
code and data. Several selectors are defined to point to the
LDT, they are the system call gates and the user code and data
selectors:/usr/include/machine/segments.h
#define LSYS5CALLS_SEL 0 /* forced by intel BCS */
#define LSYS5SIGR_SEL 1
#define L43BSDCALLS_SEL 2 /* notyet */
#define LUCODE_SEL 3
#define LSOL26CALLS_SEL 4 /* Solaris >= 2.6 system call gate */
#define LUDATA_SEL 5
/* separate stack, es,fs,gs sels ? */
/* #define LPOSIXCALLS_SEL 5*/ /* notyet */
#define LBSDICALLS_SEL 16 /* BSDI system call gate */
#define NLDT (LBSDICALLS_SEL + 1)
Next, proc0's Process Control Block (struct
pcb) structure is initialized. proc0 is a
struct proc structure that describes a kernel
process. It is always present while the kernel is running,
therefore it is declared as global:sys/kern/kern_init.c:
struct proc proc0;The structure struct pcb is a part of a
proc structure. It is defined in
/usr/include/machine/pcb.h and has a
process's information specific to the i386 architecture, such as
registers values.mi_startup()This function performs a bubble sort of all the system
initialization objects and then calls the entry of each object
one by one:sys/kern/init_main.c:
for (sipp = sysinit; *sipp; sipp++) {
/* ... skipped ... */
/* Call function */
(*((*sipp)->func))((*sipp)->udata);
/* ... skipped ... */
}Although the sysinit framework is described in the
Developers' Handbook, I will discuss the internals of it.Every system initialization object (sysinit object) is
created by calling a SYSINIT() macro. Let us take as example an
announce sysinit object. This object prints
the copyright message:sys/kern/init_main.c:
static void
print_caddr_t(void *data __unused)
{
printf("%s", (char *)data);
}
SYSINIT(announce, SI_SUB_COPYRIGHT, SI_ORDER_FIRST, print_caddr_t, copyright)The subsystem ID for this object is SI_SUB_COPYRIGHT
(0x0800001), which comes right after the SI_SUB_CONSOLE
(0x0800000). So, the copyright message will be printed out
first, just after the console initialization.Let us take a look at what exactly the macro
SYSINIT() does. It expands to a
C_SYSINIT() macro. The
C_SYSINIT() macro then expands to a static
struct sysinit structure declaration with
another DATA_SET macro call:/usr/include/sys/kernel.h:
#define C_SYSINIT(uniquifier, subsystem, order, func, ident) \
static struct sysinit uniquifier ## _sys_init = { \ subsystem, \
order, \ func, \ ident \ }; \ DATA_SET(sysinit_set,uniquifier ##
_sys_init);
#define SYSINIT(uniquifier, subsystem, order, func, ident) \
C_SYSINIT(uniquifier, subsystem, order, \
(sysinit_cfunc_t)(sysinit_nfunc_t)func, (void *)ident)The DATA_SET() macro expands to a
MAKE_SET(), and that macro is the point where
the all sysinit magic is hidden:/usr/include/linker_set.h
#define MAKE_SET(set, sym) \
static void const * const __set_##set##_sym_##sym = &sym; \
__asm(".section .set." #set ",\"aw\""); \
__asm(".long " #sym); \
__asm(".previous")
#endif
#define TEXT_SET(set, sym) MAKE_SET(set, sym)
#define DATA_SET(set, sym) MAKE_SET(set, sym)In our case, the following declaration will occur:static struct sysinit announce_sys_init = {
SI_SUB_COPYRIGHT,
SI_ORDER_FIRST,
(sysinit_cfunc_t)(sysinit_nfunc_t) print_caddr_t,
(void *) copyright
};
static void const *const __set_sysinit_set_sym_announce_sys_init =
&announce_sys_init;
__asm(".section .set.sysinit_set" ",\"aw\"");
__asm(".long " "announce_sys_init");
__asm(".previous");The first __asm instruction will create
an ELF section within the kernel's executable. This will happen
at kernel link time. The section will have the name
.set.sysinit_set. The content of this section is one 32-bit
value, the address of announce_sys_init structure, and that is
what the second __asm is. The third
__asm instruction marks the end of a section.
If a directive with the same section name occurred before, the
content, i.e. the 32-bit value, will be appended to the existing
section, so forming an array of 32-bit pointers.Running objdump on a kernel
binary, you may notice the presence of such small
sections:&prompt.user; objdump -h /kernel
7 .set.cons_set 00000014 c03164c0 c03164c0 002154c0 2**2
CONTENTS, ALLOC, LOAD, DATA
8 .set.kbddriver_set 00000010 c03164d4 c03164d4 002154d4 2**2
CONTENTS, ALLOC, LOAD, DATA
9 .set.scrndr_set 00000024 c03164e4 c03164e4 002154e4 2**2
CONTENTS, ALLOC, LOAD, DATA
10 .set.scterm_set 0000000c c0316508 c0316508 00215508 2**2
CONTENTS, ALLOC, LOAD, DATA
11 .set.sysctl_set 0000097c c0316514 c0316514 00215514 2**2
CONTENTS, ALLOC, LOAD, DATA
12 .set.sysinit_set 00000664 c0316e90 c0316e90 00215e90 2**2
CONTENTS, ALLOC, LOAD, DATAThis screen dump shows that the size of .set.sysinit_set
section is 0x664 bytes, so 0x664/sizeof(void
*) sysinit objects are compiled into the kernel. The
other sections such as .set.sysctl_set
represent other linker sets.By defining a variable of type struct
linker_set the content of
.set.sysinit_set section will be collected
into that variable:sys/kern/init_main.c:
extern struct linker_set sysinit_set; /* XXX */The struct linker_set is defined as
follows:/usr/include/linker_set.h:
struct linker_set {
int ls_length;
void *ls_items[1]; /* really ls_length of them, trailing NULL */
};The first node will be equal to the number of a sysinit
objects, and the second node will be a NULL-terminated array of
pointers to them.Returning to the mi_startup()
discussion, it is must be clear now, how the sysinit objects are
being organized. The mi_startup() function
sorts them and calls each. The very last object is the system
scheduler:/usr/include/sys/kernel.h:
enum sysinit_sub_id {
SI_SUB_DUMMY = 0x0000000, /* not executed; for linker*/
SI_SUB_DONE = 0x0000001, /* processed*/
SI_SUB_CONSOLE = 0x0800000, /* console*/
SI_SUB_COPYRIGHT = 0x0800001, /* first use of console*/
...
SI_SUB_RUN_SCHEDULER = 0xfffffff /* scheduler: no return*/
};The system scheduler sysinit object is defined in the file
sys/vm/vm_glue.c, and the entry point for
that object is scheduler(). That function
is actually an infinite loop, and it represents a process with
PID 0, the swapper process. The proc0 structure, mentioned
before, is used to describe it.The first user process, called init, is
created by the sysinit object init:sys/kern/init_main.c:
static void
create_init(const void *udata __unused)
{
int error;
int s;
s = splhigh();
error = fork1(&proc0, RFFDG | RFPROC, &initproc);
if (error)
panic("cannot fork init: %d\n", error);
initproc->p_flag |= P_INMEM | P_SYSTEM;
cpu_set_fork_handler(initproc, start_init, NULL);
remrunqueue(initproc);
splx(s);
}
SYSINIT(init,SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL)The create_init() allocates a new process
by calling fork1(), but does not mark it
runnable. When this new process is scheduled for execution by the
scheduler, the start_init() will be called.
That function is defined in init_main.c. It
tries to load and exec the init binary,
probing /sbin/init first, then
/sbin/oinit,
/sbin/init.bak, and finally
/stand/sysinstall:sys/kern/init_main.c:
static char init_path[MAXPATHLEN] =
#ifdef INIT_PATH
__XSTRING(INIT_PATH);
#else
"/sbin/init:/sbin/oinit:/sbin/init.bak:/stand/sysinstall";
#endif
diff --git a/en_US.ISO8859-1/books/developers-handbook/jail/chapter.sgml b/en_US.ISO8859-1/books/developers-handbook/jail/chapter.sgml
index f792cbd338..5bf43c7833 100644
--- a/en_US.ISO8859-1/books/developers-handbook/jail/chapter.sgml
+++ b/en_US.ISO8859-1/books/developers-handbook/jail/chapter.sgml
@@ -1,597 +1,597 @@
EvanSarmientoevms@cs.bu.edu2001Evan SarmientoThe Jail SubsystemOn most UNIX systems, root has omnipotent power. This promotes
insecurity. If an attacker were to gain root on a system, he would
have every function at his fingertips. In FreeBSD there are
sysctls which dilute the power of root, in order to minimize the
damage caused by an attacker. Specifically, one of these functions
is called secure levels. Similarly, another function which is
present from FreeBSD 4.0 and onward, is a utility called
&man.jail.8;. Jail chroots an
environment and sets certain restrictions on processes which are
forked from within. For example, a jailed process cannot affect
processes outside of the jail, utilize certain system calls, or
inflict any damage on the main computer.Jail is becoming the new security
model. People are running potentially vulnerable servers such as
Apache, BIND, and sendmail within jails, so that if an attacker
gains root within the Jail, it is only
an annoyance, and not a devastation. This article focuses on the
internals (source code) of Jail.
It will also suggest improvements upon the jail code base which
are already being worked on. If you are looking for a how-to on
setting up a Jail, I suggest you look
at my other article in Sys Admin Magazine, May 2001, entitled
"Securing FreeBSD using Jail."ArchitectureJail consists of two realms: the
user-space program, jail, and the code implemented within the
kernel: the jail() system call and associated
restrictions. I will be discussing the user-space program and
then how jail is implemented within the kernel.Userland codeThe source for the user-land jail is located in
/usr/src/usr.sbin/jail, consisting of
one file, jail.c. The program takes these
arguments: the path of the jail, hostname, ip address, and the
command to be executed.Data StructuresIn jail.c, the first thing I would
note is the declaration of an important structure
struct jail j; which was included from
- /usr/include/sys/jail.h.
+ /usr/include/sys/jail.h.The definition of the jail structure is:/usr/include/sys/jail.h:
struct jail {
u_int32_t version;
char *path;
char *hostname;
u_int32_t ip_number;
};As you can see, there is an entry for each of the
arguments passed to the jail program, and indeed, they are
set during it's execution./usr/src/usr.sbin/jail.c
j.version = 0;
j.path = argv[1];
j.hostname = argv[2];NetworkingOne of the arguments passed to the Jail program is an IP
address with which the jail can be accessed over the
network. Jail translates the ip address given into network
byte order and then stores it in j (the jail structure)./usr/src/usr.sbin/jail/jail.c:
struct in.addr in;
...
i = inet.aton(argv[3], );
...
j.ip_number = ntohl(in.s.addr);The
inet_aton3
function "interprets the specified character string as an
Internet address, placing the address into the structure
provided." The ip number node in the jail structure is set
only when the ip address placed onto the in structure by
inet aton is translated into network byte order by
ntohl().Jailing The ProcessFinally, the userland program jails the process, and
executes the command specified. Jail now becomes an
imprisoned process itself and forks a child process which
- then executes the command given using &man.execv.3;
+ then executes the command given using &man.execv.3;/usr/src/sys/usr.sbin/jail/jail.c
i = jail();
...
i = execv(argv[4], argv + 4);As you can see, the jail function is being called, and
its argument is the jail structure which has been filled
with the arguments given to the program. Finally, the
program you specify is executed. I will now discuss how Jail
is implemented within the kernel.Kernel SpaceWe will now be looking at the file
/usr/src/sys/kern/kern_jail.c. This is
the file where the jail system call, appropriate sysctls, and
networking functions are defined.sysctlsIn kern_jail.c, the following
sysctls are defined:/usr/src/sys/kern/kern_jail.c:
int jail_set_hostname_allowed = 1;
SYSCTL_INT(_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW,
_set_hostname_allowed, 0,
"Processes in jail can set their hostnames");
int jail_socket_unixiproute_only = 1;
SYSCTL_INT(_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW,
_socket_unixiproute_only, 0,
"Processes in jail are limited to creating UNIX/IPv4/route sockets only
");
int jail_sysvipc_allowed = 0;
SYSCTL_INT(_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW,
_sysvipc_allowed, 0,
"Processes in jail can use System V IPC primitives");Each of these sysctls can be accessed by the user
through the sysctl program. Throughout the kernel, these
specific sysctls are recognized by their name. For example,
the name of the first sysctl is
jail.set.hostname.allowed.&man.jail.2; system callLike all system calls, the &man.jail.2; system call takes
two arguments, struct proc *p and
struct jail_args
*uap. p is a pointer to a proc
structure which describes the calling process. In this
context, uap is a pointer to a structure which specifies the
arguments given to &man.jail.2; from the userland program
jail.c. When I described the userland
program before, you saw that the &man.jail.2; system call was
given a jail structure as its own argument./usr/src/sys/kern/kern_jail.c:
int
jail(p, uap)
struct proc *p;
struct jail_args /* {
syscallarg(struct jail *) jail;
} */ *uap;Therefore, uap->jail would access the
jail structure which was passed to the system call. Next,
the system call copies the jail structure into kernel space
using the copyin()
function. copyin() takes three arguments:
the data which is to be copied into kernel space,
uap->jail, where to store it,
j and the size of the storage. The jail
structure uap->jail is copied into kernel
space and stored in another jail structure,
j./usr/src/sys/kern/kern_jail.c:
error = copyin(uap->jail, , sizeof j);There is another important structure defined in
jail.h. It is the prison structure
(pr). The prison structure is used
exclusively within kernel space. The &man.jail.2; system call
copies everything from the jail structure onto the prison
structure. Here is the definition of the prison structure./usr/include/sys/jail.h:
struct prison {
int pr_ref;
char pr_host[MAXHOSTNAMELEN];
u_int32_t pr_ip;
void *pr_linux;
};The jail() system call then allocates memory for a
pointer to a prison structure and copies data between the two
structures./usr/src/sys/kern/kern_jail.c:
MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK);
bzero((caddr_t)pr, sizeof *pr);
error = copyinstr(j.hostname, pr_host]]>, sizeof pr->pr_host, 0);
if (error)
goto bail;Finally, the jail system call chroots the path
specified. The chroot function is given two arguments. The
first is p, which represents the calling process, the second
is a pointer to the structure chroot args. The structure
chroot args contains the path which is to be chrooted. As
you can see, the path specified in the jail structure is
copied to the chroot args structure and used./usr/src/sys/kern/kern_jail.c:
ca.path = j.path;
error = chroot(p, );These next three lines in the source are very important,
as they specify how the kernel recognizes a process as
jailed. Each process on a Unix system is described by its
own proc structure. You can see the whole proc structure in
/usr/include/sys/proc.h. For example,
the p argument in any system call is actually a pointer to
that process' proc structure, as stated before. The proc
structure contains nodes which can describe the owner's
identity (p_cred), the process resource
limits (p_limit), and so on. In the
definition of the process structure, there is a pointer to a
prison structure. (p_prison)./usr/include/sys/proc.h:
struct proc {
...
struct prison *p_prison;
...
};In kern_jail.c, the function then
copies the pr structure, which is filled with all the
information from the original jail structure, over to the
p->p_prison structure. It then does a
bitwise OR of p->p_flag with the constant
P_JAILED, meaning that the calling
process is now recognized as jailed. The parent process of
each process, forked within the jail, is the program jail
itself, as it calls the &man.jail.2; system call. When the
program is executed through execve, it inherits the
properties of its parents proc structure, therefore it has
the p->p_flag set, and the
p->p_prison structure is filled./usr/src/sys/kern/kern_jail.c
p->p.prison = pr;
p->p.flag |= P.JAILED;When a process is forked from a parent process, the
&man.fork.2; system call deals differently with imprisoned
processes. In the fork system call, there are two pointers
to a proc structure p1
and p2. p1 points to
the parent's proc structure and p2 points
to the child's unfilled proc
structure. After copying all relevant data between the
structures, &man.fork.2; checks if the structure
p->p_prison is filled on
p2. If it is, it increments the
pr.ref by one, and sets the
p_flag to one on the child process./usr/src/sys/kern/kern_fork.c:
if (p2->p_prison) {
p2->p_prison->pr_ref++;
p2->p_flag |= P_JAILED;
}RestrictionsThroughout the kernel there are access restrictions relating
to jailed processes. Usually, these restrictions only check if
the process is jailed, and if so, returns an error. For
example:if (p->p_prison)
return EPERM;SysV IPCSystem V IPC is based on messages. Processes can send each
other these messages which tell them how to act. The functions
which deal with messages are: msgsys,
msgctl, msgget,
msgsend and msgrcv.
Earlier, I mentioned that there were certain sysctls you could
turn on or off in order to affect the behavior of Jail. One of
these sysctls was jail_sysvipc_allowed. On
most systems, this sysctl is set to 0. If it were set to 1, it
would defeat the whole purpose of having a jail; privleged
users from within the jail would be able to affect processes
outside of the environment. The difference between a message
and a signal is that the message only consists of the signal
number./usr/src/sys/kern/sysv_msg.c:&man.msgget.3;: msgget returns (and possibly
creates) a message descriptor that designates a message queue
for use in other system calls.&man.msgctl.3;: Using this function, a process
can query the status of a message
descriptor.&man.msgsnd.3;: msgsnd sends a message to a
process.&man.msgrcv.3;: a process receives messages using
this functionIn each of these system calls, there is this
conditional:/usr/src/sys/kern/sysv msg.c:
if (!jail.sysvipc.allowed && p->p_prison != NULL)
return (ENOSYS);Semaphore system calls allow processes to synchronize
execution by doing a set of operations atomically on a set of
semaphores. Basically semaphores provide another way for
processes lock resources. However, process waiting on a
semaphore, that is being used, will sleep until the resources
are relinquished. The following semaphore system calls are
blocked inside a jail: semsys,
semget, semctl and
semop./usr/src/sys/kern/sysv_sem.c:&man.semctl.2;(id, num, cmd, arg):
Semctl does the specified cmd on the semaphore queue
indicated by id.&man.semget.2;(key, nsems, flag):
Semget creates an array of semaphores, corresponding to
key.Key and flag take on the same meaning as they
do in msgget.&man.semop.2;(id, ops, num):
Semop does the set of semaphore operations in the array of
structures ops, to the set of semaphores identified by
id.System V IPC allows for processes to share
memory. Processes can communicate directly with each other by
sharing parts of their virtual address space and then reading
and writing data stored in the shared memory. These system
calls are blocked within a jailed environment: shmdt,
shmat, oshmctl, shmctl, shmget, and
shmsys./usr/src/sys/kern/sysv shm.c:&man.shmctl.2;(id, cmd, buf):
shmctl does various control operations on the shared memory
region identified by id.&man.shmget.2;(key, size,
flag): shmget accesses or creates a shared memory
region of size bytes.&man.shmat.2;(id, addr, flag):
shmat attaches a shared memory region identified by id to the
address space of a process.&man.shmdt.2;(addr): shmdt
detaches the shared memory region previously attached at
addr.SocketsJail treats the &man.socket.2; system call and related
lower-level socket functions in a special manner. In order to
determine whether a certain socket is allowed to be created,
it first checks to see if the sysctl
jail.socket.unixiproute.only is set. If
set, sockets are only allowed to be created if the family
specified is either PF_LOCAL,
PF_INET or
PF_ROUTE. Otherwise, it returns an
error./usr/src/sys/kern/uipc_socket.c:
int socreate(dom, aso, type, proto, p)
...
register struct protosw *prp;
...
{
if (p->p_prison && jail_socket_unixiproute_only &&
prp->pr_domain->dom_family != PR_LOCAL && prp->pr_domain->dom_family != PF_INET
&& prp->pr_domain->dom_family != PF_ROUTE)
return (EPROTONOSUPPORT);
...
}Berkeley Packet FilterThe Berkeley Packet Filter provides a raw interface to
data link layers in a protocol independent fashion. The
function bpfopen() opens an Ethernet
device. There is a conditional which disallows any jailed
processes from accessing this function./usr/src/sys/net/bpf.c:
static int bpfopen(dev, flags, fmt, p)
...
{
if (p->p_prison)
return (EPERM);
...
}ProtocolsThere are certain protocols which are very common, such as
TCP, UDP, IP and ICMP. IP and ICMP are on the same level: the
network layer 2. There are certain precautions which are
taken in order to prevent a jailed process from binding a
protocol to a certain port only if the nam
parameter is set. nam is a pointer to a sockaddr structure,
which describes the address on which to bind the service. A
more exact definition is that sockaddr "may be used as a
template for reffering to the identifying tag and length of
each address"[2]. In the function in
pcbbind, sin is a
pointer to a sockaddr.in structure, which contains the port,
address, length and domain family of the socket which is to be
bound. Basically, this disallows any processes from jail to be
able to specify the domain family./usr/src/sys/kern/netinet/in_pcb.c:
int in.pcbbind(int, nam, p)
...
struct sockaddr *nam;
struct proc *p;
{
...
struct sockaddr.in *sin;
...
if (nam) {
sin = (struct sockaddr.in *)nam;
...
if (sin->sin_addr.s_addr != INADDR_ANY)
if (prison.ip(p, 0, ->sin.addr.s_addr))
return (EINVAL);
....
}
...
}You might be wondering what function
prison_ip() does. prison.ip is given three
arguments, the current process (represented by
p), any flags, and an ip address. It
returns 1 if the ip address belongs to a jail or 0 if it does
not. As you can see from the code, if it is indeed an ip
address belonging to a jail, the protcol is not allowed to
bind to a certain port./usr/src/sys/kern/kern_jail.c:
int prison_ip(struct proc *p, int flag, u_int32_t *ip) {
u_int32_t tmp;
if (!p->p_prison)
return (0);
if (flag)
tmp = *ip;
else tmp = ntohl (*ip);
if (tmp == INADDR_ANY) {
if (flag)
*ip = p->p_prison->pr_ip;
else *ip = htonl(p->p_prison->pr_ip);
return (0);
}
if (p->p_prison->pr_ip != tmp)
return (1);
return (0);
}Jailed users are not allowed to bind services to an ip
which does not belong to the jail. The restriction is also
written within the function in_pcbbind:/usr/src/sys/net inet/in_pcb.c
if (nam) {
...
lport = sin->sin.port;
... if (lport) {
...
if (p && p->p_prison)
prison = 1;
if (prison &&
prison_ip(p, 0, ->sin_addr.s_addr))
return (EADDRNOTAVAIL);FilesystemEven root users within the jail are not allowed to set any
file flags, such as immutable, append, and no unlink flags, if
the securelevel is greater than 0./usr/src/sys/ufs/ufs/ufs_vnops.c:
int ufs.setattr(ap)
...
{
if ((cred->cr.uid == 0) && (p->prison == NULL)) {
if ((ip->i_flags
& (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) &&
securelevel > 0)
return (EPERM);
}
diff --git a/en_US.ISO8859-1/books/developers-handbook/mac/chapter.sgml b/en_US.ISO8859-1/books/developers-handbook/mac/chapter.sgml
index ccd16eaf70..1946e991c0 100644
--- a/en_US.ISO8859-1/books/developers-handbook/mac/chapter.sgml
+++ b/en_US.ISO8859-1/books/developers-handbook/mac/chapter.sgml
@@ -1,7819 +1,7821 @@
ChrisCostelloTrustedBSD Projectchris@FreeBSD.orgRobertWatsonTrustedBSD Projectrwatson@FreeBSD.orgThe TrustedBSD MAC FrameworkMAC Documentation CopyrightThis documentation was developed for the FreeBSD Project by
Chris Costello at Safeport Network Services and Network
Associates Laboratories, the Security Research Division of
Network Associates, Inc. under DARPA/SPAWAR contract
N66001-01-C-8035 (CBOSS), as part of the DARPA
CHATS research program.Redistribution and use in source (SGML DocBook) and
'compiled' forms (SGML, HTML, PDF, PostScript, RTF and so forth)
with or without modification, are permitted provided that the
following conditions are met:Redistributions of source code (SGML DocBook) must
retain the above copyright notice, this list of conditions
and the following disclaimer as the first lines of this file
unmodified.Redistributions in compiled form (transformed to other
DTDs, converted to PDF, PostScript, RTF and other formats)
must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation
and/or other materials provided with the
distribution.THIS DOCUMENTATION IS PROVIDED BY THE NETWORKS ASSOCIATES
TECHNOLOGY, INC "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL NETWORKS ASSOCIATES TECHNOLOGY,
INC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.SynopsisFreeBSD includes experimental support for several
mandatory access control policies, as well as a framework
for kernel security extensibility, the TrustedBSD MAC
Framework. The MAC Framework provides a pluggable access
control framework, permitting new security policies to
be easily linked into the kernel, loaded at boot, or loaded
dynamically at run-time. The framework provides a variety
of features to make it easier to implement new policies,
including the ability to easily tag security labels (such as
confidentiality information) onto system objects.This chapter introduces the MAC policy framework and
provides documentation for a sample MAC policy module.IntroductionThe TrustedBSD MAC framework provides a mechanism to allow
the compile-time or run-time extension of the kernel access
control model. New system policies may be implemented as
kernel modules and linked to the kernel; if multiple policy
modules are present, their results will be composed. The
MAC Framework provides a variety of access control infrastructure
services to assist policy writers, including support for
transient and persistent policy-agnostic object security
labels. This support is currently considered experimental.Policy BackgroundMandatory Access Control (MAC), refers to a set of
access control policies that are mandatorily enforced on
users by the operating system. MAC policies may be contrasted
with Discretionary Access Control (DAC) protections, by which
non-administrative users may (at their discretion) protect
objects. In traditional UNIX systems, DAC protections include
file permissions and access control lists; MAC protections include
process controls preventing inter-user debugging and firewalls.
A variety of MAC policies have been formulated by operating system
designers and security researches, including the Multi-Level
Security (MLS) confidentiality policy, the Biba integrity policy,
Role-Based Access Control (RBAC), and Type Enforcement (TE). Each
model bases decisions on a variety of factors, including user
identity, role, and security clearance, as well as security labels
on objects representing concepts such as data sensitivity and
integrity.The TrustedBSD MAC Framework is capable of supporting policy
modules that implement all of these policies, as well as a broad
class of system hardening policies. In addition, despite the
name, the MAC Framework can also be used to implement purely
discretionary policies, as policy modules are given substantial
flexibility in how they authorize protections.MAC Framework Kernel ArchitectureThe TrustedBSD MAC Framework permits kernel modules to
extend the operating system security policy, as well as
providing infrastructure functionality required by many
access control modules. If multiple policies are
simultaneously loaded, the MAC Framework will usefully (for
some definition of useful) compose the results of the
policies.Kernel ElementsThe MAC Framework contains a number of kernel elements:Framework management interfacesConcurrency and synchronization
primitives.Policy registrationExtensible security label for kernel
objectsPolicy entry point composition
operatorsLabel management primitivesEntry point API invoked by kernel
servicesEntry point API to policy modulesEntry points implementations (policy life cycle,
object life cycle/label management, access control
checks).Policy-agnostic label-management system
callsmac_syscall() multiplex
system callVarious security policies implemented as MAC
policy modulesManagement InterfacesThe TrustedBSD MAC Framework may be directly managed using
sysctls, loader tunables, and system calls.In most cases, sysctls and loader tunables modify the same
parameters, and control behavior such as enforcement of
protections relating to various kernel subsystems. In addition,
if MAC debugging support is compiled into the kernel, a variety
of counters will be maintained tracking label allocation. In
most cases, it is advised that per-subsystem enforcement
controls not be used to control policy behavior in production
environments, as they broadly impact the operation of all
active policies. Instead, per-policy controls should be
preferred to ensure proper policy operation.Loading and unloading of policy modules is performed
using the system module management system calls and other
system interfaces, including loader variables.Concurrency and SynchronizationAs the set of active policies may change at run-time,
and the invocation of entry points is non-atomic,
synchronization is required to prevent unloading or
loading of new policies while an entry point invocation
is progress, freezing the list of policies for the
duration. This is accomplished by means of a Framework
busy count. Whenever an entry point is entered, the
busy count is incremented; whenever it is exited, the
busy count is decremented. While the busy count is
elevated, policy list changes are not permitted, and
threads attempting to modify the policy list will sleep
until the list is not busy. The busy count is protected
by a mutex, and a condition variable is used to wake up
sleepers waiting on policy list modifications.Various optimizations are used to reduce the overhead
of the busy count, including avoiding the full cost of
incrementing and decrementing if the list is empty or
contains only static entries (policies that are loaded
before the system starts, and cannot be unloaded).Policy RegistrationThe MAC Framework maintains two lists of active
policies: a static list, and a dynamic list. The lists
differ only with regards to their locking semantics: an
elevated reference count is not required to make use of
the static list. When kernel modules containing MAC
Framework policies are loaded, the policy module will
use SYSINIT to invoke a registration
function; when a policy module is unloaded,
SYSINIT will likewise invoke a
de-registration function. Registration may fail if a
policy module is loaded more than once, if insufficient
resources are available for the registration (for
example, the policy might require labeling and
insufficient labeling state might be available), or
other policy prerequisites might not be met (some
policies may only be loaded prior to boot). Likewise,
de-registration may fail if a policy refuses an
unload.Entry PointsKernel services interact with the MAC Framework in two ways:
they invoke a series of APIs to notify the framework of relevant
events, and they a policy-agnostic label structure in
security-relevant objects. This label structure is maintained by
the MAC Framework via label management entry points, and permits
the Framework to offer a labeling service to policy modules
through relatively non-invasive changes to the kernel subsystem
maintaining the object. For example, label structures have been
added to processes, process credentials, sockets, pipes, vnodes,
Mbufs, network interfaces, IP reassembly queues, and a variety
of other security-relevant structures. Kernel services also
invoke the MAC Framework when they perform important security
decisions, permitting policy modules to augment those decisions
based on their own criteria (possibly including data stored in
security labels).Policy CompositionWhen more than one policy module is loaded into the kernel
at a time, the results of the policy modules will be composed
by the framework using a composition operator. This operator
is currently hard-coded, and requires that all active policies
must approve a request for it to occur. As policies may
return a variety of error conditions (success, access denied,
object doesn't exist, ...), a precedence operator selects the
resulting error from the set of errors returned by policies.
While it is not guaranteed that the resulting composition will
be useful or secure, we've found that it is for many useful
selections of policies.Labeling SupportAs many interesting access control extensions rely on
security labels on objects, the MAC Framework provides a set
of policy-agnostic label management system calls covering
a variety of user-exposed objects. Common label types
include partition identifiers, sensitivity labels, integrity
labels, compartments, domains, roles, and types. Policy
modules participate in the internalization and externalization
of string-based labels provides by user applications, and can
expose multiple label elements to applications if desired.In-memory labels are stored in struct
label, which consists of a fixed-length array
of unions, each holding a void * pointer
and a long. Policies registering for
label storage will be assigned a "slot" identifier, which
may be used to dereference the label storage. The semantics
of the storage are left entirely up to the policy module:
modules are provided with a variety of entry points
associated with the kernel object life cycle, including
initialization, association/creation, and destruction. Using
these interfaces, it is possible to implement reference
counting and other storage mechanisms. Direct access to
the kernel object is generally not required by policy
modules to retrieve a label, as the MAC Framework generally
passes both a pointer to the object and a direct pointer
to the object's label into entry points.Initialization entry points frequently include a blocking
disposition flag indicating whether or not an initialization
is permitted to block; if blocking is not permitted, a failure
may be returned to cancel allocation of the label. This may
occur, for example, in the network stack during interrupt
handling, where blocking is not permitted. Due to the
performance cost of maintaining labels on in-flight network
packets (Mbufs), policies must specifically declare a
requirement that Mbuf labels be allocated. Dynamically
loaded policies making use of labels must be able to handle
the case where their init function has not been called on
an object, as objects may already exist when the policy is
loaded.In the case of file system labels, special support is
provided for the persistent storage of security labels in
extended attributes. Where available, EA transactions
are used to permit consistent compound updates of
security labels on vnodes.Currently, if a labeled policy permits dynamic
unloading, its state slot cannot be reclaimed.System CallsThe MAC Framework implements a number of system calls:
most of these calls support the policy-agnostic label
retrieval and manipulation APIs exposed to user
applications.The label management calls accept a label description
structure, struct mac, which
contains a series of MAC label elements. Each element
contains a character string name, and character string
value. Each policy will be given the chance to claim a
particular element name, permitting policies to expose
multiple independent elements if desired. Policy modules
perform the internalization and externalization between
kernel labels and user-provided labels via entry points,
permitting a variety of semantics. Label management system
calls are generally wrapped by user library functions to
perform memory allocation and error handling.In addition, mac_syscall()
permits policy modules to create new system calls without
allocating system calls. mac_execve()
permits an atomic process credential label change when
executing a new image.MAC Policy ArchitectureSecurity policies are either linked directly into the kernel,
or compiled into loadable kernel modules that may be loaded at
boot, or dynamically using the module loading system calls at
runtime. Policy modules interact with the system through a
set of declared entry points, providing access to a stream of
system events and permitting the policy to influence access
control decisions. Each policy contains a number of elements:Optional configuration parameters for
policy.Centralized implementation of the policy
logic and parameters.Optional implementation of policy life cycle
events, such as initialization and destruction.Optional support for initializing, maintaining, and
destroying labels on selected kernel objects.Optional support for user process inspection and
modification of labels on selected objects.Implementation of selected access control
entry points that are of interest to the policy.Declaration of policy identity, module entry
points, and policy properties.Policy DeclarationModules may be declared using the
MAC_POLICY_SET() macro, which names the
policy, provides a reference to the MAC entry point vector,
provides load-time flags determining how the policy framework
should handle the policy, and optionally requests the
allocation of label state by the framework.static struct mac_policy_ops mac_policy_ops =
{
.mpo_destroy = mac_policy_destroy,
.mpo_init = mac_policy_init,
.mpo_init_bpfdesc_label = mac_policy_init_bpfdesc_label,
.mpo_init_cred_label = mac_policy_init_label,
/* ... */
.mpo_check_vnode_setutimes = mac_policy_check_vnode_setutimes,
.mpo_check_vnode_stat = mac_policy_check_vnode_stat,
.mpo_check_vnode_write = mac_policy_check_vnode_write,
};The MAC policy entry point vector,
mac_policy_ops in this example, associates
functions defined in the module with specific entry points. A
complete listing of available entry points and their
prototypes may be found in the MAC entry point reference
section. Of specific interest during module registration are
the .mpo_destroy and .mpo_init
entry points. .mpo_init will be invoked once a
policy is successfully registered with the module framework
but prior to any other entry points becoming active. This
permits the policy to perform any policy-specific allocation
and initialization, such as initialization of any data or
locks. .mpo_destroy will be invoked when a
policy module is unloaded to permit releasing of any allocated
memory and destruction of locks. Currently, these two entry
points are invoked with the MAC policy list mutex held to
prevent any other entry points from being invoked: this will
be changed, but in the mean time, policies should be careful
about what kernel primitives they invoke so as to avoid lock
ordering or sleeping problems.The policy declaration's module name field exists so that
the module may be uniquely identified for the purposes of
module dependencies. An appropriate string should be selected.
The full string name of the policy is displayed to the user
via the kernel log during load and unload events, and also
exported when providing status information to userland
processes.Policy FlagsThe policy declaration flags field permits the module to
provide the framework with information about its capabilities at
the time the module is loaded. Currently, three flags are
defined:MPC_LOADTIME_FLAG_UNLOADOKThis flag indicates that the policy module may be
unloaded. If this flag is not provided, then the policy
framework will reject requests to unload the module.
This flag might be used by modules that allocate label
state and are unable to free that state at
runtime.MPC_LOADTIME_FLAG_NOTLATEThis flag indicates that the policy module
must be loaded and initialized early in the boot
process. If the flag is specified, attempts to register
the module following boot will be rejected. The flag
may be used by policies that require pervasive labeling
of all system objects, and cannot handle objects that
have not been properly initialized by the policy.MPC_LOADTIME_FLAG_LABELMBUFSThis flag indicates that the policy module requires
labeling of Mbufs, and that memory should always be
allocated for the storage of Mbuf labels. By default,
the MAC Framework will not allocate label storage for
Mbufs unless at least one loaded policy has this flag
set. This measurably improves network performance when
policies do not require Mbuf labeling. A kernel option,
MAC_ALWAYS_LABEL_MBUF, exists to
force the MAC Framework to allocate Mbuf label storage
regardless of the setting of this flag, and may be
useful in some environments.Policies using the
MPC_LOADTIME_FLAG_LABELMBUFS without the
MPC_LOADTIME_FLAG_NOTLATE flag set
must be able to correctly handle NULL
Mbuf label pointers passed into entry points. This is necessary
as in-flight Mbufs without label storage may persist after a
policy enabling Mbuf labeling has been loaded. If a policy
is loaded before the network subsystem is active (i.e., the
policy is not being loaded late), then all Mbufs are guaranteed
to have label storage.Policy Entry PointsFour classes of entry points are offered to policies
registered with the framework: entry points associated with
the registration and management of policies, entry points
denoting initialization, creation, destruction, and other life
cycle events for kernel objects, events associated with access
control decisions that the policy module may influence, and
calls associated with the management of labels on objects. In
addition, a mac_syscall() entry point is
provided so that policies may extend the kernel interface
without registering new system calls.Policy module writers should be aware of the kernel
locking strategy, as well as what object locks are available
during which entry points. Writers should attempt to avoid
deadlock scenarios by avoiding grabbing non-leaf locks inside
of entry points, and also follow the locking protocol for
object access and modification. In particular, writers should
be aware that while necessary locks to access objects and
their labels are generally held, sufficient locks to modify an
object or its label may not be present for all entry points.
Locking information for arguments is documented in the MAC
framework entry point document.Policy entry points will pass a reference to the object
label along with the object itself. This permits labeled
policies to be unaware of the internals of the object yet
still make decisions based on the label. The exception to this
is the process credential, which is assumed to be understood
by policies as a first class security object in the kernel.
Policies that do not implement labels on kernel objects will
be passed NULL pointers for label arguments to entry
points.MAC Policy Entry Point ReferenceGeneral-Purpose Module Entry Points&mac.mpo;_initvoid
&mac.mpo;_initstruct mac_policy_conf
*conf
&mac.thead;
confMAC policy definitionPolicy load event. The policy list mutex is held, so
caution should be applied.&mac.mpo;_destroyvoid
&mac.mpo;_destroystruct mac_policy_conf
*conf
&mac.thead;
confMAC policy definitionPolicy load event. The policy list mutex is held, so
caution should be applied.&mac.mpo;_syscallint
&mac.mpo;_syscallstruct thread
*tdint callvoid *arg
&mac.thead;
tdCalling threadcallSyscall numberargPointer to syscall argumentsThis entry point provides a policy-multiplexed system
call so that policies may provide additional services to
user processes without registering specific system calls.
The policy name provided during registration is used to
demux calls from userland, and the arguments will be
forwarded to this entry point. When implementing new
services, security modules should be sure to invoke
appropriate access control checks from the MAC framework as
needed. For example, if a policy implements an augmented
signal functionality, it should call the necessary signal
access control checks to invoke the MAC framework and other
registered policies.Modules must currently perform the
copyin() of the syscall data on their
own.&mac.mpo;_thread_userretvoid
&mac.mpo;_thread_userretstruct thread
*td
&mac.thead;
tdReturning threadThis entry point permits policy modules to perform
MAC-related events when a thread returns to user space.
This is required for policies that have floating process
labels, as it's not always possible to acquire the process
lock at arbitrary points in the stack during system call
processing; process labels might represent traditional
authentication data, process history information, or other
data.Label Operations&mac.mpo;_init_bpfdesc_labelvoid
&mac.mpo;_init_bpfdesc_labelstruct label
*label
&mac.thead;
labelNew label to applyInitialize the label on a newly instantiated bpfdesc (BPF
descriptor)&mac.mpo;_init_cred_labelvoid
&mac.mpo;_init_cred_labelstruct label
*label
&mac.thead;
labelNew label to initializeInitialize the label for a newly instantiated
user credential.&mac.mpo;_init_devfsdirent_labelvoid
&mac.mpo;_init_devfsdirent_labelstruct label
*label
&mac.thead;
labelNew label to applyInitialize the label on a newly instantiated devfs
entry.&mac.mpo;_init_ifnet_labelvoid
&mac.mpo;_init_ifnet_labelstruct label
*label
&mac.thead;
labelNew label to applyInitialize the label on a newly instantiated network
interface.&mac.mpo;_init_ipq_labelvoid
&mac.mpo;_init_ipq_labelstruct label
*labelint flag
&mac.thead;
labelNew label to applyflagBlocking/non-blocking &man.malloc.9;; see
belowInitialize the label on a newly instantiated IP fragment
reassembly queue. The flag field may
be one of M_WAITOK and M_NOWAIT,
and should be employed to avoid performing a blocking
&man.malloc.9; during this initialization call. IP fragment
reassembly queue allocation frequently occurs in performance
sensitive environments, and the implementation should be careful
to avoid blocking or long-lived operations. This entry point
is permitted to fail resulting in the failure to allocate
the IP fragment reassembly queue.&mac.mpo;_init_mbuf_labelvoid
&mac.mpo;_init_mbuf_labelint flagstruct label
*label
&mac.thead;
flagBlocking/non-blocking &man.malloc.9;; see
belowlabelPolicy label to initialize
+ Initialize the label on a newly instantiated mbuf packet
header (mbuf). The
flag field may be one of
M_WAITOK and M_NOWAIT, and
should be employed to avoid performing a blocking
&man.malloc.9; during this initialization call. Mbuf
allocation frequently occurs in performance sensitive
environments, and the implementation should be careful to
avoid blocking or long-lived operations. This entry point
is permitted to fail resulting in the failure to allocate
the mbuf header.&mac.mpo;_init_mount_labelvoid
&mac.mpo;_init_mount_labelstruct label
*mntlabelstruct label
*fslabel
&mac.thead;
mntlabelPolicy label to be initialized for the mount
itselffslabelPolicy label to be initialized for the file
systemInitialize the labels on a newly instantiated mount
point.&mac.mpo;_init_mount_fs_labelvoid
&mac.mpo;_init_mount_fs_labelstruct label
*label
&mac.thead;
labelLabel to be initializedInitialize the label on a newly mounted file
system.&mac.mpo;_init_pipe_labelvoid
&mac.mpo;_init_pipe_labelstruct
label*label
&mac.thead;
labelLabel to be filled in
+ Initialize a label for a newly instantiated pipe.&mac.mpo;_init_socket_labelvoid
&mac.mpo;_init_socket_labelstruct label
*labelint flag
&mac.thead;
labelNew label to initializeflag&man.malloc.9; flagsInitialize a label for a newly instantiated
socket.&mac.mpo;_init_socket_peer_labelvoid
&mac.mpo;_init_socket_peer_labelstruct label
*labelint flag
&mac.thead;
labelNew label to initializeflag&man.malloc.9; flagsInitialize the peer label for a newly instantiated
socket.&mac.mpo;_init_proc_labelvoid
&mac.mpo;_init_proc_labelstruct label
*label
&mac.thead;
labelNew label to initializeInitialize the label for a newly instantiated
process.&mac.mpo;_init_vnode_labelvoid
&mac.mpo;_init_vnode_labelstruct label
*label
&mac.thead;
labelNew label to initializeInitialize the label on a newly instantiated vnode.&mac.mpo;_destroy_bpfdesc_labelvoid
&mac.mpo;_destroy_bpfdesc_labelstruct label
*label
&mac.thead;
labelbpfdesc labelDestroy the label on a BPF descriptor. In this entry
point a policy should free any internal storage associated
with label so that it may be
destroyed.&mac.mpo;_destroy_cred_labelvoid
&mac.mpo;_destroy_cred_labelstruct label
*label
&mac.thead;
labelLabel being destroyedDestroy the label on a credential. In this entry point,
a policy module should free any internal storage associated
with label so that it may be
destroyed.&mac.mpo;_destroy_devfsdirent_labelvoid
&mac.mpo;_destroy_devfsdirent_labelstruct label
*label
&mac.thead;
labelLabel being destroyedDestroy the label on a devfs entry. In this entry
point, a policy module should free any internal storage
associated with label so that it may
be destroyed.&mac.mpo;_destroy_ifnet_labelvoid
&mac.mpo;_destroy_ifnet_labelstruct label
*label
&mac.thead;
labelLabel being destroyedDestroy the label on a removed interface. In this entry
point, a policy module should free any internal storage
associated with label so that it may
be destroyed.&mac.mpo;_destroy_ipq_labelvoid
&mac.mpo;_destroy_ipq_labelstruct label
*label
&mac.thead;
labelLabel being destroyedDestroy the label on an IP fragment queue. In this
entry point, a policy module should free any internal
storage associated with label so that
it may be destroyed.&mac.mpo;_destroy_mbuf_labelvoid
&mac.mpo;_destroy_mbuf_labelstruct label
*label
&mac.thead;
labelLabel being destroyedDestroy the label on an mbuf header. In this entry
point, a policy module should free any internal storage
associated with label so that it may
be destroyed.&mac.mpo;_destroy_mount_labelvoid
&mac.mpo;_destroy_mount_labelstruct label
*label
&mac.thead;
labelMount point label being destroyedDestroy the labels on a mount point. In this entry
point, a policy module should free the internal storage
associated with mntlabel so that they
may be destroyed.&mac.mpo;_destroy_mount_labelvoid
&mac.mpo;_destroy_mount_labelstruct label
*mntlabelstruct label
*fslabel
&mac.thead;
mntlabelMount point label being destroyedfslabel
- File system label being destroyed>
+ File system label being destroyed>Destroy the labels on a mount point. In this entry
point, a policy module should free the internal storage
associated with mntlabel and
fslabel so that they may be
destroyed.&mac.mpo;_destroy_socket_labelvoid
&mac.mpo;_destroy_socket_labelstruct label
*label
&mac.thead;
labelSocket label being destroyedDestroy the label on a socket. In this entry point, a
policy module should free any internal storage associated
with label so that it may be
destroyed.&mac.mpo;_destroy_socket_peer_labelvoid
&mac.mpo;_destroy_socket_peer_labelstruct label
*peerlabel
&mac.thead;
peerlabelSocket peer label being destroyedDestroy the peer label on a socket. In this entry
point, a policy module should free any internal storage
associated with label so that it may
be destroyed.&mac.mpo;_destroy_pipe_labelvoid
&mac.mpo;_destroy_pipe_labelstruct label
*label
&mac.thead;
labelPipe labelDestroy the label on a pipe. In this entry point, a
policy module should free any internal storage associated
with label so that it may be
destroyed.&mac.mpo;_destroy_proc_labelvoid
&mac.mpo;_destroy_proc_labelstruct label
*label
&mac.thead;
labelProcess labelDestroy the label on a process. In this entry point, a
policy module should free any internal storage associated
with label so that it may be
destroyed.&mac.mpo;_destroy_vnode_labelvoid
&mac.mpo;_destroy_vnode_labelstruct label
*label
&mac.thead;
labelProcess labelDestroy the label on a vnode. In this entry point, a
policy module should free any internal storage associated
with label so that it may be
destroyed.&mac.mpo;_copy_mbuf_labelvoid
&mac.mpo;_copy_mbuf_labelstruct label
*srcstruct label
*dest
&mac.thead;
srcSource labeldestDestination labelCopy the label information in
src into
dest.&mac.mpo;_copy_pipe_labelvoid
&mac.mpo;_copy_pipe_labelstruct label
*srcstruct label
*dest
&mac.thead;
srcSource labeldestDestination labelCopy the label information in
src into
dest.&mac.mpo;_copy_vnode_labelvoid
&mac.mpo;_copy_vnode_labelstruct label
*srcstruct label
*dest
&mac.thead;
srcSource labeldestDestination labelCopy the label information in
src into
dest.&mac.mpo;_externalize_cred_labelint
&mac.mpo;_externalize_cred_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_ifnet_labelint
&mac.mpo;_externalize_ifnet_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_pipe_labelint
&mac.mpo;_externalize_pipe_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_socket_labelint
&mac.mpo;_externalize_socket_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_socket_peer_labelint
&mac.mpo;_externalize_socket_peer_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_externalize_vnode_labelint
&mac.mpo;_externalize_vnode_label
&mac.externalize.paramdefs;
&mac.thead;
&mac.externalize.tbody;
&mac.externalize.para;
&mac.mpo;_internalize_cred_labelint
&mac.mpo;_internalize_cred_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
&mac.mpo;_internalize_ifnet_labelint
&mac.mpo;_internalize_ifnet_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
&mac.mpo;_internalize_pipe_labelint
&mac.mpo;_internalize_pipe_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
&mac.mpo;_internalize_socket_labelint
&mac.mpo;_internalize_socket_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
&mac.mpo;_internalize_vnode_labelint
&mac.mpo;_internalize_vnode_label
&mac.internalize.paramdefs;
&mac.thead;
&mac.internalize.tbody;
&mac.internalize.para;
Label EventsThis class of entry points is used by the MAC framework to
permit policies to maintain label information on kernel
objects. For each labeled kernel object of interest to a MAC
policy, entry points may be registered for relevant life cycle
events. All objects implement initialization, creation, and
destruction hooks. Some objects will also implement
relabeling, allowing user processes to change the labels on
objects. Some objects will also implement object-specific
events, such as label events associated with IP reassembly. A
typical labeled object will have the following life cycle of
entry points:Label initialization o
(object-specific wait) \
Label creation o
\
Relabel events, o--<--.
Various object-specific, | |
Access control events ~-->--o
\
Label destruction oLabel initialization permits policies to allocate memory
and set initial values for labels without context for the use
of the object. The label slot allocated to a policy will be
zeroed by default, so some policies may not need to perform
initialization.Label creation occurs when the kernel structure is
associated with an actual kernel object. For example, Mbufs
may be allocated and remain unused in a pool until they are
required. mbuf allocation causes label initialization on the
mbuf to take place, but mbuf creation occurs when the mbuf is
associated with a datagram. Typically, context will be
provided for a creation event, including the circumstances of
the creation, and labels of other relevant objects in the
creation process. For example, when an mbuf is created from a
socket, the socket and its label will be presented to
registered policies in addition to the new mbuf and its label.
Memory allocation in creation events is discouraged, as it may
occur in performance sensitive ports of the kernel; in
addition, creation calls are not permitted to fail so a
failure to allocate memory cannot be reported.Object specific events do not generally fall into the
other broad classes of label events, but will generally
provide an opportunity to modify or update the label on an
object based on additional context. For example, the label on
an IP fragment reassembly queue may be updated during the
MAC_UPDATE_IPQ entry point as a result of the
acceptance of an additional mbuf to that queue.Access control events are discussed in detail in the
following section.Label destruction permits policies to release storage or
state associated with a label during its association with an
object so that the kernel data structures supporting the
object may be reused or released.In addition to labels associated with specific kernel
objects, an additional class of labels exists: temporary
labels. These labels are used to store update information
submitted by user processes. These labels are initialized and
destroyed as with other label types, but the creation event is
MAC_INTERNALIZE, which accepts a user label
to be converted to an in-kernel representation.File System Object Labeling Event Operations&mac.mpo;_associate_vnode_devfsvoid
&mac.mpo;_associate_vnode_devfsstruct mount
*mpstruct label
*fslabelstruct devfs_dirent
*destruct label
*delabelstruct vnode
*vpstruct label
*vlabel
&mac.thead;
mpDevfs mount pointfslabelDevfs file system label
(mp->mnt_fslabel)deDevfs directory entrydelabelPolicy label associated with
devpvnode associated with
devlabelPolicy label associated with
vpFill in the label (vlabel) for
a newly created devfs vnode based on the devfs directory
entry passed in de and its
label.&mac.mpo;_associate_vnode_extattrint
&mac.mpo;_associate_vnode_extattrstruct mount
*mpstruct label
*fslabelstruct vnode
*vpstruct label
*vlabel
&mac.thead;
mpFile system mount pointfslabelFile system labelvpVnode to labelvlabelPolicy label associated with
vpAttempt to retrieve the label for
vp from the file system extended
attributes. Upon success, the value 0
is returned. Should extended attribute retrieval not be
supported, an accepted fallback is to copy
fslabel into
vlabel. In the event of an error,
an appropriate value for errno should
be returned.&mac.mpo;_associate_vnode_singlelabelvoid
&mac.mpo;_associate_vnode_singlelabelstruct mount
*mpstruct label
*fslabelstruct vnode
*vpstruct label
*vlabel
&mac.thead;
mpFile system mount pointfslabelFile system labelvpVnode to labelvlabelPolicy label associated with
vpOn non-multilabel file systems, this entry point is
called to set the policy label for
vp based on the file system label,
fslabel.&mac.mpo;_create_devfs_devicevoid
&mac.mpo;_create_devfs_devicedev_t devstruct devfs_dirent
*devfs_direntstruct label
*label
&mac.thead;
devDevice corresponding with
devfs_direntdevfs_direntDevfs directory entry to be labeled.labelLabel for devfs_dirent
to be filled in.Fill out the label on a devfs_dirent being created for
the passed device. This call will be made when the device
file system is mounted, regenerated, or a new device is made
available.&mac.mpo;_create_devfs_directoryvoid
&mac.mpo;_create_devfs_directorychar *dirnameint dirnamelenstruct devfs_dirent
*devfs_direntstruct label
*label
&mac.thead;
dirnameName of directory being creatednamelenLength of string
dirnamedevfs_direntDevfs directory entry for directory being
created.Fill out the label on a devfs_dirent being created for
the passed directory. This call will be made when the device
file system is mounted, regenerated, or a new device
requiring a specific directory hierarchy is made
available.&mac.mpo;_create_devfs_symlinkvoid
&mac.mpo;_create_devfs_symlinkstruct ucred
*credstruct mount
*mpstruct devfs_dirent
*ddstruct label
*ddlabelstruct devfs_dirent
*destruct label
*delabel
&mac.thead;
credSubject credentialmpDevfs mount pointddLink destinationddlabelLabel associated with
dddeSymlink entrydelabelLabel associated with
deFill in the label (delabel) for
a newly created &man.devfs.5; symbolic link entry.&mac.mpo;_create_vnode_extattrint
&mac.mpo;_create_vnode_extattrstruct ucred
*credstruct mount
*mpstruct label
*fslabelstruct vnode
*dvpstruct label
*dlabelstruct vnode
*vpstruct label
*vlabelstruct componentname
*cnp
&mac.thead;
credSubject credentialmountFile system mount pointlabelFile system labeldvpParent directory vnodedlabelLabel associated with
dvpvpNewly created vnodevlabelPolicy label associated with
vpcnpComponent name for
vpWrite out the label for vp to
the appropriate extended attribute. If the write
succeeds, fill in vlabel with the
label, and return 0. Otherwise,
return an appropriate error.&mac.mpo;_create_mountvoid
&mac.mpo;_create_mountstruct ucred
*credstruct mount
*mpstruct label
*mntstruct label
*fslabel
&mac.thead;
credSubject credentialmpObject; file system being mountedmntlabelPolicy label to be filled in for
mpfslabelPolicy label for the file system
mp mounts.Fill out the labels on the mount point being created by
the passed subject credential. This call will be made when
a new file system is mounted.&mac.mpo;_create_root_mountvoid
&mac.mpo;_create_root_mountstruct ucred
*credstruct mount
*mpstruct label
*mntlabelstruct label
*fslabel
&mac.thead;
See .Fill out the labels on the mount point being created by
the passed subject credential. This call will be made when
the root file system is mounted, after
&mac.mpo;_create_mount;.&mac.mpo;_relabel_vnodevoid
&mac.mpo;_relabel_vnodestruct ucred
*credstruct vnode
*vpstruct label
*vnodelabelstruct label
*newlabel
&mac.thead;
credSubject credentialvpvnode to relabelvnodelabelExisting policy label for
vpnewlabelNew, possibly partial label to replace
vnodelabelUpdate the label on the passed vnode given the passed
update vnode label and the passed subject credential.&mac.mpo;_setlabel_vnode_extattrint
&mac.mpo;_setlabel_vnode_extattrstruct ucred
*credstruct vnode
*vpstruct label
*vlabelstruct label
*intlabel
&mac.thead;
credSubject credentialvpVnode for which the label is being
writtenvlabelPolicy label associated with
vpintlabelLabel to write outWrite out the policy from
intlabel to an extended
attribute. This is called from
vop_stdcreatevnode_ea.&mac.mpo;_update_devfsdirentvoid
&mac.mpo;_update_devfsdirentstruct devfs_dirent
*devfs_direntstruct label
*direntlabelstruct vnode
*vpstruct label
*vnodelabel
&mac.thead;
devfs_direntObject; devfs directory entrydirentlabelPolicy label for
devfs_dirent to be
updated.vpParent vnodeLockedvnodelabelPolicy label for
vpUpdate the devfs_dirent label
from the passed devfs vnode label. This call will be made
when a devfs vnode has been successfully relabeled to commit
the label change such that it lasts even if the vnode is
recycled. It will also be made when when a symlink is
created in devfs, following a call to
mac_vnode_create_from_vnode to
initialize the vnode label.IPC Object Labeling Event Operations&mac.mpo;_create_mbuf_from_socketvoid
&mac.mpo;_create_mbuf_from_socketstruct socket
*sostruct label
*socketlabelstruct mbuf *mstruct label
*mbuflabel
&mac.thead;
socketSocketSocket locking WIPsocketlabelPolicy label for
socketmObject; mbufmbuflabelPolicy label to fill in for
mSet the label on a newly created mbuf header from the
passed socket label. This call is made when a new datagram
or message is generated by the socket and stored in the
passed mbuf.&mac.mpo;_create_pipevoid
&mac.mpo;_create_pipestruct ucred
*credstruct pipe
*pipestruct label
*pipelabel
&mac.thead;
credSubject credentialpipePipepipelabelPolicy label associated with
pipeSet the label on a newly created pipe from the passed
subject credential. This call is made when a new pipe is
created.&mac.mpo;_create_socketvoid
&mac.mpo;_create_socketstruct ucred
*credstruct socket
*sostruct label
*socketlabel
&mac.thead;
credSubject credentialImmutablesoObject; socket to labelsocketlabelLabel to fill in for
soSet the label on a newly created socket from the passed
subject credential. This call is made when a socket is
created.&mac.mpo;_create_socket_from_socketvoid
&mac.mpo;_create_socket_from_socketstruct socket
*oldsocketstruct label
*oldsocketlabelstruct socket
*newsocketstruct label
*newsocketlabel
&mac.thead;
oldsocketListening socketoldsocketlabelPolicy label associated with
oldsocketnewsocketNew socketnewsocketlabelPolicy label associated with
newsocketlabelLabel a socket, newsocket,
newly &man.accept.2;ed, based on the &man.listen.2;
socket, oldsocket.&mac.mpo;_relabel_pipevoid
&mac.mpo;_relabel_pipestruct ucred
*credstruct pipe
*pipestruct label
*oldlabelstruct label
*newlabel
&mac.thead;
credSubject credentialpipePipeoldlabelCurrent policy label associated with
pipenewlabelPolicy label update to apply to
pipeApply a new label, newlabel, to
pipe.&mac.mpo;_relabel_socketvoid
&mac.mpo;_relabel_socketstruct ucred
*credstruct socket
*sostruct label
*oldlabelstruct label
*newlabel
&mac.thead;
credSubject credentialImmutablesoObject; socketoldlabelCurrent label for
sonewlabelLabel update for
soUpdate the label on a socket from the passed socket
label update.&mac.mpo;_set_socket_peer_from_mbufvoid
&mac.mpo;_set_socket_peer_from_mbufstruct mbuf
*mbufstruct label
*mbuflabelstruct label
*oldlabelstruct label
*newlabel
&mac.thead;
mbufFirst datagram received over socketmbuflabelLabel for mbufoldlabelCurrent label for the socketnewlabelPolicy label to be filled out for the
socketSet the peer label on a stream socket from the passed
mbuf label. This call will be made when the first datagram
is received by the stream socket, with the exception of Unix
domain sockets.&mac.mpo;_set_socket_peer_from_socketvoid
&mac.mpo;_set_socket_peer_from_socketstruct socket
*oldsocketstruct label
*oldsocketlabelstruct socket
*newsocketstruct label
*newsocketpeerlabel
&mac.thead;
oldsocketLocal socketoldsocketlabelPolicy label for
oldsocketnewsocketPeer socketnewsocketpeerlabelPolicy label to fill in for
newsocketSet the peer label on a stream UNIX domain socket from
the passed remote socket endpoint. This call will be made
when the socket pair is connected, and will be made for both
endpoints.Network Object Labeling Event Operations&mac.mpo;_create_bpfdescvoid
&mac.mpo;_create_bpfdescstruct ucred
*credstruct bpf_d
*bpf_dstruct label
*bpflabel
&mac.thead;
credSubject credentialImmutablebpf_dObject; bpf descriptorbpfPolicy label to be filled in for
bpf_dSet the label on a newly created BPF descriptor from the
passed subject credential. This call will be made when a
BPF device node is opened by a process with the passed
subject credential.&mac.mpo;_create_ifnetvoid
&mac.mpo;_create_ifnetstruct ifnet
*ifnetstruct label
*ifnetlabel
&mac.thead;
ifnetNetwork interfaceifnetlabelPolicy label to fill in for
ifnetSet the label on a newly created interface. This call
may be made when a new physical interface becomes available
to the system, or when a pseudo-interface is instantiated
during the boot or as a result of a user action.&mac.mpo;_create_ipqvoid
&mac.mpo;_create_ipqstruct mbuf
*fragmentstruct label
*fragmentlabelstruct ipq
*ipqstruct label
*ipqlabel
&mac.thead;
fragmentFirst received IP fragmentfragmentlabelPolicy label for
fragmentipqIP reassembly queue to be labeledipqlabelPolicy label to be filled in for
ipqSet the label on a newly created IP fragment reassembly
queue from the mbuf header of the first received
fragment.&mac.mpo;_create_datagram_from_ipqvoid
&mac.mpo;_create_create_datagram_from_ipqstruct ipq
*ipqstruct label
*ipqlabelstruct mbuf
*datagramstruct label
*datagramlabel
&mac.thead;
ipqIP reassembly queueipqlabelPolicy label for
ipqdatagramDatagram to be labeleddatagramlabelPolicy label to be filled in for
datagramlabelSet the label on a newly reassembled IP datagram from
the IP fragment reassembly queue from which it was
generated.&mac.mpo;_create_fragmentvoid
&mac.mpo;_create_fragmentstruct mbuf
*datagramstruct label
*datagramlabelstruct mbuf
*fragmentstruct label
*fragmentlabel
&mac.thead;
datagramDatagramdatagramlabelPolicy label for
datagramfragmentFragment to be labeledfragmentlabelPolicy label to be filled in for
datagramSet the label on the mbuf header of a newly created IP
fragment from the label on the mbuf header of the datagram
it was generate from.&mac.mpo;_create_mbuf_from_mbufvoid
&mac.mpo;_create_mbuf_from_mbufstruct mbuf
*oldmbufstruct label
*oldmbuflabelstruct mbuf
*newmbufstruct label
*newmbuflabel
&mac.thead;
oldmbufExisting (source) mbufoldmbuflabelPolicy label for
oldmbufnewmbufNew mbuf to be labelednewmbuflabelPolicy label to be filled in for
newmbufSet the label on the mbuf header of a newly created
datagram from the mbuf header of an existing datagram. This
call may be made in a number of situations, including when
an mbuf is re-allocated for alignment purposes.&mac.mpo;_create_mbuf_linklayervoid
&mac.mpo;_create_mbuf_linklayerstruct ifnet
*ifnetstruct label
*ifnetlabelstruct mbuf
*mbufstruct label
*mbuflabel
&mac.thead;
ifnetNetwork interfaceifnetlabelPolicy label for
ifnetmbufmbuf header for new datagrammbuflabelPolicy label to be filled in for
mbufSet the label on the mbuf header of a newly created
datagram generated for the purposes of a link layer response
for the passed interface. This call may be made in a number
of situations, including for ARP or ND6 responses in the
IPv4 and IPv6 stacks.&mac.mpo;_create_mbuf_from_bpfdescvoid
&mac.mpo;_create_mbuf_from_bpfdescstruct bpf_d
*bpf_dstruct label
*bpflabelstruct mbuf
*mbufstruct label
*mbuflabel
&mac.thead;
bpf_dBPF descriptorbpflabelPolicy label for
bpflabelmbufNew mbuf to be labeledmbuflabelPolicy label to fill in for
mbufSet the label on the mbuf header of a newly created
datagram generated using the passed BPF descriptor. This
call is made when a write is performed to the BPF device
associated with the passed BPF descriptor.&mac.mpo;_create_mbuf_from_ifnetvoid
&mac.mpo;_create_mbuf_from_ifnetstruct ifnet
*ifnetstruct label
*ifnetlabelstruct mbuf
*mbufstruct label
*mbuflabel
&mac.thead;
ifnetNetwork interfaceifnetlabelPolicy label for
ifnetlabelmbufmbuf header for new datagrammbuflabelPolicy label to be filled in for
mbufSet the label on the mbuf header of a newly created
datagram generated from the passed network interface.&mac.mpo;_create_mbuf_multicast_encapvoid
&mac.mpo;_create_mbuf_multicast_encapstruct mbuf
*oldmbufstruct label
*oldmbuflabelstruct ifnet
*ifnetstruct label
*ifnetlabelstruct mbuf
*newmbufstruct label
*newmbuflabel
&mac.thead;
oldmbufmbuf header for existing datagramoldmbuflabelPolicy label for
oldmbufifnetNetwork interfaceifnetlabelPolicy label for
ifnetnewmbufmbuf header to be labeled for new
datagramnewmbuflabelPolicy label to be filled in for
newmbufSet the label on the mbuf header of a newly created
datagram generated from the existing passed datagram when it
is processed by the passed multicast encapsulation
interface. This call is made when an mbuf is to be
delivered using the virtual interface.&mac.mpo;_create_mbuf_netlayervoid
&mac.mpo;_create_mbuf_netlayerstruct mbuf
*oldmbufstruct label
*oldmbuflabelstruct mbuf
*newmbufstruct label
*newmbuflabel
&mac.thead;
oldmbufReceived datagramoldmbuflabelPolicy label for
oldmbufnewmbufNewly created datagramnewmbuflabelPolicy label for
newmbufSet the label on the mbuf header of a newly created
datagram generated by the IP stack in response to an
existing received datagram (oldmbuf).
This call may be made in a number of situations, including
when responding to ICMP request datagrams.&mac.mpo;_fragment_matchint
&mac.mpo;_fragment_matchstruct mbuf
*fragmentstruct label
*fragmentlabelstruct ipq
*ipqstruct label
*ipqlabel
&mac.thead;
fragmentIP datagram fragmentfragmentlabelPolicy label for
fragmentipqIP fragment reassembly queueipqlabelPolicy label for
ipqDetermine whether an mbuf header containing an IP
datagram (fragment) fragment matches
the label of the passed IP fragment reassembly queue
(ipq). Return
(1) for a successful match, or
(0) for no match. This call is
made when the IP stack attempts to find an existing fragment
reassembly queue for a newly received fragment; if this
fails, a new fragment reassembly queue may be instantiated
for the fragment. Policies may use this entry point to
prevent the reassembly of otherwise matching IP fragments if
policy does not permit them to be reassembled based on the
label or other information.&mac.mpo;_relabel_ifnetvoid
&mac.mpo;_relabel_ifnetstruct ucred
*credstruct ifnet
*ifnetstruct label
*ifnetlabelstruct label
*newlabel
&mac.thead;
credSubject credentialifnetObject; Network interfaceifnetlabelPolicy label for
ifnetnewlabelLabel update to apply to
ifnetUpdate the label of network interface,
ifnet, based on the passed update
label, newlabel, and the passed
subject credential, cred.&mac.mpo;_update_ipqvoid
&mac.mpo;_update_ipqstruct mbuf
*fragmentstruct label
*fragmentlabelstruct ipq
*ipqstruct label
*ipqlabel
&mac.thead;
mbufIP fragmentmbuflabelPolicy label for
mbufipqIP fragment reassembly queueipqlabelPolicy label to be updated for
ipqUpdate the label on an IP fragment reassembly queue
(ipq) based on the acceptance of the
passed IP fragment mbuf header
(mbuf).Process Labeling Event Operations&mac.mpo;_create_credvoid
&mac.mpo;_create_credstruct ucred
*parent_credstruct ucred
*child_cred
&mac.thead;
parent_credParent subject credentialchild_credChild subject credentialSet the label of a newly created subject credential from
the passed subject credential. This call will be made when
&man.crcopy.9; is invoked on a newly created struct
ucred. This call should not be confused with a
process forking or creation event.&mac.mpo;_execve_transitionvoid
&mac.mpo;_execve_transitionstruct ucred
*oldstruct ucred
*newstruct vnode
*vpstruct label
*vnodelabel
&mac.thead;
oldExisting subject credentialImmutablenewNew subject credential to be labeledvpFile to executeLockedvnodelabelPolicy label for
vpUpdate the label of a newly created subject credential
(new) from the passed existing
subject credential (old) based on a
label transition caused by executing the passed vnode
(vp). This call occurs when a
process executes the passed vnode and one of the policies
returns a success from the
mpo_execve_will_transition entry point.
Policies may choose to implement this call simply by
invoking mpo_create_cred and passing
the two subject credentials so as not to implement a
transitioning event. Policies should not leave this entry
point unimplemented if they implement
mpo_create_cred, even if they do not
implement
mpo_execve_will_transition.&mac.mpo;_execve_will_transitionint
&mac.mpo;_execve_will_transitionstruct ucred
*oldstruct vnode
*vpstruct label
*vnodelabel
&mac.thead;
oldSubject credential prior to
&man.execve.2;ImmutablevpFile to executevnodelabelPolicy label for
vpDetermine whether the policy will want to perform a
transition event as a result of the execution of the passed
vnode by the passed subject credential. Return
1 if a transition is required,
0 if not. Even if a policy
returns 0, it should behave
correctly in the presence of an unexpected invocation of
mpo_execve_transition, as that call may
happen as a result of another policy requesting a
transition.&mac.mpo;_create_proc0void
&mac.mpo;_create_proc0struct ucred
*cred
&mac.thead;
credSubject credential to be filled inCreate the subject credential of process 0, the parent
of all kernel processes.&mac.mpo;_create_proc1void
&mac.mpo;_create_proc1struct ucred
*cred
&mac.thead;
credSubject credential to be filled inCreate the subject credential of process 1, the parent
of all user processes.&mac.mpo;_relabel_credvoid
&mac.mpo;_relabel_credstruct ucred
*credstruct label
*newlabel
&mac.thead;
credSubject credentialnewlabelLabel update to apply to
credUpdate the label on a subject credential from the passed
update label.Access Control ChecksAccess control entry points permit policy modules to
influence access control decisions made by the kernel.
Generally, although not always, arguments to an access control
entry point will include one or more authorizing credentials,
information (possibly including a label) for any other objects
involved in the operation. An access control entry point may
return 0 to permit the operation, or an &man.errno.2; error
value. The results of invoking the entry point across various
registered policy modules will be composed as follows: if all
modules permit the operation to succeed, success will be
returned. If one or modules returns a failure, a failure will
be returned. If more than one module returns a failure, the
errno value to return to the user will be selected using the
following precedence, implemented by the
error_select() function in
kern_mac.c:Most precedenceEDEADLKEINVALESRCHEACCESLeast precedenceEPERMIf none of the error values returned by all modules are
listed in the precedence chart then an arbitrarily selected
value from the set will be returned. In general, the rules
provide precedence to errors in the following order: kernel
failures, invalid arguments, object not present, access not
permitted, other.&mac.mpo;_check_bpfdesc_receiveint
&mac.mpo;_check_bpfdesc_receivestruct bpf_d
*bpf_dstruct label
*bpflabelstruct ifnet
*ifnetstruct label
*ifnetlabel
&mac.thead;
bpf_dSubject; BPF descriptorbpflabelPolicy label for
bpf_difnetObject; network interfaceifnetlabelPolicy label for
ifnetDetermine whether the MAC framework should permit
datagrams from the passed interface to be delivered to the
buffers of the passed BPF descriptor. Return
(0) for success, or an
errno value for failure Suggested
failure: EACCES for label mismatches,
EPERM for lack of privilege.&mac.mpo;_check_kenv_dumpint
&mac.mpo;_check_kenv_dumpstruct ucred
*cred
&mac.thead;
credSubject credentialDetermine whether the subject should be allowed to
retrieve the kernel environment (see &man.kenv.2;).&mac.mpo;_check_kenv_getint
&mac.mpo;_check_kenv_getstruct ucred
*credchar *name
&mac.thead;
credSubject credentialnameKernel environment variable nameDetermine whether the subject should be allowed to
retrieve the value of the specified kernel environment
variable.&mac.mpo;_check_kenv_setint
&mac.mpo;_check_kenv_setstruct ucred
*credchar *name
&mac.thead;
credSubject credentialnameKernel environment variable nameDetermine whether the subject should be allowed to set
the specified kernel environment variable.&mac.mpo;_check_kenv_unsetint
&mac.mpo;_check_kenv_unsetstruct ucred
*credchar *name
&mac.thead;
credSubject credentialnameKernel environment variable nameDetermine whether the subject should be allowed to unset
the specified kernel environment variable.&mac.mpo;_check_kld_loadint
&mac.mpo;_check_kld_loadstruct ucred
*credstruct vnode
*vpstruct label
*vlabel
&mac.thead;
credSubject credentialvpKernel module vnodevlabelLabel associated with
vpDetermine whether the subject should be allowed to load
the specified module file.&mac.mpo;_check_kld_statint
&mac.mpo;_check_kld_statstruct ucred
*cred
&mac.thead;
credSubject credentialDetermine whether the subject should be allowed to
retrieve a list of loaded kernel module files and associated
statistics.&mac.mpo;_check_kld_unloadint
&mac.mpo;_check_kld_unloadstruct ucred
*cred
&mac.thead;
credSubject credentialDetermine whether the subject should be allowed to
unload a kernel module.&mac.mpo;_check_pipe_ioctlint
&mac.mpo;_check_pipe_ioctlstruct ucred
*credstruct pipe
*pipestruct label
*pipelabelunsigned long
cmdvoid *data
&mac.thead;
credSubject credentialpipePipepipelabelPolicy label associated with
pipecmd&man.ioctl.2; commanddata&man.ioctl.2; dataDetermine whether the subject should be allowed to make
the specified &man.ioctl.2; call.&mac.mpo;_check_pipe_pollint
&mac.mpo;_check_pipe_pollstruct ucred
*credstruct pipe
*pipestruct label
*pipelabel
&mac.thead;
credSubject credentialpipePipepipelabelPolicy label associated with
pipeDetermine whether the subject should be allowed to poll
pipe.&mac.mpo;_check_pipe_readint
&mac.mpo;_check_pipe_readstruct ucred
*credstruct pipe
*pipestruct label
*pipelabel
&mac.thead;
credSubject credentialpipePipepipelabelPolicy label associated with
pipeDetermine whether the subject should be allowed read
access to pipe.&mac.mpo;_check_pipe_relabelint
&mac.mpo;_check_pipe_relabelstruct ucred
*credstruct pipe
*pipestruct label
*pipelabelstruct label
*newlabel
&mac.thead;
credSubject credentialpipePipepipelabelCurrent policy label associated with
pipenewlabelLabel update to
pipelabelDetermine whether the subject should be allowed to
relabel pipe.&mac.mpo;_check_pipe_statint
&mac.mpo;_check_pipe_statstruct ucred
*credstruct pipe
*pipestruct label
*pipelabel
&mac.thead;
credSubject credentialpipePipepipelabelPolicy label associated with
pipeDetermine whether the subject should be allowed to
retrieve statistics related to
pipe.&mac.mpo;_check_pipe_writeint
&mac.mpo;_check_pipe_writestruct ucred
*credstruct pipe
*pipestruct label
*pipelabel
&mac.thead;
credSubject credentialpipePipepipelabelPolicy label associated with
pipeDetermine whether the subject should be allowed to write
to pipe.&mac.mpo;_check_socket_bindint
&mac.mpo;_check_socket_bindstruct ucred
*credstruct socket
*socketstruct label
*socketlabelstruct sockaddr
*sockaddr
&mac.thead;
credSubject credentialsocketSocket to be boundsocketlabelPolicy label for
socketsockaddrAddress of
socket&mac.mpo;_check_socket_connectint
&mac.mpo;_check_socket_connectstruct ucred
*credstruct socket
*socketstruct label
*socketlabelstruct sockaddr
*sockaddr
&mac.thead;
credSubject credentialsocketSocket to be connectedsocketlabelPolicy label for
socketsockaddrAddress of
socketDetermine whether the subject credential
(cred) can connect the passed socket
(socket) to the passed socket address
(sockaddr). Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches,
EPERM for lack of privilege.&mac.mpo;_check_socket_receiveint
&mac.mpo;_check_socket_receivestruct ucred
*credstruct socket
*sostruct label
*socketlabel
&mac.thead;
credSubject credentialsoSocketsocketlabelPolicy label associated with
soDetermine whether the subject should be allowed to
receive information from the socket
so.&mac.mpo;_check_socket_sendint
&mac.mpo;_check_socket_sendstruct ucred
*credstruct socket
*sostruct label
*socketlabel
&mac.thead;
credSubject credentialsoSocketsocketlabelPolicy label associated with
soDetermine whether the subject should be allowed to send
information across the socket
so.&mac.mpo;_check_cred_visibleint
&mac.mpo;_check_cred_visiblestruct ucred
*u1struct ucred
*u2
&mac.thead;
u1Subject credentialu2Object credentialDetermine whether the subject credential
u1 can see other
subjects with the passed subject credential
u2. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches,
EPERM for lack of privilege, or
ESRCH to hide visibility. This call
may be made in a number of situations, including
inter-process status sysctls used by ps,
and in procfs lookups.&mac.mpo;_check_socket_visibleint
&mac.mpo;_check_socket_visiblestruct ucred
*credstruct socket
*socketstruct label
*socketlabel
&mac.thead;
credSubject credentialsocketObject; socketsocketlabelPolicy label for
socket&mac.mpo;_check_ifnet_relabelint
&mac.mpo;_check_ifnet_relabelstruct ucred
*credstruct ifnet
*ifnetstruct label
*ifnetlabelstruct label
*newlabel
&mac.thead;
credSubject credentialifnetObject; network interfaceifnetlabelExisting policy label for
ifnetnewlabelPolicy label update to later be applied to
ifnetDetermine whether the subject credential can relabel the
passed network interface to the passed label update.&mac.mpo;_check_socket_relabelint
&mac.mpo;_check_socket_relabelstruct ucred
*credstruct socket
*socketstruct label
*socketlabelstruct label
*newlabel
&mac.thead;
credSubject credentialsocketObject; socketsocketlabelExisting policy label for
socketnewlabelLabel update to later be applied to
socketlabelDetermine whether the subject credential can relabel the
passed socket to the passed label update.&mac.mpo;_check_cred_relabelint
&mac.mpo;_check_cred_relabelstruct ucred
*credstruct label
*newlabel
&mac.thead;
credSubject credentialnewlabelLabel update to later be applied to
credDetermine whether the subject credential can relabel
itself to the passed label update.&mac.mpo;_check_vnode_relabelint
&mac.mpo;_check_vnode_relabelstruct ucred
*credstruct vnode
*vpstruct label
*vnodelabelstruct label
*newlabel
&mac.thead;
credSubject credentialImmutablevpObject; vnodeLockedvnodelabelExisting policy label for
vpnewlabelPolicy label update to later be applied to
vpDetermine whether the subject credential can relabel the
passed vnode to the passed label update.&mac.mpo;_check_mount_statint &mac.mpo;_check_mount_statstruct ucred
*credstruct mount
*mpstruct label
*mountlabel
&mac.thead;
credSubject credentialmpObject; file system mountmountlabelPolicy label for
mpDetermine whether the subject credential can see the
results of a statfs performed on the file system. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches
or EPERM for lack of privilege. This
call may be made in a number of situations, including during
invocations of &man.statfs.2; and related calls, as well as to
determine what file systems to exclude from listings of file
systems, such as when &man.getfsstat.2; is invoked. &mac.mpo;_check_proc_debugint
&mac.mpo;_check_proc_debugstruct ucred
*credstruct proc
*proc
&mac.thead;
credSubject credentialImmutableprocObject; processDetermine whether the subject credential can debug the
passed process. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, EPERM for lack of
privilege, or ESRCH to hide
visibility of the target. This call may be made in a number
of situations, including use of the &man.ptrace.2; and
&man.ktrace.2; APIs, as well as for some types of procfs
operations.&mac.mpo;_check_vnode_accessint
&mac.mpo;_check_vnode_accessstruct ucred
*credstruct vnode
*vpstruct label
*labelint flags
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vpflags&man.access.2; flagsDetermine how invocations of &man.access.2; and related
calls by the subject credential should return when performed
on the passed vnode using the passed access flags. This
should generally be implemented using the same semantics
used in &mac.mpo;_check_vnode_open.
Return 0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_chdirint
&mac.mpo;_check_vnode_chdirstruct ucred
*credstruct vnode
*dvpstruct label
*dlabel
&mac.thead;
credSubject credentialdvpObject; vnode to &man.chdir.2; intodlabelPolicy label for
dvpDetermine whether the subject credential can change the
process working directory to the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_chrootint
&mac.mpo;_check_vnode_chrootstruct ucred
*credstruct vnode
*dvpstruct label
*dlabel
&mac.thead;
credSubject credentialdvpDirectory vnodedlabelPolicy label associated with
dvpDetermine whether the subject should be allowed to
&man.chroot.2; into the specified directory
(dvp).&mac.mpo;_check_vnode_createint
&mac.mpo;_check_vnode_createstruct ucred
*credstruct vnode
*dvpstruct label
*dlabelstruct componentname
*cnpstruct vattr
*vap
&mac.thead;
credSubject credentialdvpObject; vnodedlabelPolicy label for
dvpcnpComponent name for
dvpvapvnode attributes for vapDetermine whether the subject credential can create a
vnode with the passed parent directory, passed name
information, and passed attribute information. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES. for label mismatch,
or EPERM for lack of privilege.
This call may be made in a number of situations, including
as a result of calls to &man.open.2; with
O_CREAT, &man.mknod.2;, &man.mkfifo.2;, and
others.&mac.mpo;_check_vnode_deleteint
&mac.mpo;_check_vnode_deletestruct ucred
*credstruct vnode
*dvpstruct label
*dlabelstruct vnode
*vpvoid *labelstruct componentname
*cnp
&mac.thead;
credSubject credentialdvpParent directory vnodedlabelPolicy label for
dvpvpObject; vnode to deletelabelPolicy label for
vpcnpComponent name for
vpDetermine whether the subject credential can delete a
vnode from the passed parent directory and passed name
information. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege. This call may be made in a number of situations,
including as a result of calls to &man.unlink.2; and
&man.rmdir.2;. Policies implementing this entry point
should also implement
mpo_check_rename_to to authorize
deletion of objects as a result of being the target of a
rename.&mac.mpo;_check_vnode_deleteaclint
&mac.mpo;_check_vnode_deleteaclstruct ucred *credstruct vnode *vpstruct label *labelacl_type_t type
&mac.thead;
credSubject credentialImmutablevpObject; vnodeLockedlabelPolicy label for
vptypeACL typeDetermine whether the subject credential can delete the
ACL of passed type from the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_execint
&mac.mpo;_check_vnode_execstruct ucred
*credstruct vnode
*vpstruct label
*label
&mac.thead;
credSubject credentialvpObject; vnode to executelabelPolicy label for
vpDetermine whether the subject credential can execute the
passed vnode. Determination of execute privilege is made
separately from decisions about any transitioning event.
Return 0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_getaclint
&mac.mpo;_check_vnode_getaclstruct ucred
*credstruct vnode
*vpstruct label
*labelacl_type_t
type
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vptypeACL typeDetermine whether the subject credential can retrieve
the ACL of passed type from the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_getextattrint
&mac.mpo;_check_vnode_getextattrstruct ucred
*credstruct vnode
*vpstruct label
*labelint
attrnamespaceconst char
*namestruct uio
*uio
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vpattrnamespaceExtended attribute namespacenameExtended attribute nameuioI/O structure pointer; see &man.uio.9;Determine whether the subject credential can retrieve
the extended attribute with the passed namespace and name
from the passed vnode. Policies implementing labeling using
extended attributes may be interested in special handling of
operations on those extended attributes. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_linkint
&mac.mpo;_check_vnode_linkstruct ucred
*credstruct vnode
*dvpstruct label
*dlabelstruct vnode
*vpstruct label
*labelstruct componentname
*cnp
&mac.thead;
credSubject credentialdvpDirectory vnodedlabelPolicy label associated with
dvpvpLink destination vnodelabelPolicy label associated with
vpcnpComponent name for the link being createdDetermine whether the subject should be allowed to
create a link to the vnode vp with
the name specified by cnp.&mac.mpo;_check_vnode_mmapint
&mac.mpo;_check_vnode_mmapstruct ucred
*credstruct vnode
*vpstruct label
*labelint prot
&mac.thead;
credSubject credentialvpVnode to maplabelPolicy label associated with
vpprotMmap protections (see &man.mmap.2;)Determine whether the subject should be allowed to map
the vnode vp with the protections
specified in prot.&mac.mpo;_check_vnode_mmap_downgradevoid
&mac.mpo;_check_vnode_mmap_downgradestruct ucred
*credstruct vnode
*vpstruct label
*labelint *prot
&mac.thead;
credSee
.vplabelprotMmap protections to be downgradedDowngrade the mmap protections based on the subject and
object labels.&mac.mpo;_check_vnode_mprotectint
&mac.mpo;_check_vnode_mprotectstruct ucred
*credstruct vnode
*vpstruct label
*labelint prot
&mac.thead;
credSubject credentialvpMapped vnodeprotMemory protectionsDetermine whether the subject should be allowed to
set the specified memory protections on memory mapped from
the vnode vp.&mac.mpo;_check_vnode_pollint
&mac.mpo;_check_vnode_pollstruct ucred
*active_credstruct ucred
*file_credstruct vnode
*vpstruct label
*label
&mac.thead;
active_credSubject credentialfile_credCredential associated with the struct
filevpPolled vnodelabelPolicy label associated with
vpDetermine whether the subject should be allowed to poll
the vnode vp.&mac.mpo;_check_vnode_rename_fromint
&mac.mpo;_vnode_rename_fromstruct ucred
*credstruct vnode
*dvpstruct label
*dlabelstruct vnode
*vpstruct label
*labelstruct componentname
*cnp
&mac.thead;
credSubject credentialdvpDirectory vnodedlabelPolicy label associated with
dvpvpVnode to be renamedlabelPolicy label associated with
vpcnpComponent name for
vpDetermine whether the subject should be allowed to
rename the vnode vp to something
else.&mac.mpo;_check_vnode_rename_toint
&mac.mpo;_check_vnode_rename_tostruct ucred
*credstruct vnode
*dvpstruct label
*dlabelstruct vnode
*vpstruct label
*labelint samedirstruct componentname
*cnp
&mac.thead;
credSubject credentialdvpDirectory vnodedlabelPolicy label associated with
dvpvpOverwritten vnodelabelPolicy label associated with
vpsamedirBoolean; 1 if the source and
destination directories are the samecnpDestination component nameDetermine whether the subject should be allowed to
rename to the vnode vp, into the
directory dvp, or to the name
represented by cnp. If there is no
existing file to overwrite, vp and
label will be NULL.&mac.mpo;_check_socket_listenint
&mac.mpo;_check_socket_listenstruct ucred
*credstruct socket
*socketstruct label
*socketlabel
&mac.thead;
credSubject credentialsocketObject; socketsocketlabelPolicy label for
socketDetermine whether the subject credential can listen on
the passed socket. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege.&mac.mpo;_check_vnode_lookupint
&mac.mpo;_check_vnode_lookupstruct ucred
*credstruct vnode
*dvpstruct label
*dlabelstruct componentname
*cnp
&mac.thead;
credSubject credentialdvpObject; vnodedlabelPolicy label for
dvpcnpComponent name being looked upDetermine whether the subject credential can perform a
lookup in the passed directory vnode for the passed name.
Return 0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_openint
&mac.mpo;_check_vnode_openstruct ucred
*credstruct vnode
*vpstruct label
*labelint
acc_mode
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vpacc_mode&man.open.2; access modeDetermine whether the subject credential can perform an
open operation on the passed vnode with the passed access
mode. Return 0 for success, or
an errno value for failure. Suggested failure:
EACCES for label mismatch, or
EPERM for lack of privilege.&mac.mpo;_check_vnode_readdirint
&mac.mpo;_check_vnode_readdirstruct ucred
*credstruct vnode
*dvpstruct label
*dlabel
&mac.thead;
credSubject credentialdvpObject; directory vnodedlabelPolicy label for
dvpDetermine whether the subject credential can perform a
readdir operation on the passed
directory vnode. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege.&mac.mpo;_check_vnode_readlinkint
&mac.mpo;_check_vnode_readlinkstruct ucred
*credstruct vnode
*vpstruct label
*label
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vpDetermine whether the subject credential can perform a
readlink operation on the passed
symlink vnode. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege. This call may be made in a number of situations,
including an explicit readlink call by
the user process, or as a result of an implicit
readlink during a name lookup by the
process.&mac.mpo;_check_vnode_revokeint
&mac.mpo;_check_vnode_revokestruct ucred
*credstruct vnode
*vpstruct label
*label
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vpDetermine whether the subject credential can revoke
access to the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_setaclint
&mac.mpo;_check_vnode_setaclstruct ucred
*credstruct vnode
*vpstruct label
*labelacl_type_t
typestruct acl
*acl
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vptypeACL typeaclACLDetermine whether the subject credential can set the
passed ACL of passed type on the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_setextattrint
&mac.mpo;_check_vnode_setextattrstruct ucred
*credstruct vnode
*vpstruct label
*labelint
attrnamespaceconst char
*namestruct uio
*uio
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for vpattrnamespaceExtended attribute namespacenameExtended attribute nameuioI/O structure pointer; see &man.uio.9;Determine whether the subject credential can set the
extended attribute of passed name and passed namespace on
the passed vnode. Policies implementing security labels
backed into extended attributes may want to provide
additional protections for those attributes. Additionally,
policies should avoid making decisions based on the data
referenced from uio, as there is a
potential race condition between this check and the actual
operation. The uio may also be
NULL if a delete operation is being
performed. Return 0 for success,
or an errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_setflagsint
&mac.mpo;_check_vnode_setflagsstruct ucred
*credstruct vnode
*vpstruct label
*labelu_long flags
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vpflagsFile flags; see &man.chflags.2;Determine whether the subject credential can set the
passed flags on the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_setmodeint
&mac.mpo;_check_vnode_setmodestruct ucred
*credstruct vnode
*vpstruct label
*labelmode_t mode
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for vpmodeFile mode; see &man.chmod.2;Determine whether the subject credential can set the
passed mode on the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_vnode_setownerint
&mac.mpo;_check_vnode_setownerstruct ucred
*credstruct vnode
*vpstruct label
*labeluid_t uidgid_t gid
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for vpuidUser IDgidGroup IDDetermine whether the subject credential can set the
passed uid and passed gid as file uid and file gid on the
passed vnode. The IDs may be set to (-1)
to request no update. Return 0
for success, or an errno value for
failure. Suggested failure: EACCES
for label mismatch, or EPERM for lack
of privilege.&mac.mpo;_check_vnode_setutimesint
&mac.mpo;_check_vnode_setutimesstruct ucred
*credstruct vnode
*vpstruct label
*labelstruct timespec
atimestruct timespec
mtime
&mac.thead;
credSubject credentialvpObject; vplabelPolicy label for
vpatimeAccess time; see &man.utimes.2;mtimeModification time; see &man.utimes.2;Determine whether the subject credential can set the
passed access timestamps on the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_proc_schedint
&mac.mpo;_check_proc_schedstruct ucred
*ucredstruct proc
*proc
&mac.thead;
credSubject credentialprocObject; processDetermine whether the subject credential can change the
scheduling parameters of the passed process. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
EPERM for lack of privilege, or
ESRCH to limit visibility.See &man.setpriority.2; for more information.&mac.mpo;_check_proc_signalint
&mac.mpo;_check_proc_signalstruct ucred
*credstruct proc
*procint signal
&mac.thead;
credSubject credentialprocObject; processsignalSignal; see &man.kill.2;Determine whether the subject credential can deliver the
passed signal to the passed process. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
EPERM for lack of privilege, or
ESRCH to limit visibility.&mac.mpo;_check_vnode_statint
&mac.mpo;_check_vnode_statstruct ucred
*credstruct vnode
*vpstruct label
*label
&mac.thead;
credSubject credentialvpObject; vnodelabelPolicy label for
vpDetermine whether the subject credential can
stat the passed vnode. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatch,
or EPERM for lack of
privilege.See &man.stat.2; for more information.&mac.mpo;_check_ifnet_transmitint
&mac.mpo;_check_ifnet_transmitstruct ucred
*credstruct ifnet
*ifnetstruct label
*ifnetlabelstruct mbuf
*mbufstruct label
*mbuflabel
&mac.thead;
credSubject credentialifnetNetwork interfaceifnetlabelPolicy label for
ifnetmbufObject; mbuf to be sentmbuflabelPolicy label for
mbufDetermine whether the network interface can transmit the
passed mbuf. Return 0 for
success, or an errno value for failure.
Suggested failure: EACCES for label
mismatch, or EPERM for lack of
privilege.&mac.mpo;_check_socket_deliverint
&mac.mpo;_check_socket_deliverstruct ucred
*credstruct ifnet
*ifnetstruct label
*ifnetlabelstruct mbuf
*mbufstruct label
*mbuflabel
&mac.thead;
credSubject credentialifnetNetwork interfaceifnetlabelPolicy label for
ifnetmbufObject; mbuf to be deliveredmbuflabelPolicy label for
mbufDetermine whether the socket may receive the datagram
stored in the passed mbuf header. Return
0 for success, or an
errno value for failure. Suggested
failures: EACCES for label mismatch,
or EPERM for lack of
privilege.&mac.mpo;_check_socket_visibleint
&mac.mpo;_check_socket_visiblestruct ucred
*credstruct socket
*sostruct label
*socketlabel
&mac.thead;
credSubject credentialImmutablesoObject; socketsocketlabelPolicy label for
soDetermine whether the subject credential cred can "see"
the passed socket (socket) using
system monitoring functions, such as those employed by
&man.netstat.8; and &man.sockstat.1;. Return
0 for success, or an
errno value for failure. Suggested
failure: EACCES for label mismatches,
EPERM for lack of privilege, or
ESRCH to hide visibility.&mac.mpo;_check_system_acctint
&mac.mpo;_check_system_acctstruct ucred
*ucredstruct vnode
*vpstruct label
*vlabel
&mac.thead;
ucredSubject credentialvpAccounting file; &man.acct.5;vlabelLabel associated with
vpDetermine whether the subject should be allowed to
enable accounting, based on its label and the label of the
accounting log file.&mac.mpo;_check_system_nfsdint
&mac.mpo;_check_system_nfsdstruct ucred
*cred
&mac.thead;
credSubject credentialDetermine whether the subject should be allowed to call
&man.nfssvc.2;.&mac.mpo;_check_system_rebootint
&mac.mpo;_check_system_rebootstruct ucred
*credint howto
&mac.thead;
credSubject credentialhowtohowto parameter from
&man.reboot.2;Determine whether the subject should be allowed to
reboot the system in the specified manner.&mac.mpo;_check_system_settimeint
&mac.mpo;_check_system_settimestruct ucred
*cred
&mac.thead;
credSubject credentialDetermine whether the user should be allowed to set the
system clock.&mac.mpo;_check_system_swaponint
&mac.mpo;_check_system_swaponstruct ucred
*credstruct vnode
*vpstruct label
*vlabel
&mac.thead;
credSubject credentialvpSwap devicevlabelLabel associated with
vpDetermine whether the subject should be allowed to add
vp as a swap device.&mac.mpo;_check_system_sysctlint
&mac.mpo;_check_system_sysctlstruct ucred
*credint *nameu_int *namelenvoid *oldsize_t
*oldlenpint inkernelvoid *newsize_t newlen
&mac.thead;
credSubject credentialnameSee &man.sysctl.3;namelenoldoldlenpinkernelBoolean; 1 if called from
kernelnewSee &man.sysctl.3;newlenDetermine whether the subject should be allowed to make
the specified &man.sysctl.3; transaction.Label Management CallsRelabel events occur when a user process has requested
that the label on an object be modified. A two-phase update
occurs: first, an access control check will be performed to
determine if the update is both valid and permitted, and then
the update itself is performed via a separate entry point.
Relabel entry points typically accept the object, object label
reference, and an update label submitted by the process.
Memory allocation during relabel is discouraged, as relabel
calls are not permitted to fail (failure should be reported
earlier in the relabel check).Userland ArchitectureThe TrustedBSD MAC Framework includes a number of
policy-agnostic elements, including MAC library interfaces
for abstractly managing labels, modifications to the system
credential management and login libraries to support the
assignment of MAC labels to users, and a set of tools to
monitor and modify labels on processes, files, and network
interfaces. More details on the user architecture will
be added to this section in the near future.APIs for Policy-Agnostic Label ManagementThe TrustedBSD MAC Framework provides a number of
library and system calls permitting applications to
manage MAC labels on objects using a policy-agnostic
interface. This permits applications to manipulate
labels for a variety of policies without being
written to support specific policies. These interfaces
are used by general-purpose tools such as &man.ifconfig.8;,
&man.ls.1; and &man.ps.1; to view labels on network
interfaces, files, and processes. The APIs also support
MAC management tools including &man.getfmac.8;,
&man.getpmac.8;, &man.setfmac.8;, &man.setfsmac.8;,
and &man.setpmac.8;. The MAC APIs are documented in
&man.mac.3;.Applications handle MAC labels in two forms: an
internalized form used to return and set labels on
processes and objects (mac_t),
and externalized form based on C strings appropriate for
storage in configuration files, display to the user, or
input from the user. Each MAC label contains a number of
elements, each consisting of a name and value pair.
Policy modules in the kernel bind to specific names
and interpret the values in policy-specific ways. In
the externalized string form, labels are represented
by a comma-delimited list of name and value pairs separated
by the / character. Labels may be
directly converted to and from text using provided APIs;
when retrieving labels from the kernel, internalized
label storage must first be prepared for the desired
label element set. Typically, this is done in one of
two ways: using &man.mac.prepare.3; and an arbitrary
list of desired label elements, or one of the variants
of the call that loads a default element set from the
&man.mac.conf.5; configuration file. Per-object
defaults permit application writers to usefully display
labels associated with objects without being aware of
the policies present in the system.Currently, direct manipulation of label elements
other than by conversion to a text string, string editing,
and conversion back to an internalized label is not supported
by the MAC library. Such interfaces may be added in the
future if they prove necessary for application
writers.Binding of Labels to UsersThe standard user context management interface,
&man.setusercontext.3;, has been modified to retrieve
MAC labels associated with a user's class from
&man.login.conf.5;. These labels are then set along
with other user context when either
LOGIN_SETALL is specified, or when
LOGIN_SETMAC is explicitly
specified.It is expected that, in a future version of FreeBSD,
the MAC label database will be separated from the
login.conf user class abstraction,
and be maintained in a separate database. However, the
&man.setusercontext.3; API should remain the same
following such a change.ConclusionThe TrustedBSD MAC framework permits kernel modules to
augment the system security policy in a highly integrated
manner. They may do this based on existing object properties,
or based on label data that is maintained with the assistance of
the MAC framework. The framework is sufficiently flexible to
implement a variety of policy types, including information flow
security policies such as MLS and Biba, as well as policies
based on existing BSD credentials or file protections. Policy
authors may wish to consult this documentation as well as
existing security modules when implementing a new security
service.
diff --git a/en_US.ISO8859-1/books/developers-handbook/newbus/chapter.sgml b/en_US.ISO8859-1/books/developers-handbook/newbus/chapter.sgml
index 4fda867ee6..c20617c4fc 100644
--- a/en_US.ISO8859-1/books/developers-handbook/newbus/chapter.sgml
+++ b/en_US.ISO8859-1/books/developers-handbook/newbus/chapter.sgml
@@ -1,360 +1,360 @@
JeroenRuigrok van der Werven (asmodai)asmodai@FreeBSD.orgWritten by HitenPandyahiten@uk.FreeBSD.orgNewbusSpecial thanks to Matthew N. Dodd, Warner Losh, Bill Paul,
Doug Rabson, Mike Smith, Peter Wemm and Scott Long.This chapter explains the Newbus device framework in detail.Device DriversPurpose of a Device DriverA device driver is a software component which provides the
interface between the kernel's generic view of a peripheral
(e.g. disk, network adapter) and the actual implementation of the
peripheral. The device driver interface (DDI) is
the defined interface between the kernel and the device driver component.
Types of Device DriversThere used to be days in &unix;, and thus FreeBSD, in which there
were four types of devices defined:block device driverscharacter device driversnetwork device driverspseudo-device driversBlock devices performed in way that used
fixed size blocks [of data]. This type of driver depended on the
so called buffer cache, which had the purpose
to cache accessed blocks of data in a dedicated part of the memory.
Often this buffer cache was based on write-behind, which meant that when
data was modified in memory it got synced to disk whenever the system
did its periodical disk flushing, thus optimizing writes.Character devicesHowever, in the versions of FreeBSD 4.0 and onward the
distinction between block and character devices became non-existent.
Overview of NewbusNewbus is the implementation of a new bus
architecture based on abstraction layers which saw its introduction in
FreeBSD 3.0 when the Alpha port was imported into the source tree. It was
not until 4.0 before it became the default system to use for device
drivers. Its goals are to provide a more object oriented means of
interconnecting the various busses and devices which a host system
provides to the Operating System.Its main features include amongst others:dynamic attachingeasy modularization of driverspseudo-bussesOne of the most prominent changes is the migration from the flat and
ad-hoc system to a device tree lay-out.At the top level resides the root
device which is the parent to hang all other devices on. For each
architecture, there is typically a single child of root
which has such things as host-to-PCI bridges, etc.
attached to it. For x86, this root device is the
nexus device and for Alpha, various
different different models of Alpha have different top-level devices
corresponding to the different hardware chipsets, including
lca, apecs,
cia and tsunami.A device in the Newbus context represents a single hardware entity
in the system. For instance each PCI device is represented by a Newbus
device. Any device in the system can have children; a device which has
children is often called a bus.
Examples of common busses in the system are ISA and PCI which manage lists
of devices attached to ISA and PCI busses respectively.Often, a connection between different kinds of bus is represented by
a bridge device which normally has one
child for the attached bus. An example of this is a
PCI-to-PCI bridge which is represented by a device
pcibN on the parent PCI bus
and has a child pciN for the
attached bus. This layout simplifies the implementation of the PCI bus
tree, allowing common code to be used for both top-level and bridged
busses.Each device in the Newbus architecture asks its parent to map its
resources. The parent then asks its own parent until the nexus is
reached. So, basically the nexus is the only part of the Newbus system
which knows about all resources.An ISA device might want to map its IO port at
0x230, so it asks its parent, in this case the ISA
bus. The ISA bus hands it over to the PCI-to-ISA bridge which in its turn
asks the PCI bus, which reaches the host-to-PCI bridge and finally the
nexus. The beauty of this transition upwards is that there is room to
translate the requests. For example, the 0x230 IO port
request might become memory-mapped at 0xb0000230 on a
MIPS box by the PCI bridge.Resource allocation can be controlled at any place in the device
tree. For instance on many Alpha platforms, ISA interrupts are managed
separately from PCI interrupts and resource allocations for ISA interrupts
are managed by the Alpha's ISA bus device. On IA-32, ISA and PCI
interrupts are both managed by the top-level nexus device. For both
ports, memory and port address space is managed by a single entity - nexus
for IA-32 and the relevant chipset driver on Alpha (e.g. CIA or tsunami).
In order to normalize access to memory and port mapped resources,
Newbus integrates the bus_space APIs from NetBSD.
These provide a single API to replace inb/outb and direct memory
reads/writes. The advantage of this is that a single driver can easily
use either memory-mapped registers or port-mapped registers
(some hardware supports both).This support is integrated into the resource allocation mechanism.
When a resource is allocated, a driver can retrieve the associated
bus_space_tag_t and
bus_space_handle_t from the resource.Newbus also allows for definitions of interface methods in files
dedicated to this purpose. These are the .m files
that are found under the src/sys hierarchy.The core of the Newbus system is an extensible
object-based programming model. Each device in the system
has a table of methods which it supports. The system and other devices
uses those methods to control the device and request services. The
different methods supported by a device are defined by a number of
interfaces. An interface is simply a group
of related methods which can be implemented by a device.In the Newbus system, the methods for a device are provided by the
various device drivers in the system. When a device is attached to a
driver during auto-configuration, it uses the method
table declared by the driver. A device can later
detach from its driver and
re-attach to a new driver with a new method table.
This allows dynamic replacement of drivers which can be useful for driver
development.The interfaces are described by an interface definition language
similar to the language used to define vnode operations for file systems.
The interface would be stored in a methods file (which would normally named
foo_if.m).Newbus Methods
# Foo subsystem/driver (a comment...)
INTERFACE foo
METHOD int doit {
device_t dev;
};
# DEFAULT is the method that will be used, if a method was not
# provided via: DEVMETHOD()
METHOD void doit_to_child {
device_t dev;
driver_t child;
} DEFAULT doit_generic_to_child;
When this interface is compiled, it generates a header file
foo_if.h which contains function
declarations:
int FOO_DOIT(device_t dev);
int FOO_DOIT_TO_CHILD(device_t dev, device_t child);
A source file, foo_if.c is
also created to accompany the automatically generated header file; it
contains implementations of those functions which look up the location
of the relevant functions in the object's method table and call that
function.The system defines two main interfaces. The first fundamental
interface is called device and
includes methods which are relevant to all devices. Methods in the
device interface include
probe,
attach and
detach to control detection of
hardware and shutdown,
suspend and
resume for critical event
notification.The second, more complex interface is
bus. This interface contains
methods suitable for devices which have children, including methods to
access bus specific per-device information
&man.bus.generic.read.ivar.9; and
&man.bus.generic.write.ivar.9;, event notification
(child_detached,
driver_added) and resource
management (alloc_resource,
activate_resource,
deactivate_resource,
- release_resource).
+ release_resource).Many methods in the bus interface are performing
services for some child of the bus device. These methods would normally
use the first two arguments to specify the bus providing the service
and the child device which is requesting the service. To simplify
driver code, many of these methods have accessor functions which
lookup the parent and call a method on the parent. For instance the
method
BUS_TEARDOWN_INTR(device_t dev, device_t child, ...)
can be called using the function
bus_teardown_intr(device_t child, ...).Some bus types in the system define additional interfaces to
provide access to bus-specific functionality. For instance, the PCI
bus driver defines the pci interface which has two
methods read_config and
write_config for accessing the
configuration registers of a PCI device.Newbus APIAs the Newbus API is huge, this section makes some effort at
documenting it. More information to come in the next revision of this
document.Important locations in the source hierarchysrc/sys/[arch]/[arch] - Kernel code for a
specific machine architecture resides in this directory. for example,
the i386 architecture, or the
SPARC64 architecture.src/sys/dev/[bus] - device support for a
specific [bus] resides in this directory.src/sys/dev/pci - PCI bus support code
resides in this directory.src/sys/[isa|pci] - PCI/ISA device drivers
reside in this directory. The PCI/ISA bus support code used to exist
in this directory in FreeBSD version 4.0.Important structures and type definitionsdevclass_t - This is a type definition of a
pointer to a struct devclass.device_method_t - This is same as
kobj_method_t (see
src/sys/kobj.h).device_t - This is a type definition of a
pointer to a struct device.
device_t represents a device in the system. It is
a kernel object. See src/sys/sys/bus_private.h
for implementation details.driver_t - This is a type definition which,
references struct driver. The
driver struct is a class of the
device kernel object; it also holds data private
to for the driver.driver_t implementation
struct driver {
KOBJ_CLASS_FIELDS;
void *priv; /* driver private data */
};
A device_state_t type, which is
an enumeration, device_state. It contains
the possible states of a Newbus device before and after the
autoconfiguration process.Device statesdevice_state_t
/*
* src/sys/sys/bus.h
*/
typedef enum device_state {
DS_NOTPRESENT, /* not probed or probe failed */
DS_ALIVE, /* probe succeeded */
DS_ATTACHED, /* attach method called */
DS_BUSY /* device is open */
} device_state_t;
diff --git a/en_US.ISO8859-1/books/developers-handbook/sound/chapter.sgml b/en_US.ISO8859-1/books/developers-handbook/sound/chapter.sgml
index aeb4656017..0a107812fa 100644
--- a/en_US.ISO8859-1/books/developers-handbook/sound/chapter.sgml
+++ b/en_US.ISO8859-1/books/developers-handbook/sound/chapter.sgml
@@ -1,687 +1,690 @@
Jean-FrancoisDockesContributed by Sound subsystemIntroductionThe FreeBSD sound subsystem cleanly separates generic sound
handling issues from device-specific ones. This makes it easier
to add support for new hardware.The &man.pcm.4; framework is the central piece of the sound
subsystem. It mainly implements the following elements:A system call interface (read, write, ioctls) to
digitized sound and mixer functions. The ioctl command set
is compatible with the legacy OSS or
Voxware interface, allowing common
multimedia applications to be ported without
modification.
+ Common code for processing sound data (format
conversions, virtual channels).A uniform software interface to hardware-specific audio
interface modules.Additional support for some common hardware interfaces
(ac97), or shared hardware-specific code (ex: ISA DMA
routines).The support for specific sound cards is implemented by
hardware-specific drivers, which provide channel and mixer interfaces
to plug into the generic pcm code.In this chapter, the term pcm will
refer to the central, common part of the sound driver, as
opposed to the hardware-specific modules.The prospective driver writer will of course want to start
from an existing module and use the code as the ultimate
reference. But, while the sound code is nice and clean, it is
also mostly devoid of comments. This document tries to give an
overview of the framework interface and answer some questions
that may arise while adapting the existing code.As an alternative, or in addition to starting from a working
example, you can find a commented driver template at
http://people.FreeBSD.org/~cg/template.cFilesAll the relevant code currently (FreeBSD 4.4) lives in
/usr/src/sys/dev/sound/, except for the
public ioctl interface definitions, found in
/usr/src/sys/sys/soundcard.hUnder /usr/src/sys/dev/sound/, the
pcm/ directory holds the central code,
while the isa/ and
pci/ directories have the drivers for ISA
and PCI boards.Probing, attaching, etc.Sound drivers probe and attach in almost the same way as any
hardware driver module. You might want to look at the ISA or PCI specific sections of the handbook for
more information.However, sound drivers differ in some ways:They declare themselves as pcm
class devices, with a struct
snddev_info device private structure: static driver_t xxx_driver = {
"pcm",
xxx_methods,
sizeof(struct snddev_info)
};
DRIVER_MODULE(snd_xxxpci, pci, xxx_driver, pcm_devclass, 0, 0);
MODULE_DEPEND(snd_xxxpci, snd_pcm, PCM_MINVER, PCM_PREFVER,PCM_MAXVER);Most sound drivers need to store additional private
information about their device. A private data structure is
usually allocated in the attach routine. Its address is
passed to pcm by the calls to
pcm_register() and
mixer_init().
pcm later passes back this address
as a parameter in calls to the sound driver
interfaces.The sound driver attach routine should declare its MIXER
or AC97 interface to pcm by calling
mixer_init(). For a MIXER interface,
this causes in turn a call to
xxxmixer_init().The sound driver attach routine declares its general
CHANNEL configuration to pcm by
calling pcm_register(dev, sc, nplay,
nrec), where sc is the address
for the device data structure, used in further calls from
pcm, and nplay
and nrec are the number of play and
record channels.The sound driver attach routine declares each of its
channel objects by calls to
pcm_addchan(). This sets up the
channel glue in pcm and causes in
turn a call to
xxxchannel_init().The sound driver detach routine should call
pcm_unregister() before releasing its
resources.There are two possible methods to handle non-PnP devices:Use a device_identify() method
(example: sound/isa/es1888.c). The
device_identify() method probes for the
hardware at known addresses and, if it finds a supported
device, creates a new pcm device which is then passed to
probe/attach.Use a custom kernel configuration with appropriate hints
for pcm devices (example:
sound/isa/mss.c).pcm drivers should implement
device_suspend,
device_resume and
device_shutdown routines, so that power
management and module unloading function correctly.InterfacesThe interface between the pcm core
and the sound drivers is defined in terms of kernel objects.There are two main interfaces that a sound driver will
usually provide: CHANNEL and either
MIXER or AC97.The AC97 interface is a very small
hardware access (register read/write) interface, implemented by
drivers for hardware with an AC97 codec. In this case, the
actual MIXER interface is provided by the shared AC97 code in
pcm.The CHANNEL interfaceCommon notes for function parametersSound drivers usually have a private data structure to
describe their device, and one structure for each play and
record data channel that it supports.For all CHANNEL interface functions, the first parameter
is an opaque pointer.The second parameter is a pointer to the private
channel data structure, except for
channel_init() which has a pointer to the
private device structure (and returns the channel pointer
for further use by pcm).Overview of data transfer operationsFor sound data transfers, the
pcm core and the sound drivers
communicate through a shared memory area, described by a
struct snd_dbuf.struct snd_dbuf is private to
pcm, and sound drivers obtain
values of interest by calls to accessor functions
(sndbuf_getxxx()).The shared memory area has a size of
sndbuf_getsize() and is divided into
fixed size blocks of sndbuf_getblksz()
bytes.When playing, the general transfer mechanism is as
follows (reverse the idea for recording):pcm initially fills up the
buffer, then calls the sound driver's
xxxchannel_trigger()
function with a parameter of PCMTRIG_START.The sound driver then arranges to repeatedly
transfer the whole memory area
(sndbuf_getbuf(),
sndbuf_getsize()) to the device, in
blocks of sndbuf_getblksz() bytes.
It calls back the chn_intr()pcm function for each
transferred block (this will typically happen at
interrupt time).chn_intr() arranges to copy new
data to the area that was transferred to the device (now
free), and make appropriate updates to the
snd_dbuf structure.
+
+
channel_initxxxchannel_init() is called to
initialize each of the play or record channels. The calls
are initiated from the sound driver attach routine. (See
the probe and attach
section). static void *
xxxchannel_init(kobj_t obj, void *data,
struct snd_dbuf *b, struct pcm_channel *c, int dir)
{
struct xxx_info *sc = data;
struct xxx_chinfo *ch;
...
return ch;
}b is the address for the channel
struct snd_dbuf. It should be
initialized in the function by calling
sndbuf_alloc(). The buffer size to
use is normally a small multiple of the 'typical' unit
transfer size for your device.c is the
pcm channel control structure
pointer. This is an opaque object. The function should
store it in the local channel structure, to be used in
later calls to pcm (ie:
chn_intr(c)).dir indicates the channel
direction (PCMDIR_PLAY or
PCMDIR_REC).The function should return a pointer to the private
area used to control this channel. This will be passed
as a parameter to other channel interface calls.channel_setformatxxxchannel_setformat() should set
up the hardware for the specified channel for the specified
sound format. static int
xxxchannel_setformat(kobj_t obj, void *data, u_int32_t format)
{
struct xxx_chinfo *ch = data;
...
return 0;
}format is specified as an
AFMT_XXX value
(soundcard.h).channel_setspeedxxxchannel_setspeed() sets up the
channel hardware for the specified sampling speed, and
returns the possibly adjusted speed. static int
xxxchannel_setspeed(kobj_t obj, void *data, u_int32_t speed)
{
struct xxx_chinfo *ch = data;
...
return speed;
}channel_setblocksizexxxchannel_setblocksize() sets the
block size, which is the size of unit transactions between
pcm and the sound driver, and
between the sound driver and the device. Typically, this
would be the number of bytes transferred before an interrupt
occurs. During a transfer, the sound driver should call
pcm's
chn_intr() every time this size has
been transferred.Most sound drivers only take note of the block size
here, to be used when an actual transfer will be
started. static int
xxxchannel_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
{
struct xxx_chinfo *ch = data;
...
return blocksize;
}The function returns the possibly adjusted block
size. In case the block size is indeed changed,
sndbuf_resize() should be called to
adjust the buffer.channel_triggerxxxchannel_trigger() is called by
pcm to control data transfer
operations in the driver. static int
xxxchannel_trigger(kobj_t obj, void *data, int go)
{
struct xxx_chinfo *ch = data;
...
return 0;
}go defines the action for the
current call. The possible values are:PCMTRIG_START: the driver
should start a data transfer from or to the channel
buffer. If needed, the buffer base and size can be
retrieved through
sndbuf_getbuf() and
sndbuf_getsize().PCMTRIG_EMLDMAWR /
PCMTRIG_EMLDMARD: this tells the
driver that the input or output buffer may have been
updated. Most drivers just ignore these
calls.PCMTRIG_STOP /
PCMTRIG_ABORT: the driver should
stop the current transfer.If the driver uses ISA DMA,
sndbuf_isadma() should be called before
performing actions on the device, and will take care of the
DMA chip side of things.channel_getptrxxxchannel_getptr() returns the
current offset in the transfer buffer. This will typically
be called by chn_intr(), and this is how
pcm knows where it can transfer
new data.channel_freexxxchannel_free() is called to free
up channel resources, for example when the driver is
unloaded, and should be implemented if the channel data
structures are dynamically allocated or if
sndbuf_alloc() was not used for buffer
allocation.channel_getcaps struct pcmchan_caps *
xxxchannel_getcaps(kobj_t obj, void *data)
{
return &xxx_caps;
}The routine returns a pointer to a (usually
statically-defined) pcmchan_caps
structure (defined in
sound/pcm/channel.h. The structure holds
the minimum and maximum sampling frequencies, and the
accepted sound formats. Look at any sound driver for an
example.More functionschannel_reset(),
channel_resetdone(), and
channel_notify() are for special purposes
and should not be implemented in a driver without discussing
it with the authorities (&a.cg;).channel_setdir() is deprecated.The MIXER interfacemixer_initxxxmixer_init() initializes the
hardware and tells pcm what mixer
devices are available for playing and recording static int
xxxmixer_init(struct snd_mixer *m)
{
struct xxx_info *sc = mix_getdevinfo(m);
u_int32_t v;
[Initialize hardware]
[Set appropriate bits in v for play mixers]
mix_setdevs(m, v);
[Set appropriate bits in v for record mixers]
mix_setrecdevs(m, v)
return 0;
}Set bits in an integer value and call
mix_setdevs() and
mix_setrecdevs() to tell
pcm what devices exist.Mixer bits definitions can be found in
soundcard.h
(SOUND_MASK_XXX values and
SOUND_MIXER_XXX bit shifts).mixer_setxxxmixer_set() sets the volume
level for one mixer device. static int
xxxmixer_set(struct snd_mixer *m, unsigned dev,
unsigned left, unsigned right)
{
struct sc_info *sc = mix_getdevinfo(m);
[set volume level]
return left | (right << 8);
}The device is specified as a SOUND_MIXER_XXX
valueThe volume values are specified in
range [0-100]. A value of zero should mute the
device.As the hardware levels probably won't match the
input scale, and some rounding will occur, the routine
returns the actual level values (in range 0-100) as
shown.mixer_setrecsrcxxxmixer_setrecsrc() sets the
recording source device. static int
xxxmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
{
struct xxx_info *sc = mix_getdevinfo(m);
[look for non zero bit(s) in src, set up hardware]
[update src to reflect actual action]
return src;
}The desired recording devices are specified as a
bit fieldThe actual devices set for recording are returned.
Some drivers can only set one device for recording. The
function should return -1 if an error occurs.mixer_uninit, mixer_reinitxxxmixer_uninit() should ensure
that all sound is muted and if possible mixer hardware
should be powered down xxxmixer_reinit() should ensure
that the mixer hardware is powered up and any settings not
controlled by mixer_set() or
mixer_setrecsrc() are restored.The AC97 interfaceThe AC97 interface is implemented
by drivers with an AC97 codec. It only has three methods:xxxac97_init() returns
the number of ac97 codecs found.ac97_read() and
ac97_write() read or write a specified
register.The AC97 interface is used by the
AC97 code in pcm to perform higher
level operations. Look at
sound/pci/maestro3.c or many others under
sound/pci/ for an example.