diff options
author | Sergio Carlavilla Delgado <carlavilla@FreeBSD.org> | 2021-01-25 23:31:29 +0000 |
---|---|---|
committer | Sergio Carlavilla Delgado <carlavilla@FreeBSD.org> | 2021-01-25 23:31:29 +0000 |
commit | 989d921f5d4ac8d8b7c831c13b8954ad1901be24 (patch) | |
tree | a5d768f9af4b55422fdf5b17064879ae1c7ce032 /en_US.ISO8859-1/books | |
parent | 0cff342f42461c5081b98bce7581f43df319e4f4 (diff) | |
download | doc-989d921f5d4ac8d8b7c831c13b8954ad1901be24.tar.gz doc-989d921f5d4ac8d8b7c831c13b8954ad1901be24.zip |
Migrate doc to Hugo/AsciiDoctor
I'm very pleased to announce the release of
our new website and documentation using
the new toolchain with Hugo and AsciiDoctor.
To get more information about the new toolchain
please read the FreeBSD Documentation Project Primer[1],
Hugo docs[2] and AsciiDoctor docs[3].
Acknowledgment:
Benedict Reuschling <bcr@>
Glen Barber <gjb@>
Hiroki Sato <hrs@>
Li-Wen Hsu <lwhsu@>
Sean Chittenden <seanc@>
The FreeBSD Foundation
[1] https://docs.FreeBSD.org/en/books/fdp-primer/
[2] https://gohugo.io/documentation/
[3] https://docs.asciidoctor.org/home/
Approved by: doceng, core
Diffstat (limited to 'en_US.ISO8859-1/books')
186 files changed, 0 insertions, 173932 deletions
diff --git a/en_US.ISO8859-1/books/Makefile b/en_US.ISO8859-1/books/Makefile deleted file mode 100644 index 9874dfb34e..0000000000 --- a/en_US.ISO8859-1/books/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# $FreeBSD$ - -SUBDIR = arch-handbook -SUBDIR+= design-44bsd -SUBDIR+= dev-model -SUBDIR+= developers-handbook -SUBDIR+= faq -SUBDIR+= fdp-primer -SUBDIR+= handbook -SUBDIR+= porters-handbook - -ROOT_SYMLINKS= faq handbook - -DOC_PREFIX?= ${.CURDIR}/../.. -.include "${DOC_PREFIX}/share/mk/doc.project.mk" diff --git a/en_US.ISO8859-1/books/Makefile.inc b/en_US.ISO8859-1/books/Makefile.inc deleted file mode 100644 index 2bcfd06112..0000000000 --- a/en_US.ISO8859-1/books/Makefile.inc +++ /dev/null @@ -1,5 +0,0 @@ -# -# $FreeBSD$ -# - -DESTDIR?= ${DOCDIR}/en_US.ISO8859-1/books/${.CURDIR:T} diff --git a/en_US.ISO8859-1/books/arch-handbook/Makefile b/en_US.ISO8859-1/books/arch-handbook/Makefile deleted file mode 100644 index 5f933755f9..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/Makefile +++ /dev/null @@ -1,57 +0,0 @@ -# -# $FreeBSD$ -# -# Build the FreeBSD Architecture Handbook. -# - -MAINTAINER=doc@FreeBSD.org - -DOC?= book - -FORMATS?= html-split - -INSTALL_COMPRESSED?= gz -INSTALL_ONLY_COMPRESSED?= - -# -# SRCS lists the individual XML files that make up the document. Changes -# to any of these files will force a rebuild -# - -# XML content -SRCS= book.xml -SRCS+= boot/chapter.xml -SRCS+= driverbasics/chapter.xml -SRCS+= isa/chapter.xml -SRCS+= jail/chapter.xml -SRCS+= kobj/chapter.xml -SRCS+= locking/chapter.xml -SRCS+= mac/chapter.xml -SRCS+= newbus/chapter.xml -SRCS+= pci/chapter.xml -SRCS+= scsi/chapter.xml -SRCS+= smp/chapter.xml -SRCS+= sound/chapter.xml -SRCS+= pccard/chapter.xml -SRCS+= sysinit/chapter.xml -SRCS+= usb/chapter.xml -SRCS+= vm/chapter.xml - -# Images from the cross-document image library -IMAGES_LIB= callouts/1.png -IMAGES_LIB+= callouts/2.png -IMAGES_LIB+= callouts/3.png -IMAGES_LIB+= callouts/4.png -IMAGES_LIB+= callouts/5.png -IMAGES_LIB+= callouts/6.png -IMAGES_LIB+= callouts/7.png -IMAGES_LIB+= callouts/8.png -IMAGES_LIB+= callouts/9.png -IMAGES_LIB+= callouts/10.png - -# Entities - -URL_RELPREFIX?= ../../../.. -DOC_PREFIX?= ${.CURDIR}/../../.. - -.include "${DOC_PREFIX}/share/mk/doc.project.mk" diff --git a/en_US.ISO8859-1/books/arch-handbook/book.xml b/en_US.ISO8859-1/books/arch-handbook/book.xml deleted file mode 100644 index 83fbc2a758..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/book.xml +++ /dev/null @@ -1,192 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1"?> -<!DOCTYPE book PUBLIC "-//FreeBSD//DTD DocBook XML V5.0-Based Extension//EN" - "http://www.FreeBSD.org/XML/share/xml/freebsd50.dtd" [ -<!ENTITY % chapters SYSTEM "chapters.ent"> -%chapters; -<!ENTITY % mac-entities SYSTEM "mac.ent"> -%mac-entities; -]> -<!-- - The FreeBSD Documentation Project - - $FreeBSD$ ---> -<book xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" - xml:lang="en"> - - <info> - <title>&os; Architecture Handbook</title> - - <author><orgname>The FreeBSD Documentation - Project</orgname></author> - - <pubdate>$FreeBSD$</pubdate> - - <copyright> - <year>2000</year> - <year>2001</year> - <year>2002</year> - <year>2003</year> - <year>2004</year> - <year>2005</year> - <year>2006</year> - <year>2012</year> - <year>2013</year> - <holder>The FreeBSD Documentation Project</holder> - </copyright> - - <legalnotice xml:id="trademarks" role="trademarks"> - &tm-attrib.freebsd; - &tm-attrib.unix; - &tm-attrib.apple; - &tm-attrib.microsoft; - &tm-attrib.general; - </legalnotice> - - &legalnotice; - - <releaseinfo>$FreeBSD$</releaseinfo> - - <abstract> - <para>Welcome to the &os; Architecture Handbook. This manual is - a - <emphasis>work in progress</emphasis> and is the work of many - individuals. Many sections do not yet exist and some of those - that do exist need to be updated. If you are interested in - helping with this project, send email to the &a.doc;.</para> - - <para>The latest version of this document is always available - from the <link xlink:href="&url.base;/index.html">FreeBSD - World Wide Web server</link>. It may also be downloaded in - a variety of formats and compression options from the <link - xlink:href="https://download.freebsd.org/ftp/doc/">FreeBSD - FTP server</link> or one of the numerous <link - xlink:href="&url.books.handbook;/mirrors-ftp.html">mirror - sites</link>.</para> - </abstract> - </info> - - <part xml:id="kernel"> - <title>Kernel</title> - - &chap.boot; - &chap.locking; - &chap.kobj; - &chap.jail; - &chap.sysinit; - &chap.mac; - &chap.vm; - &chap.smp; - - </part> - - <part xml:id="devicedrivers"> - <title>Device Drivers</title> - - &chap.driverbasics; - &chap.isa; - &chap.pci; - &chap.scsi; - &chap.usb; - &chap.newbus; - - &chap.snd; - &chap.pccard; - - </part> - -<!-- XXX - finish me - <part id="architectures"> - <title>Architectures</title> - - <chapter id="i386"> - <title>* I386</title> - - <para>Talk about <literal>i386</literal> specific &os; - architecture.</para> - </chapter> - - <chapter id="sparc64"> - <title>* SPARC64</title> - - <para>Talk about <literal>SPARC64</literal> specific &os; - architecture.</para> - </chapter> - - <chapter id="amd64"> - <title>* AMD64</title> - - <para>Talk about <literal>AMD64</literal> specific &os; - architecture.</para> - </chapter> - - <chapter id="powerpc"> - <title>* PowerPC</title> - - <para>Talk about <literal>PowerPC</literal> specific &os; - architecture.</para> - </chapter> - </part> ---> - - <part xml:id="appendices"> - <title>Appendices</title> - - <bibliography> - - <biblioentry xreflabel="1"> - <authorgroup> - <author> - <personname> - <firstname>Marshall</firstname> - <othername role="Middle">Kirk</othername> - <surname>McKusick</surname> - </personname> - </author> - <author> - <personname> - <firstname>Keith</firstname> - <surname>Bostic</surname> - </personname> - </author> - <author> - <personname> - <firstname>Michael</firstname> - <othername role="MI">J</othername> - <surname>Karels</surname> - </personname> - </author> - <author> - <personname> - <firstname>John</firstname> - <othername role="MI">S</othername> - <surname>Quarterman</surname> - </personname> - </author> - </authorgroup> - - <copyright> - <year>1996</year> - <holder>Addison-Wesley Publishing Company, Inc.</holder> - </copyright> - - <biblioid class="isbn">0-201-54979-4</biblioid> - - <publisher> - <publishername>Addison-Wesley Publishing Company, - Inc.</publishername> - </publisher> - - <citetitle>The Design and Implementation of the 4.4 BSD - Operating System</citetitle> - - <pagenums>1-2</pagenums> - </biblioentry> - - </bibliography> - </part> - - &chap.index; - -</book> diff --git a/en_US.ISO8859-1/books/arch-handbook/boot/chapter.xml b/en_US.ISO8859-1/books/arch-handbook/boot/chapter.xml deleted file mode 100644 index 2ba2795fb3..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/boot/chapter.xml +++ /dev/null @@ -1,2396 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1"?> -<!-- -The FreeBSD Documentation Project - -Copyright (c) 2002 Sergey Lyubka <devnull@uptsoft.com> -All rights reserved -Copyright (c) 2014 Sergio Andr?s G?mez del Real <Sergio.G.delReal@gmail.com> -All rights reserved -$FreeBSD$ ---> - -<chapter xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" - xml:id="boot"> - - <info> - <title>Bootstrapping and Kernel Initialization</title> - - <authorgroup> - <author> - <personname> - <firstname>Sergey</firstname> - <surname>Lyubka</surname> - </personname> - - <contrib>Contributed by </contrib> - </author> - <!-- devnull@uptsoft.com 12 Jun 2002 --> - </authorgroup> - - <authorgroup> - <author> - <personname> - <firstname>Sergio Andrés</firstname> - <surname> Gómez del Real</surname> - </personname> - - <contrib>Updated and enhanced by </contrib> - </author> - <!-- Sergio.G.DelReal@gmail.com Jan 2014 --> - </authorgroup> - </info> - - <sect1 xml:id="boot-synopsis"> - <title>Synopsis</title> - - <indexterm><primary>BIOS</primary></indexterm> - <indexterm><primary>firmware</primary></indexterm> - <indexterm><primary>POST</primary></indexterm> - <indexterm><primary>IA-32</primary></indexterm> - <indexterm><primary>booting</primary></indexterm> - <indexterm><primary>system initialization</primary></indexterm> - <para>This chapter is an overview of the boot and system - initialization processes, starting from the - <acronym>BIOS</acronym> (firmware) <acronym>POST</acronym>, 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.</para> - - <para>The &os; boot process can be surprisingly complex. After - control is passed from the <acronym>BIOS</acronym>, a - considerable amount of low-level configuration must be done - before the kernel can be loaded and executed. This setup must - be done in a simple and flexible manner, allowing the user a - great deal of customization possibilities.</para> - </sect1> - - <sect1 xml:id="boot-overview"> - <title>Overview</title> - - <para>The boot process is an extremely machine-dependent - activity. Not only must code be written for every computer - architecture, but there may also be multiple types of booting on - the same architecture. For example, a directory listing of - <filename>/usr/src/sys/boot</filename> - reveals a great amount of architecture-dependent code. There is - a directory for each of the various supported architectures. In - the x86-specific <filename>i386</filename> - directory, there are subdirectories for different boot standards - like <filename>mbr</filename> (Master Boot Record), - <filename>gpt</filename> (<acronym>GUID</acronym> Partition - Table), and <filename>efi</filename> (Extensible Firmware - Interface). Each boot standard has its own conventions and data - structures. The example that follows shows booting an x86 - computer from an <acronym>MBR</acronym> hard drive with the &os; - <filename>boot0</filename> multi-boot loader stored in the very - first sector. That boot code starts the &os; three-stage boot - process.</para> - - <para>The key to understanding this process is that it is a series - of stages of increasing complexity. These stages are - <filename>boot1</filename>, <filename>boot2</filename>, and - <filename>loader</filename> (see &man.boot.8; for more detail). - The boot system executes each stage in sequence. The last - stage, <filename>loader</filename>, is responsible for loading - the &os; kernel. Each stage is examined in the following - sections.</para> - - <para>Here is an example of the output generated by the - different boot stages. Actual output - may differ from machine to machine:</para> - - <informaltable frame="none" pgwide="0"> - <tgroup cols="2"> - <tbody> - <row> - <entry>&os; Component</entry> - <entry>Output (may vary)</entry> - </row> - - <row> - <entry><literal>boot0</literal></entry> - <entry><screen>F1 FreeBSD -F2 BSD -F5 Disk 2</screen></entry> - </row> - - <row> - <entry><literal>boot2</literal> - <footnote><para>This prompt will appear if the user - presses a key just after selecting an OS to boot at - the <literal>boot0</literal> - stage.</para></footnote></entry> - <entry><screen>>>FreeBSD/i386 BOOT -Default: 1:ad(1,a)/boot/loader -boot:</screen></entry> - </row> - - <row> - <entry><filename>loader</filename></entry> - <entry><screen>BTX loader 1.00 BTX version is 1.02 -Consoles: internal video/keyboard -BIOS drive C: is disk0 -BIOS 639kB/2096064kB available memory - -FreeBSD/x86 bootstrap loader, Revision 1.1 -Console internal video/keyboard -(root@snap.freebsd.org, Thu Jan 16 22:18:05 UTC 2014) -Loading /boot/defaults/loader.conf -/boot/kernel/kernel text=0xed9008 data=0x117d28+0x176650 syms=[0x8+0x137988+0x8+0x1515f8]</screen></entry> - </row> - - <row> - <entry>kernel</entry> - <entry><screen>Copyright (c) 1992-2013 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 is a registered trademark of The FreeBSD Foundation. -FreeBSD 10.0-RELEASE #0 r260789: Thu Jan 16 22:34:59 UTC 2014 - root@snap.freebsd.org:/usr/obj/usr/src/sys/GENERIC amd64 -FreeBSD clang version 3.3 (tags/RELEASE_33/final 183502) 20130610</screen></entry> - </row> - </tbody> - </tgroup> - </informaltable> - </sect1> - - <sect1 xml:id="boot-bios"> - <title>The <acronym>BIOS</acronym></title> - - <para>When the computer powers on, the processor's registers are - set to some predefined values. One of the registers is the - <emphasis>instruction pointer</emphasis> register, and its value - after a power on is well defined: it is a 32-bit value of - <literal>0xfffffff0</literal>. The instruction pointer register - (also known as the Program Counter) points to code to be - executed by the processor. Another important register is the - <literal>cr0</literal> 32-bit control register, and its value - just after a reboot is <literal>0</literal>. One of - <literal>cr0</literal>'s bits, the PE (Protection Enabled) bit, - indicates whether the processor is running in 32-bit protected - mode or 16-bit real mode. Since this bit is cleared at boot - time, the processor boots in 16-bit real mode. Real mode means, - among other things, that linear and physical addresses are - identical. The reason for the processor not to start - immediately in 32-bit protected mode is backwards compatibility. - In particular, the boot process relies on the services provided - by the <acronym>BIOS</acronym>, and the <acronym>BIOS</acronym> - itself works in legacy, 16-bit code.</para> - - <para>The value of <literal>0xfffffff0</literal> is slightly less - than 4 GB, so unless the machine has 4 GB of physical - memory, it cannot point to a valid memory address. The - computer's hardware translates this address so that it points to - a <acronym>BIOS</acronym> memory block.</para> - - <para>The <acronym>BIOS</acronym> (Basic Input Output - System) is a chip on the motherboard that has a relatively small - amount of read-only memory (<acronym>ROM</acronym>). This - memory contains various low-level routines that are specific to - the hardware supplied with the motherboard. The processor will - first jump to the address 0xfffffff0, which really resides in - the <acronym>BIOS</acronym>'s memory. Usually this address - contains a jump instruction to the <acronym>BIOS</acronym>'s - POST routines.</para> - - <para>The <acronym>POST</acronym> (Power On Self Test) - is a set of routines including the memory check, system bus - check, and other low-level initialization so the - <acronym>CPU</acronym> can set up the computer properly. The - important step of this stage is determining the boot device. - Modern <acronym>BIOS</acronym> implementations permit the - selection of a boot device, allowing booting from a floppy, - <acronym>CD-ROM</acronym>, hard disk, or other devices.</para> - - <para>The very last thing in the <acronym>POST</acronym> is the - <literal>INT 0x19</literal> instruction. The - <literal>INT 0x19</literal> handler reads 512 bytes from the - first sector of boot device into the memory at address - <literal>0x7c00</literal>. The term - <emphasis>first sector</emphasis> originates from hard drive - architecture, where the magnetic plate is divided into a number - of cylindrical tracks. Tracks are numbered, and every track is - divided into a number (usually 64) of sectors. Track numbers - start at 0, but sector numbers start from 1. Track 0 is the - outermost on the magnetic plate, and sector 1, the first sector, - has a special purpose. It is also called the - <acronym>MBR</acronym>, or Master Boot Record. The remaining - sectors on the first track are never used.</para> - - <para>This sector is our boot-sequence starting point. As we will - see, this sector contains a copy of our - <filename>boot0</filename> program. A jump is made by the - <acronym>BIOS</acronym> to address <literal>0x7c00</literal> so - it starts executing.</para> - </sect1> - - <sect1 xml:id="boot-boot0"> - <title>The Master Boot Record (<literal>boot0</literal>)</title> - - <indexterm><primary>MBR</primary></indexterm> - - <para>After control is received from the <acronym>BIOS</acronym> - at memory address <literal>0x7c00</literal>, - <filename>boot0</filename> starts executing. It is the first - piece of code under &os; control. The task of - <filename>boot0</filename> is quite simple: scan the partition - table and let the user choose which partition to boot from. The - Partition Table is a special, standard data structure embedded - in the <acronym>MBR</acronym> (hence embedded in - <filename>boot0</filename>) describing the four standard PC - <quote>partitions</quote> - <footnote> - <para><link - xlink:href="http://en.wikipedia.org/wiki/Master_boot_record"></link></para></footnote>. - <filename>boot0</filename> resides in the filesystem as - <filename>/boot/boot0</filename>. It is a small 512-byte file, - and it is exactly what &os;'s installation procedure wrote to - the hard disk's <acronym>MBR</acronym> if you chose the - <quote>bootmanager</quote> option at installation time. Indeed, - <filename>boot0</filename> <emphasis>is</emphasis> the - <acronym>MBR</acronym>.</para> - - <para>As mentioned previously, the <literal>INT 0x19</literal> - instruction causes the <literal>INT 0x19</literal> handler to - load an <acronym>MBR</acronym> (<filename>boot0</filename>) into - memory at address <literal>0x7c00</literal>. The source file - for <filename>boot0</filename> can be found in - <filename>sys/boot/i386/boot0/boot0.S</filename> - which is an - awesome piece of code written by Robert Nordier.</para> - - <para>A special structure starting from offset - <literal>0x1be</literal> in the <acronym>MBR</acronym> is called - the <emphasis>partition table</emphasis>. It has four records - of 16 bytes each, called <emphasis>partition records</emphasis>, - which represent how the hard disk is partitioned, or, in &os;'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 <filename>boot0</filename>'s code - will refuse to proceed.</para> - - <para>A partition record has the following fields:</para> - - <itemizedlist> - <listitem> - <para>the 1-byte filesystem type</para> - </listitem> - - <listitem> - <para>the 1-byte bootable flag</para> - </listitem> - - <listitem> - <para>the 6 byte descriptor in CHS format</para> - </listitem> - - <listitem> - <para>the 8 byte descriptor in LBA format</para> - </listitem> - </itemizedlist> - - <para>A partition record descriptor contains information about - where exactly the partition resides on the drive. Both - descriptors, <acronym>LBA</acronym> and <acronym>CHS</acronym>, - describe the same information, but in different ways: - <acronym>LBA</acronym> (Logical Block Addressing) has the - starting sector for the partition and the partition's length, - while <acronym>CHS</acronym> (Cylinder Head Sector) has - coordinates for the first and last sectors of the partition. - The partition table ends with the special signature - <literal>0xaa55</literal>.</para> - - <para>The <acronym>MBR</acronym> must fit into 512 bytes, a single - disk sector. This program uses low-level <quote>tricks</quote> - like taking advantage of the side effects of certain - instructions and reusing register values from previous - operations to make the most out of the fewest possible - instructions. Care must also be taken when handling the - partition table, which is embedded in the <acronym>MBR</acronym> - itself. For these reasons, be very careful when modifying - <filename>boot0.S</filename>.</para> - - <para>Note that the <filename>boot0.S</filename> source file - is assembled <quote>as is</quote>: instructions are translated - one by one to binary, with no additional information (no - <acronym>ELF</acronym> file format, for example). This kind of - low-level control is achieved at link time through special - control flags passed to the linker. For example, the text - section of the program is set to be located at address - <literal>0x600</literal>. In practice this means that - <filename>boot0</filename> must be loaded to memory address - <literal>0x600</literal> in order to function properly.</para> - - <para>It is worth looking at the <filename>Makefile</filename> for - <filename>boot0</filename> - (<filename>sys/boot/i386/boot0/Makefile</filename>), as it - defines some of the run-time behavior of - <filename>boot0</filename>. For instance, if a terminal - connected to the serial port (COM1) is used for I/O, the macro - <literal>SIO</literal> must be defined - (<literal>-DSIO</literal>). <literal>-DPXE</literal> enables - boot through <acronym>PXE</acronym> by pressing - <keycap>F6</keycap>. Additionally, the program defines a set of - <emphasis>flags</emphasis> that allow further modification of - its behavior. All of this is illustrated in the - <filename>Makefile</filename>. For example, look at the - linker directives which command the linker to start the text - section at address <literal>0x600</literal>, and to build the - output file <quote>as is</quote> (strip out any file - formatting):</para> - - <figure xml:id="boot-boot0-makefile-as-is"> - <title><filename>sys/boot/i386/boot0/Makefile</filename></title> - - <programlisting> BOOT_BOOT0_ORG?=0x600 - LDFLAGS=-e start -Ttext ${BOOT_BOOT0_ORG} \ - -Wl,-N,-S,--oformat,binary</programlisting> - </figure> - - <para>Let us now start our study of the <acronym>MBR</acronym>, or - <filename>boot0</filename>, starting where execution - begins.</para> - - <note> - <para>Some modifications have been made to some instructions in - favor of better exposition. For example, some macros are - expanded, and some macro tests are omitted when the result of - the test is known. This applies to all of the code examples - shown.</para> - </note> - - <figure xml:id="boot-boot0-entrypoint"> - <title><filename>sys/boot/i386/boot0/boot0.S</filename></title> - - <programlisting>start: - cld # String ops inc - xorw %ax,%ax # Zero - movw %ax,%es # Address - movw %ax,%ds # data - movw %ax,%ss # Set up - movw 0x7c00,%sp # stack</programlisting> - </figure> - - <para>This first block of code is the entry point of the program. - It is where the <acronym>BIOS</acronym> transfers control. - First, it makes sure that the string operations autoincrement - its pointer operands (the <literal>cld</literal> instruction) - <footnote> - <para>When in doubt, we refer the reader to the official Intel - manuals, which describe the exact semantics for each - instruction: <link - xlink:href="http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html"></link>.</para></footnote>. - Then, as it makes no assumption about the state of the segment - registers, it initializes them. Finally, it sets the stack - pointer register (<literal>%sp</literal>) to address - <literal>0x7c00</literal>, so we have a working stack.</para> - - <para>The next block is responsible for the relocation and - subsequent jump to the relocated code.</para> - - <figure xml:id="boot-boot0-relocation"> - <title><filename>sys/boot/i386/boot0/boot0.S</filename></title> - - <programlisting> movw $0x7c00,%si # Source - movw $0x600,%di # Destination - movw $512,%cx # Word count - rep # Relocate - movsb # code - movw %di,%bp # Address variables - movb $16,%cl # Words to clear - rep # Zero - stosb # them - incb -0xe(%di) # Set the S field to 1 - jmp main-0x7c00+0x600 # Jump to relocated code</programlisting> - </figure> - - <para>As <filename>boot0</filename> is loaded by the - <acronym>BIOS</acronym> to address <literal>0x7C00</literal>, it - copies itself to address <literal>0x600</literal> and then - transfers control there (recall that it was linked to execute at - address <literal>0x600</literal>). The source address, - <literal>0x7c00</literal>, is copied to register - <literal>%si</literal>. The destination address, - <literal>0x600</literal>, to register <literal>%di</literal>. - The number of bytes to copy, <literal>512</literal> (the - program's size), is copied to register <literal>%cx</literal>. - Next, the <literal>rep</literal> instruction repeats the - instruction that follows, that is, <literal>movsb</literal>, the - number of times dictated by the <literal>%cx</literal> register. - The <literal>movsb</literal> instruction copies the byte pointed - to by <literal>%si</literal> to the address pointed to by - <literal>%di</literal>. This is repeated another 511 times. On - each repetition, both the source and destination registers, - <literal>%si</literal> and <literal>%di</literal>, are - incremented by one. Thus, upon completion of the 512-byte copy, - <literal>%di</literal> has the value - <literal>0x600</literal>+<literal>512</literal>= - <literal>0x800</literal>, and <literal>%si</literal> has the - value <literal>0x7c00</literal>+<literal>512</literal>= - <literal>0x7e00</literal>; we have thus completed the code - <emphasis>relocation</emphasis>.</para> - - <para>Next, the destination register - <literal>%di</literal> is copied to <literal>%bp</literal>. - <literal>%bp</literal> gets the value <literal>0x800</literal>. - The value <literal>16</literal> is copied to - <literal>%cl</literal> in preparation for a new string operation - (like our previous <literal>movsb</literal>). Now, - <literal>stosb</literal> is executed 16 times. This instruction - copies a <literal>0</literal> value to the address pointed to by - the destination register (<literal>%di</literal>, which is - <literal>0x800</literal>), and increments it. This is repeated - another 15 times, so <literal>%di</literal> ends up with value - <literal>0x810</literal>. Effectively, this clears the address - range <literal>0x800</literal>-<literal>0x80f</literal>. This - range is used as a (fake) partition table for writing the - <acronym>MBR</acronym> back to disk. Finally, the sector field - for the <acronym>CHS</acronym> addressing of this fake partition - is given the value 1 and a jump is made to the main function - from the relocated code. Note that until this jump to the - relocated code, any reference to an absolute address was - avoided.</para> - - <para>The following code block tests whether the drive number - provided by the <acronym>BIOS</acronym> should be used, or - the one stored in <filename>boot0</filename>.</para> - - <figure xml:id="boot-boot0-drivenumber"> - <title><filename>sys/boot/i386/boot0/boot0.S</filename></title> - - <programlisting>main: - testb $SETDRV,-69(%bp) # Set drive number? - jnz disable_update # Yes - testb %dl,%dl # Drive number valid? - js save_curdrive # Possibly (0x80 set)</programlisting> - </figure> - - <para>This code tests the <literal>SETDRV</literal> bit - (<literal>0x20</literal>) in the <emphasis>flags</emphasis> - variable. Recall that register <literal>%bp</literal> points to - address location <literal>0x800</literal>, so the test is done - to the <emphasis>flags</emphasis> variable at address - <literal>0x800</literal>-<literal>69</literal>= - <literal>0x7bb</literal>. This is an example of the type of - modifications that can be done to <filename>boot0</filename>. - The <literal>SETDRV</literal> flag is not set by default, but it - can be set in the <filename>Makefile</filename>. When set, the - drive number stored in the <acronym>MBR</acronym> is used - instead of the one provided by the <acronym>BIOS</acronym>. We - assume the defaults, and that the <acronym>BIOS</acronym> - provided a valid drive number, so we jump to - <literal>save_curdrive</literal>.</para> - - <para>The next block saves the drive number provided by the - <acronym>BIOS</acronym>, and calls <literal>putn</literal> to - print a new line on the screen.</para> - - <figure xml:id="boot-boot0-savedrivenumber"> - <title><filename>sys/boot/i386/boot0/boot0.S</filename></title> - - <programlisting>save_curdrive: - movb %dl, (%bp) # Save drive number - pushw %dx # Also in the stack -#ifdef TEST /* test code, print internal bios drive */ - rolb $1, %dl - movw $drive, %si - call putkey -#endif - callw putn # Print a newline</programlisting> - </figure> - - <para>Note that we assume <varname>TEST</varname> is not defined, - so the conditional code in it is not assembled and will not - appear in our executable <filename>boot0</filename>.</para> - - <para>Our next block implements the actual scanning of the - partition table. It prints to the screen the partition type for - each of the four entries in the partition table. It compares - each type with a list of well-known operating system file - systems. Examples of recognized partition types are - <acronym>NTFS</acronym> (&windows;, ID 0x7), - <literal>ext2fs</literal> (&linux;, ID 0x83), and, of course, - <literal>ffs</literal>/<literal>ufs2</literal> (&os;, ID 0xa5). - The implementation is fairly simple.</para> - - <figure xml:id="boot-boot0-partition-scan"> - <title><filename>sys/boot/i386/boot0/boot0.S</filename></title> - - <programlisting> movw $(partbl+0x4),%bx # Partition table (+4) - xorw %dx,%dx # Item number - -read_entry: - movb %ch,-0x4(%bx) # Zero active flag (ch == 0) - btw %dx,_FLAGS(%bp) # Entry enabled? - jnc next_entry # No - movb (%bx),%al # Load type - test %al, %al # skip empty partition - jz next_entry - movw $bootable_ids,%di # Lookup tables - movb $(TLEN+1),%cl # Number of entries - repne # Locate - scasb # type - addw $(TLEN-1), %di # Adjust - movb (%di),%cl # Partition - addw %cx,%di # description - callw putx # Display it - -next_entry: - incw %dx # Next item - addb $0x10,%bl # Next entry - jnc read_entry # Till done</programlisting> - </figure> - - <para>It is important to note that the active flag for each entry - is cleared, so after the scanning, <emphasis>no</emphasis> - partition entry is active in our memory copy of - <filename>boot0</filename>. Later, the active flag will be set - for the selected partition. This ensures that only one active - partition exists if the user chooses to write the changes back - to disk.</para> - - <para>The next block tests for other drives. At startup, - the <acronym>BIOS</acronym> writes the number of drives present - in the computer to address <literal>0x475</literal>. If there - are any other drives present, <filename>boot0</filename> prints - the current drive to screen. The user may command - <filename>boot0</filename> to scan partitions on another drive - later.</para> - - <figure xml:id="boot-boot0-test-drives"> - <title><filename>sys/boot/i386/boot0/boot0.S</filename></title> - - <programlisting> popw %ax # Drive number - subb $0x79,%al # Does next - cmpb 0x475,%al # drive exist? (from BIOS?) - jb print_drive # Yes - decw %ax # Already drive 0? - jz print_prompt # Yes</programlisting> - </figure> - - <para>We make the assumption that a single drive is present, so - the jump to <literal>print_drive</literal> is not performed. We - also assume nothing strange happened, so we jump to - <literal>print_prompt</literal>.</para> - - <para>This next block just prints out a prompt followed by the - default option:</para> - - <figure xml:id="boot-boot0-prompt"> - <title><filename>sys/boot/i386/boot0/boot0.S</filename></title> - - <programlisting>print_prompt: - movw $prompt,%si # Display - callw putstr # prompt - movb _OPT(%bp),%dl # Display - decw %si # default - callw putkey # key - jmp start_input # Skip beep</programlisting> - </figure> - - <para>Finally, a jump is performed to - <literal>start_input</literal>, where the - <acronym>BIOS</acronym> services are used to start a timer and - for reading user input from the keyboard; if the timer expires, - the default option will be selected:</para> - - <figure xml:id="boot-boot0-start-input"> - <title><filename>sys/boot/i386/boot0/boot0.S</filename></title> - - <programlisting>start_input: - xorb %ah,%ah # BIOS: Get - int $0x1a # system time - movw %dx,%di # Ticks when - addw _TICKS(%bp),%di # timeout -read_key: - movb $0x1,%ah # BIOS: Check - int $0x16 # for keypress - jnz got_key # Have input - xorb %ah,%ah # BIOS: int 0x1a, 00 - int $0x1a # get system time - cmpw %di,%dx # Timeout? - jb read_key # No</programlisting> - </figure> - - <para>An interrupt is requested with number - <literal>0x1a</literal> and argument <literal>0</literal> in - register <literal>%ah</literal>. The <acronym>BIOS</acronym> - has a predefined set of services, requested by applications as - software-generated interrupts through the <literal>int</literal> - instruction and receiving arguments in registers (in this case, - <literal>%ah</literal>). Here, particularly, we are requesting - the number of clock ticks since last midnight; this value is - computed by the <acronym>BIOS</acronym> through the - <acronym>RTC</acronym> (Real Time Clock). This clock can be - programmed to work at frequencies ranging from 2 Hz to - 8192 Hz. The <acronym>BIOS</acronym> sets it to - 18.2 Hz at startup. When the request is satisfied, a - 32-bit result is returned by the <acronym>BIOS</acronym> in - registers <literal>%cx</literal> and <literal>%dx</literal> - (lower bytes in <literal>%dx</literal>). This result (the - <literal>%dx</literal> part) is copied to register - <literal>%di</literal>, and the value of the - <varname>TICKS</varname> variable is added to - <literal>%di</literal>. This variable resides in - <filename>boot0</filename> at offset <literal>_TICKS</literal> - (a negative value) from register <literal>%bp</literal> (which, - recall, points to <literal>0x800</literal>). The default value - of this variable is <literal>0xb6</literal> (182 in decimal). - Now, the idea is that <filename>boot0</filename> constantly - requests the time from the <acronym>BIOS</acronym>, and when the - value returned in register <literal>%dx</literal> is greater - than the value stored in <literal>%di</literal>, the time is up - and the default selection will be made. Since the RTC ticks - 18.2 times per second, this condition will be met after 10 - seconds (this default behavior can be changed in the - <filename>Makefile</filename>). Until this time has passed, - <filename>boot0</filename> continually asks the - <acronym>BIOS</acronym> for any user input; this is done through - <literal>int 0x16</literal>, argument <literal>1</literal> in - <literal>%ah</literal>.</para> - - <para>Whether a key was pressed or the time expired, subsequent - code validates the selection. Based on the selection, the - register <literal>%si</literal> is set to point to the - appropriate partition entry in the partition table. This new - selection overrides the previous default one. Indeed, it - becomes the new default. Finally, the ACTIVE flag of the - selected partition is set. If it was enabled at compile time, - the in-memory version of <filename>boot0</filename> with these - modified values is written back to the <acronym>MBR</acronym> on - disk. We leave the details of this implementation to the - reader.</para> - - <para>We now end our study with the last code block from the - <filename>boot0</filename> program:</para> - - <figure xml:id="boot-boot0-check-bootable"> - <title><filename>sys/boot/i386/boot0/boot0.S</filename></title> - - <programlisting> movw $0x7c00,%bx # Address for read - movb $0x2,%ah # Read sector - callw intx13 # from disk - jc beep # If error - cmpw $0xaa55,0x1fe(%bx) # Bootable? - jne beep # No - pushw %si # Save ptr to selected part. - callw putn # Leave some space - popw %si # Restore, next stage uses it - jmp *%bx # Invoke bootstrap</programlisting> - </figure> - - <para>Recall that <literal>%si</literal> points to the selected - partition entry. This entry tells us where the partition begins - on disk. We assume, of course, that the partition selected is - actually a &os; slice.</para> - - <note> - <para>From now on, we will favor the use of the technically - more accurate term <quote>slice</quote> rather than - <quote>partition</quote>.</para> - </note> - - <para>The transfer buffer is set to <literal>0x7c00</literal> - (register <literal>%bx</literal>), and a read for the first - sector of the &os; slice is requested by calling - <literal>intx13</literal>. We assume that everything went okay, - so a jump to <literal>beep</literal> is not performed. In - particular, the new sector read must end with the magic sequence - <literal>0xaa55</literal>. Finally, the value at - <literal>%si</literal> (the pointer to the selected partition - table) is preserved for use by the next stage, and a jump is - performed to address <literal>0x7c00</literal>, where execution - of our next stage (the just-read block) is started.</para> - </sect1> - - <sect1 xml:id="boot-boot1"> - <title><literal>boot1</literal> Stage</title> - - <para>So far we have gone through the following sequence:</para> - - <itemizedlist> - <listitem> - <para>The <acronym>BIOS</acronym> did some early hardware - initialization, including the <acronym>POST</acronym>. The - <acronym>MBR</acronym> (<filename>boot0</filename>) was - loaded from absolute disk sector one to address - <literal>0x7c00</literal>. Execution control was passed to - that location.</para> - </listitem> - - <listitem> - <para><filename>boot0</filename> relocated itself to the - location it was linked to execute - (<literal>0x600</literal>), followed by a jump to continue - execution at the appropriate place. Finally, - <filename>boot0</filename> loaded the first disk sector from - the &os; slice to address <literal>0x7c00</literal>. - Execution control was passed to that location.</para> - </listitem> - </itemizedlist> - - <para><filename>boot1</filename> is the next step in the - boot-loading sequence. It is the first of three boot stages. - Note that we have been dealing exclusively - with disk sectors. Indeed, the <acronym>BIOS</acronym> loads - the absolute first sector, while <filename>boot0</filename> - loads the first sector of the &os; slice. Both loads are to - address <literal>0x7c00</literal>. We can conceptually think of - these disk sectors as containing the files - <filename>boot0</filename> and <filename>boot1</filename>, - respectively, but in reality this is not entirely true for - <filename>boot1</filename>. Strictly speaking, unlike - <filename>boot0</filename>, <filename>boot1</filename> is not - part of the boot blocks - <footnote> - <para>There is a file <filename>/boot/boot1</filename>, but it - is not the written to the beginning of the &os; slice. - Instead, it is concatenated with <filename>boot2</filename> - to form <filename>boot</filename>, which - <emphasis>is</emphasis> written to the beginning of the &os; - slice and read at boot time.</para></footnote>. - Instead, a single, full-blown file, <filename>boot</filename> - (<filename>/boot/boot</filename>), is what ultimately is - written to disk. This file is a combination of - <filename>boot1</filename>, <filename>boot2</filename> and the - <literal>Boot Extender</literal> (or <acronym>BTX</acronym>). - This single file is greater in size than a single sector - (greater than 512 bytes). Fortunately, - <filename>boot1</filename> occupies <emphasis>exactly</emphasis> - the first 512 bytes of this single file, so when - <filename>boot0</filename> loads the first sector of the &os; - slice (512 bytes), it is actually loading - <filename>boot1</filename> and transferring control to - it.</para> - - <para>The main task of <filename>boot1</filename> is to load the - next boot stage. This next stage is somewhat more complex. It - is composed of a server called the <quote>Boot Extender</quote>, - or <acronym>BTX</acronym>, and a client, called - <filename>boot2</filename>. As we will see, the last boot - stage, <filename>loader</filename>, is also a client of the - <acronym>BTX</acronym> server.</para> - - <para>Let us now look in detail at what exactly is done by - <filename>boot1</filename>, starting like we did for - <filename>boot0</filename>, at its entry point:</para> - - <figure xml:id="boot-boot1-entry"> - <title><filename>sys/boot/i386/boot2/boot1.S</filename></title> - - <programlisting>start: - jmp main</programlisting> - </figure> - - <para>The entry point at <literal>start</literal> simply jumps - past a special data area to the label <literal>main</literal>, - which in turn looks like this:</para> - - <figure xml:id="boot-boot1-main"> - <title><filename>sys/boot/i386/boot2/boot1.S</filename></title> - - <programlisting>main: - cld # String ops inc - xor %cx,%cx # Zero - mov %cx,%es # Address - mov %cx,%ds # data - mov %cx,%ss # Set up - mov $start,%sp # stack - mov %sp,%si # Source - mov $0x700,%di # Destination - incb %ch # Word count - rep # Copy - movsw # code</programlisting> - </figure> - - <para>Just like <filename>boot0</filename>, this - code relocates <filename>boot1</filename>, - this time to memory address <literal>0x700</literal>. However, - unlike <filename>boot0</filename>, it does not jump there. - <filename>boot1</filename> is linked to execute at - address <literal>0x7c00</literal>, effectively where it was - loaded in the first place. The reason for this relocation will - be discussed shortly.</para> - - <para>Next comes a loop that looks for the &os; slice. Although - <filename>boot0</filename> loaded <filename>boot1</filename> - from the &os; slice, no information was passed to it about this - <footnote> - <para>Actually we did pass a pointer to the slice entry in - register <literal>%si</literal>. However, - <filename>boot1</filename> does not assume that it was - loaded by <filename>boot0</filename> (perhaps some other - <acronym>MBR</acronym> loaded it, and did not pass this - information), so it assumes nothing.</para></footnote>, - so <filename>boot1</filename> must rescan the - partition table to find where the &os; slice starts. Therefore - it rereads the <acronym>MBR</acronym>:</para> - - <figure xml:id="boot-boot1-find-freebsd"> - <title><filename>sys/boot/i386/boot2/boot1.S</filename></title> - - <programlisting> mov $part4,%si # Partition - cmpb $0x80,%dl # Hard drive? - jb main.4 # No - movb $0x1,%dh # Block count - callw nread # Read MBR</programlisting> - </figure> - - <para>In the code above, register <literal>%dl</literal> - maintains information about the boot device. This is passed on - by the <acronym>BIOS</acronym> and preserved by the - <acronym>MBR</acronym>. Numbers <literal>0x80</literal> and - greater tells us that we are dealing with a hard drive, so a - call is made to <literal>nread</literal>, where the - <acronym>MBR</acronym> is read. Arguments to - <literal>nread</literal> are passed through - <literal>%si</literal> and <literal>%dh</literal>. The memory - address at label <literal>part4</literal> is copied to - <literal>%si</literal>. This memory address holds a - <quote>fake partition</quote> to be used by - <literal>nread</literal>. The following is the data in the fake - partition:</para> - - <figure xml:id="boot-boot2-make-fake-partition"> - <title><filename>sys/boot/i386/boot2/Makefile</filename></title> - - <programlisting> part4: - .byte 0x80, 0x00, 0x01, 0x00 - .byte 0xa5, 0xfe, 0xff, 0xff - .byte 0x00, 0x00, 0x00, 0x00 - .byte 0x50, 0xc3, 0x00, 0x00</programlisting> - </figure> - - <para>In particular, the <acronym>LBA</acronym> for this fake - partition is hardcoded to zero. This is used as an argument to - the <acronym>BIOS</acronym> for reading absolute sector one from - the hard drive. Alternatively, CHS addressing could be used. - In this case, the fake partition holds cylinder 0, head 0 and - sector 1, which is equivalent to absolute sector one.</para> - - <para>Let us now proceed to take a look at - <literal>nread</literal>:</para> - - <figure xml:id="boot-boot1-nread"> - <title><filename>sys/boot/i386/boot2/boot1.S</filename></title> - - <programlisting>nread: - mov $0x8c00,%bx # Transfer buffer - mov 0x8(%si),%ax # Get - mov 0xa(%si),%cx # LBA - push %cs # Read from - callw xread.1 # disk - jnc return # If success, return</programlisting> - </figure> - - <para>Recall that <literal>%si</literal> points to the fake - partition. The word - <footnote> - <para>In the context of 16-bit real mode, a word is 2 - bytes.</para></footnote> - at offset <literal>0x8</literal> is copied to register - <literal>%ax</literal> and word at offset <literal>0xa</literal> - to <literal>%cx</literal>. They are interpreted by the - <acronym>BIOS</acronym> as the lower 4-byte value denoting the - LBA to be read (the upper four bytes are assumed to be zero). - Register <literal>%bx</literal> holds the memory address where - the <acronym>MBR</acronym> will be loaded. The instruction - pushing <literal>%cs</literal> onto the stack is very - interesting. In this context, it accomplishes nothing. - However, as we will see shortly, <filename>boot2</filename>, in - conjunction with the <acronym>BTX</acronym> server, also uses - <literal>xread.1</literal>. This mechanism will be discussed in - the next section.</para> - - <para>The code at <literal>xread.1</literal> further calls - the <literal>read</literal> function, which actually calls the - <acronym>BIOS</acronym> asking for the disk sector:</para> - - <figure xml:id="boot-boot1-xread1"> - <title><filename>sys/boot/i386/boot2/boot1.S</filename></title> - - <programlisting>xread.1: - pushl $0x0 # absolute - push %cx # block - push %ax # number - push %es # Address of - push %bx # transfer buffer - xor %ax,%ax # Number of - movb %dh,%al # blocks to - push %ax # transfer - push $0x10 # Size of packet - mov %sp,%bp # Packet pointer - callw read # Read from disk - lea 0x10(%bp),%sp # Clear stack - lret # To far caller</programlisting> - </figure> - - <para>Note the long return instruction at the end of this block. - This instruction pops out the <literal>%cs</literal> register - pushed by <literal>nread</literal>, and returns. Finally, - <literal>nread</literal> also returns.</para> - - <para>With the <acronym>MBR</acronym> loaded to memory, the actual - loop for searching the &os; slice begins:</para> - - <figure xml:id="boot-boot1-find-part"> - <title><filename>sys/boot/i386/boot2/boot1.S</filename></title> - - <programlisting> mov $0x1,%cx # Two passes -main.1: - mov $0x8dbe,%si # Partition table - movb $0x1,%dh # Partition -main.2: - cmpb $0xa5,0x4(%si) # Our partition type? - jne main.3 # No - jcxz main.5 # If second pass - testb $0x80,(%si) # Active? - jnz main.5 # Yes -main.3: - add $0x10,%si # Next entry - incb %dh # Partition - cmpb $0x5,%dh # In table? - jb main.2 # Yes - dec %cx # Do two - jcxz main.1 # passes</programlisting> - </figure> - - <para>If a &os; slice is identified, execution continues at - <literal>main.5</literal>. Note that when a &os; slice is found - <literal>%si</literal> points to the appropriate entry in the - partition table, and <literal>%dh</literal> holds the partition - number. We assume that a &os; slice is found, so we continue - execution at <literal>main.5</literal>:</para> - - <figure xml:id="boot-boot1-main5"> - <title><filename>sys/boot/i386/boot2/boot1.S</filename></title> - - <programlisting>main.5: - mov %dx,0x900 # Save args - movb $0x10,%dh # Sector count - callw nread # Read disk - mov $0x9000,%bx # BTX - mov 0xa(%bx),%si # Get BTX length and set - add %bx,%si # %si to start of boot2.bin - mov $0xc000,%di # Client page 2 - mov $0xa200,%cx # Byte - sub %si,%cx # count - rep # Relocate - movsb # client</programlisting> - </figure> - - <para>Recall that at this point, register <literal>%si</literal> - points to the &os; slice entry in the <acronym>MBR</acronym> - partition table, so a call to <literal>nread</literal> will - effectively read sectors at the beginning of this partition. - The argument passed on register <literal>%dh</literal> tells - <literal>nread</literal> to read 16 disk sectors. Recall that - the first 512 bytes, or the first sector of the &os; slice, - coincides with the <filename>boot1</filename> program. Also - recall that the file written to the beginning of the &os; - slice is not <filename>/boot/boot1</filename>, but - <filename>/boot/boot</filename>. Let us look at the size of - these files in the filesystem:</para> - - <screen xml:id="boot-boot1-filesize">-r--r--r-- 1 root wheel 512B Jan 8 00:15 /boot/boot0 --r--r--r-- 1 root wheel 512B Jan 8 00:15 /boot/boot1 --r--r--r-- 1 root wheel 7.5K Jan 8 00:15 /boot/boot2 --r--r--r-- 1 root wheel 8.0K Jan 8 00:15 /boot/boot</screen> - - <para>Both <filename>boot0</filename> and - <filename>boot1</filename> are 512 bytes each, so they fit - <emphasis>exactly</emphasis> in one disk sector. - <filename>boot2</filename> is much bigger, holding both - the <acronym>BTX</acronym> server and the - <filename>boot2</filename> client. Finally, a file called - simply <filename>boot</filename> is 512 bytes larger than - <filename>boot2</filename>. This file is a - concatenation of <filename>boot1</filename> and - <filename>boot2</filename>. As already noted, - <filename>boot0</filename> is the file written to the absolute - first disk sector (the <acronym>MBR</acronym>), and - <filename>boot</filename> is the file written to the first - sector of the &os; slice; <filename>boot1</filename> and - <filename>boot2</filename> are <emphasis>not</emphasis> written - to disk. The command used to concatenate - <filename>boot1</filename> and <filename>boot2</filename> into a - single <filename>boot</filename> is merely - <command>cat boot1 boot2 > boot</command>.</para> - - <para>So <filename>boot1</filename> occupies exactly the first 512 - bytes of <filename>boot</filename> and, because - <filename>boot</filename> is written to the first sector of the - &os; slice, <filename>boot1</filename> fits exactly in this - first sector. When <literal>nread</literal> reads the first - 16 sectors of the &os; slice, it effectively reads the entire - <filename>boot</filename> file - <footnote> - <para>512*16=8192 bytes, exactly the size of - <filename>boot</filename></para></footnote>. - We will see more details about how <filename>boot</filename> is - formed from <filename>boot1</filename> and - <filename>boot2</filename> in the next section.</para> - - <para>Recall that <literal>nread</literal> uses memory address - <literal>0x8c00</literal> as the transfer buffer to hold the - sectors read. This address is conveniently chosen. Indeed, - because <filename>boot1</filename> belongs to the first 512 - bytes, it ends up in the address range - <literal>0x8c00</literal>-<literal>0x8dff</literal>. The 512 - bytes that follows (range - <literal>0x8e00</literal>-<literal>0x8fff</literal>) is used to - store the <emphasis>bsdlabel</emphasis> - <footnote> - <para>Historically known as <quote>disklabel</quote>. If you - ever wondered where &os; stored this information, it is in - this region. See &man.bsdlabel.8;</para></footnote>.</para> - - <para>Starting at address <literal>0x9000</literal> is the - beginning of the <acronym>BTX</acronym> server, and immediately - following is the <filename>boot2</filename> client. The - <acronym>BTX</acronym> server acts as a kernel, and executes in - protected mode in the most privileged level. In contrast, the - <acronym>BTX</acronym> clients (<filename>boot2</filename>, for - example), execute in user mode. We will see how this is - accomplished in the next section. The code after the call to - <literal>nread</literal> locates the beginning of - <filename>boot2</filename> in the memory buffer, and copies it - to memory address <literal>0xc000</literal>. This is because - the <acronym>BTX</acronym> server arranges - <filename>boot2</filename> to execute in a segment starting at - <literal>0xa000</literal>. We explore this in detail in the - following section.</para> - - <para>The last code block of <filename>boot1</filename> enables - access to memory above 1MB - <footnote> - <para>This is necessary for legacy reasons. Interested - readers should see <link - xlink:href="http://en.wikipedia.org/wiki/A20_line"/>.</para></footnote> - and concludes with a jump to the starting point of the - <acronym>BTX</acronym> server:</para> - - <figure xml:id="boot-boot1-seta20"> - <title><filename>sys/boot/i386/boot2/boot1.S</filename></title> - - <programlisting>seta20: - cli # Disable interrupts -seta20.1: - dec %cx # Timeout? - jz seta20.3 # Yes - - inb $0x64,%al # Get status - testb $0x2,%al # Busy? - jnz seta20.1 # Yes - movb $0xd1,%al # Command: Write - outb %al,$0x64 # output port -seta20.2: - inb $0x64,%al # Get status - testb $0x2,%al # Busy? - jnz seta20.2 # Yes - movb $0xdf,%al # Enable - outb %al,$0x60 # A20 -seta20.3: - sti # Enable interrupts - jmp 0x9010 # Start BTX</programlisting> - </figure> - - <para>Note that right before the jump, interrupts are - enabled.</para> - </sect1> - - <sect1 xml:id="btx-server"> - <title>The <acronym>BTX</acronym> Server</title> - - <para>Next in our boot sequence is the - <acronym>BTX</acronym> Server. Let us quickly remember how we - got here:</para> - - <itemizedlist> - <listitem> - <para>The <acronym>BIOS</acronym> loads the absolute sector - one (the <acronym>MBR</acronym>, or - <filename>boot0</filename>), to address - <literal>0x7c00</literal> and jumps there.</para> - </listitem> - - <listitem> - <para><filename>boot0</filename> relocates itself to - <literal>0x600</literal>, the address it was linked to - execute, and jumps over there. It then reads the first - sector of the &os; slice (which consists of - <filename>boot1</filename>) into address - <literal>0x7c00</literal> and jumps over there.</para> - </listitem> - - <listitem> - <para><filename>boot1</filename> loads the first 16 sectors - of the &os; slice into address <literal>0x8c00</literal>. - This 16 sectors, or 8192 bytes, is the whole file - <filename>boot</filename>. The file is a - concatenation of <filename>boot1</filename> and - <filename>boot2</filename>. <filename>boot2</filename>, in - turn, contains the <acronym>BTX</acronym> server and the - <filename>boot2</filename> client. Finally, a jump is made - to address <literal>0x9010</literal>, the entry point of the - <acronym>BTX</acronym> server.</para> - </listitem> - </itemizedlist> - - <para>Before studying the <acronym>BTX</acronym> Server in detail, - let us further review how the single, all-in-one - <filename>boot</filename> file is created. The way - <filename>boot</filename> is built is defined in its - <filename>Makefile</filename> - (<filename>/usr/src/sys/boot/i386/boot2/Makefile</filename>). - Let us look at the rule that creates the - <filename>boot</filename> file:</para> - - <figure xml:id="boot-boot1-make-boot"> - <title><filename>sys/boot/i386/boot2/Makefile</filename></title> - - <programlisting> boot: boot1 boot2 - cat boot1 boot2 > boot</programlisting> - </figure> - - <para>This tells us that <filename>boot1</filename> and - <filename>boot2</filename> are needed, and the rule simply - concatenates them to produce a single file called - <filename>boot</filename>. The rules for creating - <filename>boot1</filename> are also quite simple:</para> - - <figure xml:id="boot-boot1-make-boot1"> - <title><filename>sys/boot/i386/boot2/Makefile</filename></title> - - <programlisting> boot1: boot1.out - objcopy -S -O binary boot1.out boot1 - - boot1.out: boot1.o - ld -e start -Ttext 0x7c00 -o boot1.out boot1.o</programlisting> - </figure> - - <para>To apply the rule for creating - <filename>boot1</filename>, <filename>boot1.out</filename> must - be resolved. This, in turn, depends on the existence of - <filename>boot1.o</filename>. This last file is simply the - result of assembling our familiar <filename>boot1.S</filename>, - without linking. Now, the rule for creating - <filename>boot1.out</filename> is applied. This tells us that - <filename>boot1.o</filename> should be linked with - <literal>start</literal> as its entry point, and starting at - address <literal>0x7c00</literal>. Finally, - <filename>boot1</filename> is created from - <filename>boot1.out</filename> applying the appropriate rule. - This rule is the <filename>objcopy</filename> command applied to - <filename>boot1.out</filename>. Note the flags passed to - <filename>objcopy</filename>: <literal>-S</literal> tells it to - strip all relocation and symbolic information; - <literal>-O binary</literal> indicates the output format, that - is, a simple, unformatted binary file.</para> - - <para>Having <filename>boot1</filename>, let us take a look at how - <filename>boot2</filename> is constructed:</para> - - <figure xml:id="boot-boot1-make-boot2"> - <title><filename>sys/boot/i386/boot2/Makefile</filename></title> - - <programlisting> boot2: boot2.ld - @set -- `ls -l boot2.ld`; x=$$((7680-$$5)); \ - echo "$$x bytes available"; test $$x -ge 0 - dd if=boot2.ld of=boot2 obs=7680 conv=osync - - boot2.ld: boot2.ldr boot2.bin ../btx/btx/btx - btxld -v -E 0x2000 -f bin -b ../btx/btx/btx -l boot2.ldr \ - -o boot2.ld -P 1 boot2.bin - - boot2.ldr: - dd if=/dev/zero of=boot2.ldr bs=512 count=1 - - boot2.bin: boot2.out - objcopy -S -O binary boot2.out boot2.bin - - boot2.out: ../btx/lib/crt0.o boot2.o sio.o - ld -Ttext 0x2000 -o boot2.out - - boot2.o: boot2.s - ${CC} ${ACFLAGS} -c boot2.s - - boot2.s: boot2.c boot2.h ${.CURDIR}/../../common/ufsread.c - ${CC} ${CFLAGS} -S -o boot2.s.tmp ${.CURDIR}/boot2.c - sed -e '/align/d' -e '/nop/d' "MISSING" boot2.s.tmp > boot2.s - rm -f boot2.s.tmp - - boot2.h: boot1.out - ${NM} -t d ${.ALLSRC} | awk '/([0-9])+ T xread/ \ - { x = $$1 - ORG1; \ - printf("#define XREADORG %#x\n", REL1 + x) }' \ - ORG1=`printf "%d" ${ORG1}` \ - REL1=`printf "%d" ${REL1}` > ${.TARGET}</programlisting> - </figure> - - <para>The mechanism for building <filename>boot2</filename> is - far more elaborate. Let us point out the most relevant facts. - The dependency list is as follows:</para> - - <figure xml:id="boot-boot1-make-boot2-more"> - <title><filename>sys/boot/i386/boot2/Makefile</filename></title> - - <programlisting> boot2: boot2.ld - boot2.ld: boot2.ldr boot2.bin ${BTXDIR}/btx/btx - boot2.bin: boot2.out - boot2.out: ${BTXDIR}/lib/crt0.o boot2.o sio.o - boot2.o: boot2.s - boot2.s: boot2.c boot2.h ${.CURDIR}/../../common/ufsread.c - boot2.h: boot1.out</programlisting> - </figure> - - <para>Note that initially there is no header file - <filename>boot2.h</filename>, but its creation depends on - <filename>boot1.out</filename>, which we already have. The rule - for its creation is a bit terse, but the important thing is that - the output, <filename>boot2.h</filename>, is something like - this:</para> - - <figure xml:id="boot-boot1-make-boot2h"> - <title><filename>sys/boot/i386/boot2/boot2.h</filename></title> - - <programlisting>#define XREADORG 0x725</programlisting> - </figure> - - <para>Recall that <filename>boot1</filename> was relocated (i.e., - copied from <literal>0x7c00</literal> to - <literal>0x700</literal>). This relocation will now make sense, - because as we will see, the <acronym>BTX</acronym> server - reclaims some memory, including the space where - <filename>boot1</filename> was originally loaded. However, the - <acronym>BTX</acronym> server needs access to - <filename>boot1</filename>'s <literal>xread</literal> function; - this function, according to the output of - <filename>boot2.h</filename>, is at location - <literal>0x725</literal>. Indeed, the - <acronym>BTX</acronym> server uses the - <literal>xread</literal> function from - <filename>boot1</filename>'s relocated code. This function is - now accessible from within the <filename>boot2</filename> - client.</para> - - <para>We next build <filename>boot2.s</filename> from files - <filename>boot2.h</filename>, <filename>boot2.c</filename> and - <filename>/usr/src/sys/boot/common/ufsread.c</filename>. The - rule for this is to compile the code in - <filename>boot2.c</filename> (which includes - <filename>boot2.h</filename> and <filename>ufsread.c</filename>) - into assembly code. Having <filename>boot2.s</filename>, the - next rule assembles <filename>boot2.s</filename>, creating the - object file <filename>boot2.o</filename>. The - next rule directs the linker to link various files - (<filename>crt0.o</filename>, - <filename>boot2.o</filename> and <filename>sio.o</filename>). - Note that the output file, <filename>boot2.out</filename>, is - linked to execute at address <literal>0x2000</literal>. Recall - that <filename>boot2</filename> will be executed in user mode, - within a special user segment set up by the - <acronym>BTX</acronym> server. This segment starts at - <literal>0xa000</literal>. Also, remember that the - <filename>boot2</filename> portion of <filename>boot</filename> - was copied to address <literal>0xc000</literal>, that is, offset - <literal>0x2000</literal> from the start of the user segment, so - <filename>boot2</filename> will work properly when we transfer - control to it. Next, <filename>boot2.bin</filename> is created - from <filename>boot2.out</filename> by stripping its symbols and - format information; boot2.bin is a <emphasis>raw</emphasis> - binary. Now, note that a file <filename>boot2.ldr</filename> is - created as a 512-byte file full of zeros. This space is - reserved for the bsdlabel.</para> - - <para>Now that we have files <filename>boot1</filename>, - <filename>boot2.bin</filename> and - <filename>boot2.ldr</filename>, only the - <acronym>BTX</acronym> server is missing before creating the - all-in-one <filename>boot</filename> file. The - <acronym>BTX</acronym> server is located in - <filename>/usr/src/sys/boot/i386/btx/btx</filename>; it has its - own <filename>Makefile</filename> with its own set of rules for - building. The important thing to notice is that it is also - compiled as a <emphasis>raw</emphasis> binary, and that it is - linked to execute at address <literal>0x9000</literal>. The - details can be found in - <filename>/usr/src/sys/boot/i386/btx/btx/Makefile</filename>.</para> - - <para>Having the files that comprise the <filename>boot</filename> - program, the final step is to <emphasis>merge</emphasis> them. - This is done by a special program called - <filename>btxld</filename> (source located in - <filename>/usr/src/usr.sbin/btxld</filename>). Some arguments - to this program include the name of the output file - (<filename>boot</filename>), its entry point - (<literal>0x2000</literal>) and its file format - (raw binary). The various files are - finally merged by this utility into the file - <filename>boot</filename>, which consists of - <filename>boot1</filename>, <filename>boot2</filename>, the - <literal>bsdlabel</literal> and the - <acronym>BTX</acronym> server. This file, which takes - exactly 16 sectors, or 8192 bytes, is what is - actually written to the beginning of the &os; slice - during installation. Let us now proceed to study the - <acronym>BTX</acronym> server program.</para> - - <para>The <acronym>BTX</acronym> server prepares a simple - environment and switches from 16-bit real mode to 32-bit - protected mode, right before passing control to the client. - This includes initializing and updating the following data - structures:</para> - - <indexterm><primary>virtual v86 mode</primary></indexterm> - <itemizedlist> - <listitem> - <para>Modifies the - <literal>Interrupt Vector Table (IVT)</literal>. The - <acronym>IVT</acronym> provides exception and interrupt - handlers for Real-Mode code.</para> - </listitem> - - <listitem> - <para>The <literal>Interrupt Descriptor Table (IDT)</literal> - is created. Entries are provided for processor exceptions, - hardware interrupts, two system calls and V86 interface. - The IDT provides exception and interrupt handlers for - Protected-Mode code.</para> - </listitem> - - <listitem> - <para>A <literal>Task-State Segment (TSS)</literal> is - created. This is necessary because the processor works in - the <emphasis>least</emphasis> privileged level when - executing the client (<filename>boot2</filename>), but in - the <emphasis>most</emphasis> privileged level when - executing the <acronym>BTX</acronym> server.</para> - </listitem> - - <listitem> - <para>The <acronym>GDT</acronym> (Global Descriptor Table) is - set up. Entries (descriptors) are provided for - supervisor code and data, user code and data, and real-mode - code and data. - <footnote> - <para>Real-mode code and data are necessary when switching - back to real mode from protected mode, as suggested by - the Intel manuals.</para></footnote></para> - </listitem> - </itemizedlist> - - <para>Let us now start studying the actual implementation. Recall - that <filename>boot1</filename> made a jump to address - <literal>0x9010</literal>, the <acronym>BTX</acronym> server's - entry point. Before studying program execution there, - note that the <acronym>BTX</acronym> server has a special header - at address range <literal>0x9000-0x900f</literal>, right before - its entry point. This header is defined as follows:</para> - - <figure xml:id="btx-header"> - <title><filename>sys/boot/i386/btx/btx/btx.S</filename></title> - - <programlisting>start: # Start of code -/* - * BTX header. - */ -btx_hdr: .byte 0xeb # Machine ID - .byte 0xe # Header size - .ascii "BTX" # Magic - .byte 0x1 # Major version - .byte 0x2 # Minor version - .byte BTX_FLAGS # Flags - .word PAG_CNT-MEM_ORG>>0xc # Paging control - .word break-start # Text size - .long 0x0 # Entry address</programlisting> - </figure> - - <para>Note the first two bytes are <literal>0xeb</literal> and - <literal>0xe</literal>. In the IA-32 architecture, these two - bytes are interpreted as a relative jump past the header into - the entry point, so in theory, <filename>boot1</filename> could - jump here (address <literal>0x9000</literal>) instead of address - <literal>0x9010</literal>. Note that the last field in the - <acronym>BTX</acronym> header is a pointer to the client's - (<filename>boot2</filename>) entry point. This field is patched - at link time.</para> - - <para>Immediately following the header is the - <acronym>BTX</acronym> server's entry point:</para> - - <figure xml:id="btx-init"> - <title><filename>sys/boot/i386/btx/btx/btx.S</filename></title> - - <programlisting>/* - * Initialization routine. - */ -init: cli # Disable interrupts - xor %ax,%ax # Zero/segment - mov %ax,%ss # Set up - mov $0x1800,%sp # stack - mov %ax,%es # Address - mov %ax,%ds # data - pushl $0x2 # Clear - popfl # flags</programlisting> - </figure> - - <para>This code disables interrupts, sets up a working stack - (starting at address <literal>0x1800</literal>) and clears the - flags in the EFLAGS register. Note that the - <literal>popfl</literal> instruction pops out a doubleword (4 - bytes) from the stack and places it in the EFLAGS register. - As the value actually popped is <literal>2</literal>, the - EFLAGS register is effectively cleared (IA-32 requires that bit - 2 of the EFLAGS register always be 1).</para> - - <para>Our next code block clears (sets to <literal>0</literal>) - the memory range <literal>0x5e00-0x8fff</literal>. This range - is where the various data structures will be created:</para> - - <figure xml:id="btx-clear-mem"> - <title><filename>sys/boot/i386/btx/btx/btx.S</filename></title> - - <programlisting>/* - * Initialize memory. - */ - mov $0x5e00,%di # Memory to initialize - mov $(0x9000-0x5e00)/2,%cx # Words to zero - rep # Zero-fill - stosw # memory</programlisting> - </figure> - - <para>Recall that <filename>boot1</filename> was originally loaded - to address <literal>0x7c00</literal>, so, with this memory - initialization, that copy effectively disappeared. However, - also recall that <filename>boot1</filename> was relocated to - <literal>0x700</literal>, so <emphasis>that</emphasis> copy is - still in memory, and the <acronym>BTX</acronym> server will make - use of it.</para> - - <para>Next, the real-mode <acronym>IVT</acronym> (Interrupt Vector - Table is updated. The <acronym>IVT</acronym> is an array of - segment/offset pairs for exception and interrupt handlers. The - <acronym>BIOS</acronym> normally maps hardware interrupts to - interrupt vectors <literal>0x8</literal> to - <literal>0xf</literal> and <literal>0x70</literal> to - <literal>0x77</literal> but, as will be seen, the 8259A - Programmable Interrupt Controller, the chip controlling the - actual mapping of hardware interrupts to interrupt vectors, is - programmed to remap these interrupt vectors from - <literal>0x8-0xf</literal> to <literal>0x20-0x27</literal> and - from <literal>0x70-0x77</literal> to - <literal>0x28-0x2f</literal>. Thus, interrupt handlers are - provided for interrupt vectors <literal>0x20-0x2f</literal>. - The reason the <acronym>BIOS</acronym>-provided handlers are not - used directly is because they work in 16-bit real mode, but not - 32-bit protected mode. Processor mode will be switched to - 32-bit protected mode shortly. However, the - <acronym>BTX</acronym> server sets up a mechanism to effectively - use the handlers provided by the <acronym>BIOS</acronym>:</para> - - <figure xml:id="btx-ivt"> - <title><filename>sys/boot/i386/btx/btx/btx.S</filename></title> - - <programlisting>/* - * Update real mode IDT for reflecting hardware interrupts. - */ - mov $intr20,%bx # Address first handler - mov $0x10,%cx # Number of handlers - mov $0x20*4,%di # First real mode IDT entry -init.0: mov %bx,(%di) # Store IP - inc %di # Address next - inc %di # entry - stosw # Store CS - add $4,%bx # Next handler - loop init.0 # Next IRQ</programlisting> - </figure> - - <para>The next block creates the <acronym>IDT</acronym> (Interrupt - Descriptor Table). The <acronym>IDT</acronym> is analogous, in - protected mode, to the <acronym>IVT</acronym> in real mode. - That is, the <acronym>IDT</acronym> describes the various - exception and interrupt handlers used when the processor is - executing in protected mode. In essence, it also consists of an - array of segment/offset pairs, although the structure is - somewhat more complex, because segments in protected mode are - different than in real mode, and various protection mechanisms - apply:</para> - - <figure xml:id="btx-idt"> - <title><filename>sys/boot/i386/btx/btx/btx.S</filename></title> - - <programlisting>/* - * Create IDT. - */ - mov $0x5e00,%di # IDT's address - mov $idtctl,%si # Control string -init.1: lodsb # Get entry - cbw # count - xchg %ax,%cx # as word - jcxz init.4 # If done - lodsb # Get segment - xchg %ax,%dx # P:DPL:type - lodsw # Get control - xchg %ax,%bx # set - lodsw # Get handler offset - 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 handler -init.3: lea 0x8(%di),%di # Next entry - loop init.2 # Till set done - jmp init.1 # Continue</programlisting> - </figure> - - <para>Each entry in the <literal>IDT</literal> is 8 bytes long. - Besides the segment/offset information, they also describe the - segment type, privilege level, and whether the segment is - present in memory or not. The construction is such that - interrupt vectors from <literal>0</literal> to - <literal>0xf</literal> (exceptions) are handled by function - <literal>intx00</literal>; vector <literal>0x10</literal> (also - an exception) is handled by <literal>intx10</literal>; hardware - interrupts, which are later configured to start at interrupt - vector <literal>0x20</literal> all the way to interrupt vector - <literal>0x2f</literal>, are handled by function - <literal>intx20</literal>. Lastly, interrupt vector - <literal>0x30</literal>, which is used for system calls, is - handled by <literal>intx30</literal>, and vectors - <literal>0x31</literal> and <literal>0x32</literal> are handled - by <literal>intx31</literal>. It must be noted that only - descriptors for interrupt vectors <literal>0x30</literal>, - <literal>0x31</literal> and <literal>0x32</literal> are given - privilege level 3, the same privilege level as the - <filename>boot2</filename> client, which means the client can - execute a software-generated interrupt to this vectors through - the <literal>int</literal> instruction without failing (this is - the way <filename>boot2</filename> use the services provided by - the <acronym>BTX</acronym> server). Also, note that - <emphasis>only</emphasis> software-generated interrupts are - protected from code executing in lesser privilege levels. - Hardware-generated interrupts and processor-generated exceptions - are <emphasis>always</emphasis> handled adequately, regardless - of the actual privileges involved.</para> - - <para>The next step is to initialize the <acronym>TSS</acronym> - (Task-State Segment). The <acronym>TSS</acronym> is a hardware - feature that helps the operating system or executive software - implement multitasking functionality through process - abstraction. The IA-32 architecture demands the creation and - use of <emphasis>at least</emphasis> one <acronym>TSS</acronym> - if multitasking facilities are used or different privilege - levels are defined. Since the <filename>boot2</filename> - client is executed in privilege level 3, but the - <acronym>BTX</acronym> server runs in privilege level 0, a - <acronym>TSS</acronym> must be defined:</para> - - <figure xml:id="btx-tss"> - <title><filename>sys/boot/i386/btx/btx/btx.S</filename></title> - - <programlisting>/* - * Initialize TSS. - */ -init.4: movb $_ESP0H,TSS_ESP0+1(%di) # Set ESP0 - movb $SEL_SDATA,TSS_SS0(%di) # Set SS0 - movb $_TSSIO,TSS_MAP(%di) # Set I/O bit map base</programlisting> - </figure> - - <para>Note that a value is given for the Privilege Level 0 stack - pointer and stack segment in the <acronym>TSS</acronym>. This - is needed because, if an interrupt or exception is received - while executing <filename>boot2</filename> in Privilege Level 3, - a change to Privilege Level 0 is automatically performed by the - processor, so a new working stack is needed. Finally, the I/O - Map Base Address field of the <acronym>TSS</acronym> is given a - value, which is a 16-bit offset from the beginning of the - <acronym>TSS</acronym> to the I/O Permission Bitmap and the - Interrupt Redirection Bitmap.</para> - - <para>After the <acronym>IDT</acronym> and <acronym>TSS</acronym> - are created, the processor is ready to switch to protected mode. - This is done in the next block:</para> - - <figure xml:id="btx-prot"> - <title><filename>sys/boot/i386/btx/btx/btx.S</filename></title> - - <programlisting>/* - * Bring up the system. - */ - mov $0x2820,%bx # Set protected mode - callw setpic # IRQ offsets - lidt idtdesc # Set IDT - lgdt gdtdesc # Set GDT - mov %cr0,%eax # Switch to protected - inc %ax # mode - mov %eax,%cr0 # - ljmp $SEL_SCODE,$init.8 # To 32-bit code - .code32 -init.8: xorl %ecx,%ecx # Zero - movb $SEL_SDATA,%cl # To 32-bit - movw %cx,%ss # stack</programlisting> - </figure> - - <para>First, a call is made to <literal>setpic</literal> to - program the 8259A <acronym>PIC</acronym> (Programmable Interrupt - Controller). This chip is connected to multiple hardware - interrupt sources. Upon receiving an interrupt from a device, - it signals the processor with the appropriate interrupt vector. - This can be customized so that specific interrupts are - associated with specific interrupt vectors, as explained before. - Next, the <acronym>IDTR</acronym> (Interrupt Descriptor Table - Register) and <acronym>GDTR</acronym> (Global Descriptor Table - Register) are loaded with the instructions - <literal>lidt</literal> and <literal>lgdt</literal>, - respectively. These registers are loaded with the base address - and limit address for the <acronym>IDT</acronym> and - <acronym>GDT</acronym>. The following three instructions set - the Protection Enable (PE) bit of the <literal>%cr0</literal> - register. This effectively switches the processor to 32-bit - protected mode. Next, a long jump is made to - <literal>init.8</literal> using segment selector SEL_SCODE, - which selects the Supervisor Code Segment. The processor is - effectively executing in CPL 0, the most privileged level, after - this jump. Finally, the Supervisor Data Segment is selected for - the stack by assigning the segment selector SEL_SDATA to the - <literal>%ss</literal> register. This data segment also has a - privilege level of <literal>0</literal>.</para> - - <para>Our last code block is responsible for loading the - <acronym>TR</acronym> (Task Register) with the segment selector - for the <acronym>TSS</acronym> we created earlier, and setting - the User Mode environment before passing execution control to - the <filename>boot2</filename> client.</para> - - <figure xml:id="btx-end"> - <title><filename>sys/boot/i386/btx/btx/btx.S</filename></title> - - <programlisting>/* - * Launch user task. - */ - movb $SEL_TSS,%cl # Set task - ltr %cx # register - movl $0xa000,%edx # User base address - movzwl %ss:BDA_MEM,%eax # Get free memory - shll $0xa,%eax # To bytes - subl $ARGSPACE,%eax # Less arg space - subl %edx,%eax # Less base - movb $SEL_UDATA,%cl # User data selector - pushl %ecx # Set SS - pushl %eax # Set ESP - push $0x202 # Set flags (IF set) - push $SEL_UCODE # Set CS - pushl btx_hdr+0xc # Set EIP - pushl %ecx # Set GS - pushl %ecx # Set FS - pushl %ecx # Set DS - pushl %ecx # Set ES - pushl %edx # Set EAX - movb $0x7,%cl # Set remaining -init.9: push $0x0 # general - loop init.9 # registers - popa # and initialize - popl %es # Initialize - popl %ds # user - popl %fs # segment - popl %gs # registers - iret # To user mode</programlisting> - </figure> - - <para>Note that the client's environment include a stack segment - selector and stack pointer (registers <literal>%ss</literal> and - <literal>%esp</literal>). Indeed, once the - <acronym>TR</acronym> is loaded with the appropriate stack - segment selector (instruction <literal>ltr</literal>), the stack - pointer is calculated and pushed onto the stack along with the - stack's segment selector. Next, the value - <literal>0x202</literal> is pushed onto the stack; it is the - value that the EFLAGS will get when control is passed to the - client. Also, the User Mode code segment selector and the - client's entry point are pushed. Recall that this entry - point is patched in the <acronym>BTX</acronym> header at link - time. Finally, segment selectors (stored in register - <literal>%ecx</literal>) for the segment registers - <literal>%gs, %fs, %ds and %es</literal> are pushed onto the - stack, along with the value at <literal>%edx</literal> - (<literal>0xa000</literal>). Keep in mind the various values - that have been pushed onto the stack (they will be popped out - shortly). Next, values for the remaining general purpose - registers are also pushed onto the stack (note the - <literal>loop</literal> that pushes the value - <literal>0</literal> seven times). Now, values will be started - to be popped out of the stack. First, the - <literal>popa</literal> instruction pops out of the stack the - latest seven values pushed. They are stored in the general - purpose registers in order - <literal>%edi, %esi, %ebp, %ebx, %edx, %ecx, %eax</literal>. - Then, the various segment selectors pushed are popped into the - various segment registers. Five values still remain on the - stack. They are popped when the <literal>iret</literal> - instruction is executed. This instruction first pops - the value that was pushed from the <acronym>BTX</acronym> - header. This value is a pointer to <filename>boot2</filename>'s - entry point. It is placed in the register - <literal>%eip</literal>, the instruction pointer register. - Next, the segment selector for the User Code Segment is popped - and copied to register <literal>%cs</literal>. Remember that - this segment's privilege level is 3, the least privileged - level. This means that we must provide values for the stack of - this privilege level. This is why the processor, besides - further popping the value for the EFLAGS register, does two more - pops out of the stack. These values go to the stack - pointer (<literal>%esp</literal>) and the stack segment - (<literal>%ss</literal>). Now, execution continues at - <literal>boot0</literal>'s entry point.</para> - - <para>It is important to note how the User Code Segment is - defined. This segment's <emphasis>base address</emphasis> is - set to <literal>0xa000</literal>. This means that code memory - addresses are <emphasis>relative</emphasis> to address 0xa000; - if code being executed is fetched from address - <literal>0x2000</literal>, the <emphasis>actual</emphasis> - memory addressed is - <literal>0xa000+0x2000=0xc000</literal>.</para> - </sect1> - - <sect1 xml:id="boot2"> - <title><application>boot2</application> Stage</title> - - <para><literal>boot2</literal> defines an important structure, - <literal>struct bootinfo</literal>. This structure is - initialized by <literal>boot2</literal> and passed to the - loader, and then further to the kernel. Some nodes of this - structures are set by <literal>boot2</literal>, the rest by the - loader. This structure, among other information, contains the - kernel filename, <acronym>BIOS</acronym> harddisk geometry, - <acronym>BIOS</acronym> drive number for boot device, physical - memory available, <literal>envp</literal> pointer etc. The - definition for it is:</para> - - <programlisting><filename>/usr/include/machine/bootinfo.h:</filename> -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 */ -};</programlisting> - - <para><literal>boot2</literal> enters into an infinite loop - waiting for user input, then calls <function>load()</function>. - If the user does not press anything, the loop breaks by a - timeout, so <function>load()</function> will load the default - file (<filename>/boot/loader</filename>). Functions - <function>ino_t lookup(char *filename)</function> and - <function>int xfsread(ino_t inode, void *buf, size_t - nbyte)</function> are used to read the content of a file into - memory. <filename>/boot/loader</filename> is an - <acronym>ELF</acronym> binary, but where the - <acronym>ELF</acronym> header is prepended with - <filename>a.out</filename>'s <literal>struct - exec</literal> structure. <function>load()</function> scans the - loader's ELF header, loading the content of - <filename>/boot/loader</filename> into memory, and passing the - execution to the loader's entry:</para> - - <programlisting><filename>sys/boot/i386/boot2/boot2.c:</filename> - __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));</programlisting> - </sect1> - - <sect1 xml:id="boot-loader"> - <title><application>loader</application> Stage</title> - - <para><application>loader</application> is a - <acronym>BTX</acronym> client as well. I will not describe it - here in detail, there is a comprehensive man page written by - Mike Smith, &man.loader.8;. The underlying mechanisms and - <acronym>BTX</acronym> were discussed above.</para> - - <para>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:</para> - - <programlisting><filename>sys/boot/common/boot.c:</filename> - /* Call the exec handler from the loader matching the kernel */ - module_formats[km->m_loader]->l_exec(km);</programlisting> - </sect1> - - <sect1 xml:id="boot-kernel"> - <title>Kernel Initialization</title> - - <para>Let us take a look at the command that links the kernel. - This will help identify the exact location where the loader - passes execution to the kernel. This location is the kernel's - actual entry point.</para> - - <programlisting><filename>sys/conf/Makefile.i386:</filename> -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></programlisting> - - <indexterm><primary>ELF</primary></indexterm> - <para>A few interesting things can be seen here. First, the - kernel is an ELF dynamically linked binary, but the dynamic - linker for kernel is <filename>/red/herring</filename>, which is - definitely a bogus file. Second, taking a look at the file - <filename>sys/conf/ldscript.i386</filename> gives an idea about - what <application>ld</application> options are used when - compiling a kernel. Reading through the first few lines, the - string</para> - - <programlisting><filename>sys/conf/ldscript.i386:</filename> -ENTRY(btext)</programlisting> - - <para>says that a kernel's entry point is the symbol `btext'. - This symbol is defined in <filename>locore.s</filename>:</para> - - <programlisting><filename>sys/i386/i386/locore.s:</filename> - .text -/********************************************************************** - * - * This is where the bootblocks start us, set the ball rolling... - * - */ -NON_GPROF_ENTRY(btext)</programlisting> - - <para>First, the register EFLAGS is set to a predefined value of - 0x00000002. Then all the segment registers are - initialized:</para> - - <programlisting><filename>sys/i386/i386/locore.s:</filename> -/* 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, %gs</programlisting> - - <para>btext calls the routines - <function>recover_bootinfo()</function>, - <function>identify_cpu()</function>, - <function>create_pagetables()</function>, which are also defined - in <filename>locore.s</filename>. Here is a description of what - they do:</para> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="2" align="left"> - <tbody> - <row> - <entry><function>recover_bootinfo</function></entry> - <entry>This 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, or by the old diskless boot - procedure. This function determines the booting method, - and stores the <literal>struct bootinfo</literal> - structure into the kernel memory.</entry> - </row> - - <row> - <entry><function>identify_cpu</function></entry> - <entry>This functions tries to find out what CPU it is - running on, storing the value found in a variable - <varname>_cpu</varname>.</entry> - </row> - - <row> - <entry><function>create_pagetables</function></entry> - <entry>This function allocates and fills out a Page Table - Directory at the top of the kernel memory area.</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>The next steps are enabling VME, if the CPU supports - it:</para> - - <programlisting> testl $CPUID_VME, R(_cpu_feature) - jz 1f - movl %cr4, %eax - orl $CR4_VME, %eax - movl %eax, %cr4</programlisting> - - <para>Then, enabling paging:</para> - - <programlisting>/* 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! */</programlisting> - - <para>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:</para> - - <programlisting> pushl $begin /* jump to high virtualized address */ - ret - -/* now running relocated at KERNBASE where the system is linked to run */ -begin:</programlisting> - - <para>The function <function>init386()</function> is called with - a pointer to the first free physical page, after that - <function>mi_startup()</function>. <function>init386</function> - is an architecture dependent initialization function, and - <function>mi_startup()</function> is an architecture independent - one (the 'mi_' prefix stands for Machine Independent). The - kernel never returns from <function>mi_startup()</function>, and - by calling it, the kernel finishes booting:</para> - - <programlisting><filename>sys/i386/i386/locore.s:</filename> - 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 */</programlisting> - - <sect2> - <title><function>init386()</function></title> - - <para><function>init386()</function> is defined in - <filename>sys/i386/i386/machdep.c</filename> 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 looking at the code, consider - the tasks the processor must complete to initialize protected - mode execution:</para> - - <itemizedlist> - <listitem> - <para>Initialize the kernel tunable parameters, passed from - the bootstrapping program.</para> - </listitem> - - <listitem> - <para>Prepare the GDT.</para> - </listitem> - - <listitem> - <para>Prepare the IDT.</para> - </listitem> - - <listitem> - <para>Initialize the system console.</para> - </listitem> - - <listitem> - <para>Initialize the DDB, if it is compiled into - kernel.</para> - </listitem> - - <listitem> - <para>Initialize the TSS.</para> - </listitem> - - <listitem> - <para>Prepare the LDT.</para> - </listitem> - - <listitem> - <para>Set up proc0's pcb.</para> - </listitem> - </itemizedlist> - - <indexterm><primary>parameters</primary></indexterm> - <para><function>init386()</function> initializes the tunable - parameters passed from bootstrap by setting the environment - pointer (envp) and calling <function>init_param1()</function>. - The envp pointer has been passed from loader in the - <literal>bootinfo</literal> structure:</para> - - <programlisting><filename>sys/i386/i386/machdep.c:</filename> - kern_envp = (caddr_t)bootinfo.bi_envp + KERNBASE; - - /* Init basic tunables, hz etc */ - init_param1();</programlisting> - - <para><function>init_param1()</function> is defined in - <filename>sys/kern/subr_param.c</filename>. That file has a - number of sysctls, and two functions, - <function>init_param1()</function> and - <function>init_param2()</function>, that are called from - <function>init386()</function>:</para> - - <programlisting><filename>sys/kern/subr_param.c:</filename> - hz = HZ; - TUNABLE_INT_FETCH("kern.hz", &hz);</programlisting> - - <para>TUNABLE_<typename>_FETCH is used to fetch the value - from the environment:</para> - - <programlisting><filename>/usr/src/sys/sys/kernel.h:</filename> -#define TUNABLE_INT_FETCH(path, var) getenv_int((path), (var))</programlisting> - - <para>Sysctl <literal>kern.hz</literal> is the system clock - tick. Additionally, these sysctls are set by - <function>init_param1()</function>: <literal>kern.maxswzone, - kern.maxbcache, kern.maxtsiz, kern.dfldsiz, kern.maxdsiz, - kern.dflssiz, kern.maxssiz, kern.sgrowsiz</literal>.</para> - - <indexterm> - <primary>Global Descriptors Table (GDT)</primary> - </indexterm> - - <para>Then <function>init386()</function> 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 - <quote>the virtual address of code segment CS</quote> + 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:</para> - - <programlisting><filename>sys/i386/i386/machdep.c:</filename> -union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */ - -<filename>sys/i386/include/segments.h:</filename> -/* - * 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) */</programlisting> - - <para>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.</para> - - <indexterm><primary>Interrupt Descriptor Table - (IDT)</primary></indexterm> - <para>The next step is to initialize the Interrupt Descriptor - Table (IDT). This table is referenced by the processor when a - software or hardware interrupt occurs. For example, to make a - system call, user application issues the - <literal>INT 0x80</literal> 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):</para> - - <programlisting><filename>sys/i386/i386/machdep.c:</filename> -static struct gate_descriptor idt0[NIDT]; -struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */</programlisting> - - <para>For each interrupt, an appropriate handler is set. The - syscall gate for <literal>INT 0x80</literal> is set as - well:</para> - - <programlisting><filename>sys/i386/i386/machdep.c:</filename> - setidt(0x80, &IDTVEC(int0x80_syscall), - SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL));</programlisting> - - <para>So when a userland application issues the - <literal>INT 0x80</literal> instruction, control will transfer - to the function <function>_Xint0x80_syscall</function>, which - is in the kernel code segment and will be executed with - supervisor privileges.</para> - - <para>Console and DDB are then initialized:</para> - <indexterm><primary>DDB</primary></indexterm> - - <programlisting><filename>sys/i386/i386/machdep.c:</filename> - cninit(); -/* skipped */ -#ifdef DDB - kdb_init(); - if (boothowto & RB_KDB) - Debugger("Boot flags requested debugger"); -#endif</programlisting> - - <para>The 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.</para> - - <para>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:</para> - - <programlisting><filename>/usr/include/machine/segments.h:</filename> -#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)</programlisting> - - <para>Next, proc0's Process Control Block - (<literal>struct pcb</literal>) structure is initialized. - proc0 is a <literal>struct proc</literal> structure that - describes a kernel process. It is always present while the - kernel is running, therefore it is declared as global:</para> - - <programlisting><filename>sys/kern/kern_init.c:</filename> - struct proc proc0;</programlisting> - - <para>The structure <literal>struct pcb</literal> is a part of a - proc structure. It is defined in - <filename>/usr/include/machine/pcb.h</filename> and has a - process's information specific to the i386 architecture, such - as registers values.</para> - </sect2> - - <sect2> - <title><function>mi_startup()</function></title> - - <para>This function performs a bubble sort of all the system - initialization objects and then calls the entry of each object - one by one:</para> - - <programlisting><filename>sys/kern/init_main.c:</filename> - for (sipp = sysinit; *sipp; sipp++) { - - /* ... skipped ... */ - - /* Call function */ - (*((*sipp)->func))((*sipp)->udata); - /* ... skipped ... */ - }</programlisting> - - <para>Although the sysinit framework is described in the <link - xlink:href="&url.doc.langbase;/books/developers-handbook">Developers' - Handbook</link>, I will discuss the internals of it.</para> - - <indexterm><primary>sysinit objects</primary></indexterm> - <para>Every system initialization object (sysinit object) is - created by calling a SYSINIT() macro. Let us take as example - an <literal>announce</literal> sysinit object. This object - prints the copyright message:</para> - - <programlisting><filename>sys/kern/init_main.c:</filename> -static void -print_caddr_t(void *data __unused) -{ - printf("%s", (char *)data); -} -SYSINIT(announce, SI_SUB_COPYRIGHT, SI_ORDER_FIRST, print_caddr_t, copyright)</programlisting> - - <para>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.</para> - - <para>Let us take a look at what exactly the macro - <literal>SYSINIT()</literal> does. It expands to a - <literal>C_SYSINIT()</literal> macro. The - <literal>C_SYSINIT()</literal> macro then expands to a static - <literal>struct sysinit</literal> structure declaration with - another <literal>DATA_SET</literal> macro call:</para> - - <programlisting><filename>/usr/include/sys/kernel.h:</filename> - #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)</programlisting> - - <para>The <literal>DATA_SET()</literal> macro expands to a - <literal>MAKE_SET()</literal>, and that macro is the point - where all the sysinit magic is hidden:</para> - - <programlisting><filename>/usr/include/linker_set.h:</filename> -#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)</programlisting> - - <para>In our case, the following declaration will occur:</para> - - <programlisting>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");</programlisting> - - <para>The first <literal>__asm</literal> instruction will create - an ELF section within the kernel's executable. This will - happen at kernel link time. The section will have the name - <literal>.set.sysinit_set</literal>. The content of this - section is one 32-bit value, the address of announce_sys_init - structure, and that is what the second - <literal>__asm</literal> is. The third - <literal>__asm</literal> 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.</para> - - <para>Running <application>objdump</application> on a kernel - binary, you may notice the presence of such small - sections:</para> - - <screen>&prompt.user; <userinput>objdump -h /kernel</userinput> - 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, DATA</screen> - - <para>This screen dump shows that the size of .set.sysinit_set - section is 0x664 bytes, so <literal>0x664/sizeof(void - *)</literal> sysinit objects are compiled into the kernel. - The other sections such as <literal>.set.sysctl_set</literal> - represent other linker sets.</para> - - <para>By defining a variable of type <literal>struct - linker_set</literal> the content of - <literal>.set.sysinit_set</literal> section will be - <quote>collected</quote> into that variable:</para> - - <programlisting><filename>sys/kern/init_main.c:</filename> - extern struct linker_set sysinit_set; /* XXX */</programlisting> - - <para>The <literal>struct linker_set</literal> is defined as - follows:</para> - - <programlisting><filename>/usr/include/linker_set.h:</filename> - struct linker_set { - int ls_length; - void *ls_items[1]; /* really ls_length of them, trailing NULL */ -};</programlisting> - - <para>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.</para> - - <para>Returning to the <function>mi_startup()</function> - discussion, it is must be clear now, how the sysinit objects - are being organized. The <function>mi_startup()</function> - function sorts them and calls each. The very last object is - the system scheduler:</para> - - <programlisting><filename>/usr/include/sys/kernel.h:</filename> -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*/ -};</programlisting> - - <para>The system scheduler sysinit object is defined in the file - <filename>sys/vm/vm_glue.c</filename>, and the entry point for - that object is <function>scheduler()</function>. 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.</para> - - <para>The first user process, called <emphasis>init</emphasis>, - is created by the sysinit object - <literal>init</literal>:</para> - - <programlisting><filename>sys/kern/init_main.c:</filename> -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)</programlisting> - - <para>The <function>create_init()</function> allocates a new - process by calling <function>fork1()</function>, but does not - mark it runnable. When this new process is scheduled for - execution by the scheduler, the - <function>start_init()</function> will be called. That - function is defined in <filename>init_main.c</filename>. It - tries to load and exec the <filename>init</filename> binary, - probing <filename>/sbin/init</filename> first, then - <filename>/sbin/oinit</filename>, - <filename>/sbin/init.bak</filename>, and finally - <filename>/stand/sysinstall</filename>:</para> - - <programlisting><filename>sys/kern/init_main.c:</filename> -static char init_path[MAXPATHLEN] = -#ifdef INIT_PATH - __XSTRING(INIT_PATH); -#else - "/sbin/init:/sbin/oinit:/sbin/init.bak:/stand/sysinstall"; -#endif</programlisting> - </sect2> - </sect1> -</chapter> diff --git a/en_US.ISO8859-1/books/arch-handbook/chapters.ent b/en_US.ISO8859-1/books/arch-handbook/chapters.ent deleted file mode 100644 index 5182a6f8fb..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/chapters.ent +++ /dev/null @@ -1,34 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1"?> -<!-- - Creates entities for each chapter in the FreeBSD Architecture - Handbook. Each entity is named chap.foo, where foo is the value - of the id attribute on that chapter, and corresponds to the name of - the directory in which that chapter's .xml file is stored. - - Chapters should be listed in the order in which they are referenced. - - $FreeBSD$ ---> - -<!-- Part one - Kernel --> -<!ENTITY chap.boot SYSTEM "boot/chapter.xml"> -<!ENTITY chap.kobj SYSTEM "kobj/chapter.xml"> -<!ENTITY chap.sysinit SYSTEM "sysinit/chapter.xml"> -<!ENTITY chap.locking SYSTEM "locking/chapter.xml"> -<!ENTITY chap.vm SYSTEM "vm/chapter.xml"> -<!ENTITY chap.jail SYSTEM "jail/chapter.xml"> -<!ENTITY chap.mac SYSTEM "mac/chapter.xml"> -<!ENTITY chap.smp SYSTEM "smp/chapter.xml"> - -<!-- Part Two - Device Drivers --> -<!ENTITY chap.driverbasics SYSTEM "driverbasics/chapter.xml"> -<!ENTITY chap.isa SYSTEM "isa/chapter.xml"> -<!ENTITY chap.pci SYSTEM "pci/chapter.xml"> -<!ENTITY chap.scsi SYSTEM "scsi/chapter.xml"> -<!ENTITY chap.usb SYSTEM "usb/chapter.xml"> -<!ENTITY chap.newbus SYSTEM "newbus/chapter.xml"> -<!ENTITY chap.snd SYSTEM "sound/chapter.xml"> -<!ENTITY chap.pccard SYSTEM "pccard/chapter.xml"> - -<!-- Part three - Appendices --> -<!ENTITY chap.index "<index xmlns='http://docbook.org/ns/docbook'/>"> diff --git a/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.xml b/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.xml deleted file mode 100644 index 9826e3a1d9..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.xml +++ /dev/null @@ -1,423 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1"?> -<!-- - The FreeBSD Documentation Project - - $FreeBSD$ ---> - -<chapter xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" - xml:id="driverbasics"> - - <info> - <title>Writing FreeBSD Device Drivers</title> - - <authorgroup> - <author> - <personname> - <firstname>Murray</firstname> - <surname>Stokely</surname> - </personname> - - <contrib>Written by </contrib> - </author> - </authorgroup> - - <authorgroup> - <author> - <personname> - <firstname>Jörg</firstname> - <surname>Wunsch</surname> - </personname> - - <contrib>Based on intro(4) manual page by </contrib> - </author> - </authorgroup> - </info> - - <sect1 xml:id="driverbasics-intro"> - <title>Introduction</title> - - <indexterm><primary>device driver</primary></indexterm> - <indexterm><primary>pseudo-device</primary></indexterm> - - <para>This chapter provides a brief introduction to writing device - drivers for FreeBSD. A device in this context is a term used - mostly for hardware-related stuff that belongs to the system, - like disks, printers, or a graphics display with its keyboard. - A device driver is the software component of the operating - system that controls a specific device. There are also - so-called pseudo-devices where a device driver emulates the - behavior of a device in software without any particular - underlying hardware. Device drivers can be compiled into the - system statically or loaded on demand through the dynamic kernel - linker facility `kld'.</para> - - <indexterm><primary>device nodes</primary></indexterm> - - <para>Most devices in a &unix;-like operating system are accessed - through device-nodes, sometimes also called special files. - These files are usually located under the directory - <filename>/dev</filename> in the filesystem hierarchy.</para> - - <para>Device drivers can roughly be broken down into two - categories; character and network device drivers.</para> - - </sect1> - - <sect1 xml:id="driverbasics-kld"> - <title>Dynamic Kernel Linker Facility - KLD</title> - - <indexterm> - <primary>kernel linking</primary> - <secondary>dynamic</secondary> - </indexterm> - <indexterm> - <primary>kernel loadable modules (KLD)</primary> - </indexterm> - - <para>The kld interface allows system administrators to - dynamically add and remove functionality from a running system. - This allows device driver writers to load their new changes into - a running kernel without constantly rebooting to test - changes.</para> - - <indexterm> - <primary>kernel modules</primary> - <secondary>loading</secondary> - </indexterm> - <indexterm> - <primary>kernel modules</primary> - <secondary>unloading</secondary> - </indexterm> - <indexterm> - <primary>kernel modules</primary> - <secondary>listing</secondary> - </indexterm> - - <para>The kld interface is used through:</para> - - <itemizedlist> - <listitem> - <simpara><command>kldload</command> - loads a new kernel - module</simpara></listitem> - <listitem> - <simpara><command>kldunload</command> - unloads a kernel - module</simpara></listitem> - <listitem> - <simpara><command>kldstat</command> - lists loaded - modules</simpara></listitem> - </itemizedlist> - - <para>Skeleton Layout of a kernel module</para> - - <programlisting>/* - * KLD Skeleton - * Inspired by Andrew Reiter's Daemonnews article - */ - -#include <sys/types.h> -#include <sys/module.h> -#include <sys/systm.h> /* uprintf */ -#include <sys/errno.h> -#include <sys/param.h> /* defines used in kernel.h */ -#include <sys/kernel.h> /* types used in module initialization */ - -/* - * Load handler that deals with the loading and unloading of a KLD. - */ - -static int -skel_loader(struct module *m, int what, void *arg) -{ - int err = 0; - - switch (what) { - case MOD_LOAD: /* kldload */ - uprintf("Skeleton KLD loaded.\n"); - break; - case MOD_UNLOAD: - uprintf("Skeleton KLD unloaded.\n"); - break; - default: - err = EOPNOTSUPP; - break; - } - return(err); -} - -/* Declare this module to the rest of the kernel */ - -static moduledata_t skel_mod = { - "skel", - skel_loader, - NULL -}; - -DECLARE_MODULE(skeleton, skel_mod, SI_SUB_KLD, SI_ORDER_ANY);</programlisting> - - - <sect2> - <title>Makefile</title> - - <para>&os; provides a system makefile to simplify compiling a - kernel module.</para> - - <programlisting>SRCS=skeleton.c -KMOD=skeleton - -.include <bsd.kmod.mk></programlisting> - - <para>Running <command>make</command> with this makefile - will create a file <filename>skeleton.ko</filename> that can - be loaded into the kernel by typing:</para> - - <screen>&prompt.root; <userinput>kldload -v ./skeleton.ko</userinput></screen> - </sect2> - </sect1> - - <sect1 xml:id="driverbasics-char"> - <title>Character Devices</title> - - <indexterm> - <primary>character devices</primary> - </indexterm> - <para>A character device driver is one that transfers data - directly to and from a user process. This is the most common - type of device driver and there are plenty of simple examples in - the source tree.</para> - - <para>This simple example pseudo-device remembers whatever values - are written to it and can then echo them back when - read.</para> - - <example> - <title>Example of a Sample Echo Pseudo-Device Driver for - &os; 10.X - 12.X</title> - - <programlisting>/* - * Simple Echo pseudo-device KLD - * - * Murray Stokely - * Søren (Xride) Straarup - * Eitan Adler - */ - -#include <sys/types.h> -#include <sys/module.h> -#include <sys/systm.h> /* uprintf */ -#include <sys/param.h> /* defines used in kernel.h */ -#include <sys/kernel.h> /* types used in module initialization */ -#include <sys/conf.h> /* cdevsw struct */ -#include <sys/uio.h> /* uio struct */ -#include <sys/malloc.h> - -#define BUFFERSIZE 255 - -/* Function prototypes */ -static d_open_t echo_open; -static d_close_t echo_close; -static d_read_t echo_read; -static d_write_t echo_write; - -/* Character device entry points */ -static struct cdevsw echo_cdevsw = { - .d_version = D_VERSION, - .d_open = echo_open, - .d_close = echo_close, - .d_read = echo_read, - .d_write = echo_write, - .d_name = "echo", -}; - -struct s_echo { - char msg[BUFFERSIZE + 1]; - int len; -}; - -/* vars */ -static struct cdev *echo_dev; -static struct s_echo *echomsg; - -MALLOC_DECLARE(M_ECHOBUF); -MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module"); - -/* - * This function is called by the kld[un]load(2) system calls to - * determine what actions to take when a module is loaded or unloaded. - */ -static int -echo_loader(struct module *m __unused, int what, void *arg __unused) -{ - int error = 0; - - switch (what) { - case MOD_LOAD: /* kldload */ - error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, - &echo_dev, - &echo_cdevsw, - 0, - UID_ROOT, - GID_WHEEL, - 0600, - "echo"); - if (error != 0) - break; - - echomsg = malloc(sizeof(*echomsg), M_ECHOBUF, M_WAITOK | - M_ZERO); - printf("Echo device loaded.\n"); - break; - case MOD_UNLOAD: - destroy_dev(echo_dev); - free(echomsg, M_ECHOBUF); - printf("Echo device unloaded.\n"); - break; - default: - error = EOPNOTSUPP; - break; - } - return (error); -} - -static int -echo_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, - struct thread *td __unused) -{ - int error = 0; - - uprintf("Opened device \"echo\" successfully.\n"); - return (error); -} - -static int -echo_close(struct cdev *dev __unused, int fflag __unused, int devtype __unused, - struct thread *td __unused) -{ - - uprintf("Closing device \"echo\".\n"); - return (0); -} - -/* - * The read function just takes the buf that was saved via - * echo_write() and returns it to userland for accessing. - * uio(9) - */ -static int -echo_read(struct cdev *dev __unused, struct uio *uio, int ioflag __unused) -{ - size_t amt; - int error; - - /* - * How big is this read operation? Either as big as the user wants, - * or as big as the remaining data. Note that the 'len' does not - * include the trailing null character. - */ - amt = MIN(uio->uio_resid, uio->uio_offset >= echomsg->len + 1 ? 0 : - echomsg->len + 1 - uio->uio_offset); - - if ((error = uiomove(echomsg->msg, amt, uio)) != 0) - uprintf("uiomove failed!\n"); - - return (error); -} - -/* - * echo_write takes in a character string and saves it - * to buf for later accessing. - */ -static int -echo_write(struct cdev *dev __unused, struct uio *uio, int ioflag __unused) -{ - size_t amt; - int error; - - /* - * We either write from the beginning or are appending -- do - * not allow random access. - */ - if (uio->uio_offset != 0 && (uio->uio_offset != echomsg->len)) - return (EINVAL); - - /* This is a new message, reset length */ - if (uio->uio_offset == 0) - echomsg->len = 0; - - /* Copy the string in from user memory to kernel memory */ - amt = MIN(uio->uio_resid, (BUFFERSIZE - echomsg->len)); - - error = uiomove(echomsg->msg + uio->uio_offset, amt, uio); - - /* Now we need to null terminate and record the length */ - echomsg->len = uio->uio_offset; - echomsg->msg[echomsg->len] = 0; - - if (error != 0) - uprintf("Write failed: bad address!\n"); - return (error); -} - -DEV_MODULE(echo, echo_loader, NULL);</programlisting> - </example> - - <para>With this driver loaded try:</para> - - <screen>&prompt.root; <userinput>echo -n "Test Data" > /dev/echo</userinput> -&prompt.root; <userinput>cat /dev/echo</userinput> -Opened device "echo" successfully. -Test Data -Closing device "echo".</screen> - - <para>Real hardware devices are described in the next - chapter.</para> - </sect1> - - <sect1 xml:id="driverbasics-block"> - <title>Block Devices (Are Gone)</title> - - <indexterm><primary>block devices</primary></indexterm> - - <para>Other &unix; systems may support a second type of disk - device known as block devices. Block devices are disk devices - for which the kernel provides caching. This caching makes - block-devices almost unusable, or at least dangerously - unreliable. The caching will reorder the sequence of write - operations, depriving the application of the ability to know the - exact disk contents at any one instant in time.</para> - - <para>This makes predictable and reliable crash recovery of - on-disk data structures (filesystems, databases, etc.) - impossible. Since writes may be delayed, there is no way - the kernel can report to the application which particular - write operation encountered a write error, this further - compounds the consistency problem.</para> - - <para>For this reason, no serious applications rely on block - devices, and in fact, almost all applications which access - disks directly take great pains to specify that character - (or <quote>raw</quote>) devices should always be used. As - the implementation of the aliasing of each disk (partition) to - two devices with different semantics significantly complicated - the relevant kernel code, &os; dropped support for cached disk - devices as part of the modernization of the disk I/O - infrastructure.</para> - </sect1> - - <sect1 xml:id="driverbasics-net"> - <title>Network Drivers</title> - - <indexterm> - <primary>network devices</primary> - </indexterm> - <para>Drivers for network devices do not use device nodes in order - to be accessed. Their selection is based on other decisions - made inside the kernel and instead of calling open(), use of a - network device is generally introduced by using the system call - socket(2).</para> - - <para>For more information see ifnet(9), the source of the - loopback device, and Bill Paul's network drivers.</para> - </sect1> -</chapter> diff --git a/en_US.ISO8859-1/books/arch-handbook/isa/chapter.xml b/en_US.ISO8859-1/books/arch-handbook/isa/chapter.xml deleted file mode 100644 index 04de498a3f..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/isa/chapter.xml +++ /dev/null @@ -1,2514 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1"?> -<!-- - The FreeBSD Documentation Project - - $FreeBSD$ ---> -<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xml:id="isa-driver"> - <info><title>ISA Device Drivers</title> - <authorgroup> - <author><personname><firstname>Sergey</firstname><surname>Babkin</surname></personname><contrib>Written by </contrib></author> - </authorgroup> - <authorgroup> - <author><personname><firstname>Murray</firstname><surname>Stokely</surname></personname><contrib>Modifications for Handbook made by </contrib></author> - <author><personname><firstname>Valentino</firstname><surname>Vaschetto</surname></personname></author> - <author><personname><firstname>Wylie</firstname><surname>Stilwell</surname></personname></author> - </authorgroup> - </info> - - - - <sect1 xml:id="isa-driver-synopsis"> - <title>Synopsis</title> - - <indexterm><primary>ISA</primary></indexterm> - <indexterm><primary>device driver</primary><secondary>ISA</secondary></indexterm> - - <para>This chapter introduces the issues relevant to writing a - driver for an ISA device. The pseudo-code presented here is - rather detailed and reminiscent of the real code but is still - only pseudo-code. It avoids the details irrelevant to the - subject of the discussion. The real-life examples can be found - in the source code of real drivers. In particular the drivers - <literal>ep</literal> and <literal>aha</literal> are good sources of information.</para> - </sect1> - - <sect1 xml:id="isa-driver-basics"> - <title>Basic Information</title> - - <para>A typical ISA driver would need the following include - files:</para> - -<programlisting>#include <sys/module.h> -#include <sys/bus.h> -#include <machine/bus.h> -#include <machine/resource.h> -#include <sys/rman.h> - -#include <isa/isavar.h> -#include <isa/pnpvar.h></programlisting> - - <para>They describe the things specific to the ISA and generic - bus subsystem.</para> - - <indexterm><primary>object-oriented</primary></indexterm> - <para>The bus subsystem is implemented in an object-oriented - fashion, its main structures are accessed by associated method - functions.</para> - - <indexterm><primary>bus methods</primary></indexterm> - <para>The list of bus methods implemented by an ISA driver is like - one for any other bus. For a hypothetical driver named <quote>xxx</quote> - they would be:</para> - - <itemizedlist> - <listitem> - <para><function>static void xxx_isa_identify (driver_t *, - device_t);</function> Normally used for bus drivers, not - device drivers. But for ISA devices this method may have - special use: if the device provides some device-specific - (non-PnP) way to auto-detect devices this routine may - implement it.</para> - </listitem> - - <listitem> - <para><function>static int xxx_isa_probe (device_t - dev);</function> Probe for a device at a known (or PnP) - location. This routine can also accommodate device-specific - auto-detection of parameters for partially configured - devices.</para> - </listitem> - - <listitem> - <para><function>static int xxx_isa_attach (device_t - dev);</function> Attach and initialize device.</para> - </listitem> - - <listitem> - <para><function>static int xxx_isa_detach (device_t - dev);</function> Detach device before unloading the driver - module.</para> - </listitem> - - <listitem> - <para><function>static int xxx_isa_shutdown (device_t - dev);</function> Execute shutdown of the device before - system shutdown.</para> - </listitem> - - <listitem> - <para><function>static int xxx_isa_suspend (device_t - dev);</function> Suspend the device before the system goes - to the power-save state. May also abort transition to the - power-save state.</para> - </listitem> - - <listitem> - <para><function>static int xxx_isa_resume (device_t - dev);</function> Resume the device activity after return - from power-save state.</para> - </listitem> - - </itemizedlist> - - <para><function>xxx_isa_probe()</function> and - <function>xxx_isa_attach()</function> are mandatory, the rest of - the routines are optional, depending on the device's - needs.</para> - - <para>The driver is linked to the system with the following set of - descriptions.</para> - -<programlisting> /* table of supported bus methods */ - static device_method_t xxx_isa_methods[] = { - /* list all the bus method functions supported by the driver */ - /* omit the unsupported methods */ - DEVMETHOD(device_identify, xxx_isa_identify), - DEVMETHOD(device_probe, xxx_isa_probe), - DEVMETHOD(device_attach, xxx_isa_attach), - DEVMETHOD(device_detach, xxx_isa_detach), - DEVMETHOD(device_shutdown, xxx_isa_shutdown), - DEVMETHOD(device_suspend, xxx_isa_suspend), - DEVMETHOD(device_resume, xxx_isa_resume), - - DEVMETHOD_END - }; - - static driver_t xxx_isa_driver = { - "xxx", - xxx_isa_methods, - sizeof(struct xxx_softc), - }; - - - static devclass_t xxx_devclass; - - DRIVER_MODULE(xxx, isa, xxx_isa_driver, xxx_devclass, - load_function, load_argument);</programlisting> - - <indexterm><primary>softc</primary></indexterm> - - <para>Here struct <varname remap="structname">xxx_softc</varname> is a - device-specific structure that contains private driver data - and descriptors for the driver's resources. The bus code - automatically allocates one softc descriptor per device as - needed.</para> - - <indexterm><primary>kernel module</primary></indexterm> - - <para>If the driver is implemented as a loadable module then - <function>load_function()</function> is called to do - driver-specific initialization or clean-up when the driver is - loaded or unloaded and load_argument is passed as one of its - arguments. If the driver does not support dynamic loading (in - other words it must always be linked into the kernel) then these - values should be set to 0 and the last definition would look - like:</para> - - <programlisting> DRIVER_MODULE(xxx, isa, xxx_isa_driver, - xxx_devclass, 0, 0);</programlisting> - - <indexterm><primary>PnP</primary></indexterm> - - <para>If the driver is for a device which supports PnP then a - table of supported PnP IDs must be defined. The table - consists of a list of PnP IDs supported by this driver and - human-readable descriptions of the hardware types and models - having these IDs. It looks like:</para> - -<programlisting> static struct isa_pnp_id xxx_pnp_ids[] = { - /* a line for each supported PnP ID */ - { 0x12345678, "Our device model 1234A" }, - { 0x12345679, "Our device model 1234B" }, - { 0, NULL }, /* end of table */ - };</programlisting> - - <para>If the driver does not support PnP devices it still needs - an empty PnP ID table, like:</para> - -<programlisting> static struct isa_pnp_id xxx_pnp_ids[] = { - { 0, NULL }, /* end of table */ - };</programlisting> - - </sect1> - - <sect1 xml:id="isa-driver-device-t"> - <title><varname remap="structname">device_t</varname> Pointer</title> - - <para><varname remap="structname">device_t</varname> is the pointer type for - the device structure. Here we consider only the methods - interesting from the device driver writer's standpoint. The - methods to manipulate values in the device structure - are:</para> - - <itemizedlist> - - <listitem><para><function>device_t - device_get_parent(dev)</function> Get the parent bus of a - device.</para></listitem> - - <listitem><para><function>driver_t - device_get_driver(dev)</function> Get pointer to its driver - structure.</para></listitem> - - <listitem><para><function>char - *device_get_name(dev)</function> Get the driver name, such - as <literal>"xxx"</literal> for our example.</para></listitem> - - <listitem><para><function>int device_get_unit(dev)</function> - Get the unit number (units are numbered from 0 for the - devices associated with each driver).</para></listitem> - - <listitem><para><function>char - *device_get_nameunit(dev)</function> Get the device name - including the unit number, such as <quote>xxx0</quote>, <quote>xxx1</quote> and so - on.</para></listitem> - - <listitem><para><function>char - *device_get_desc(dev)</function> Get the device - description. Normally it describes the exact model of device - in human-readable form.</para></listitem> - - <listitem><para><function>device_set_desc(dev, - desc)</function> Set the description. This makes the device - description point to the string desc which may not be - deallocated or changed after that.</para></listitem> - - <listitem><para><function>device_set_desc_copy(dev, - desc)</function> Set the description. The description is - copied into an internal dynamically allocated buffer, so the - string desc may be changed afterwards without adverse - effects.</para></listitem> - - <listitem><para><function>void - *device_get_softc(dev)</function> Get pointer to the device - descriptor (struct <varname remap="structname">xxx_softc</varname>) - associated with this device.</para></listitem> - - <listitem><para><function>u_int32_t - device_get_flags(dev)</function> Get the flags specified for - the device in the configuration file.</para></listitem> - - </itemizedlist> - - <para>A convenience function <function>device_printf(dev, fmt, - ...)</function> may be used to print the messages from the - device driver. It automatically prepends the unitname and - colon to the message.</para> - - <para>The device_t methods are implemented in the file - <filename>kern/bus_subr.c</filename>.</para> - - </sect1> - - <sect1 xml:id="isa-driver-config"> - <title>Configuration File and the Order of Identifying and Probing - During Auto-Configuration</title> - - <indexterm><primary>ISA</primary><secondary>probing</secondary></indexterm> - - <para>The ISA devices are described in the kernel configuration file - like:</para> - - <programlisting>device xxx0 at isa? port 0x300 irq 10 drq 5 - iomem 0xd0000 flags 0x1 sensitive</programlisting> - - <indexterm><primary>IRQ</primary></indexterm> - - <para>The values of port, IRQ and so on are converted to the - resource values associated with the device. They are optional, - depending on the device's needs and abilities for - auto-configuration. For example, some devices do not need DRQ - at all and some allow the driver to read the IRQ setting from - the device configuration ports. If a machine has multiple ISA - buses the exact bus may be specified in the configuration - line, like <literal>isa0</literal> or <literal>isa1</literal>, otherwise the device would be - searched for on all the ISA buses.</para> - - <para><literal>sensitive</literal> is a resource requesting that this device must - be probed before all non-sensitive devices. It is supported - but does not seem to be used in any current driver.</para> - - <para>For legacy ISA devices in many cases the drivers are still - able to detect the configuration parameters. But each device - to be configured in the system must have a config line. If two - devices of some type are installed in the system but there is - only one configuration line for the corresponding driver, ie: - <programlisting>device xxx0 at isa?</programlisting> then only - one device will be configured.</para> - - <para>But for the devices supporting automatic identification by - the means of Plug-n-Play or some proprietary protocol one - configuration line is enough to configure all the devices in - the system, like the one above or just simply:</para> - - <programlisting>device xxx at isa?</programlisting> - - <para>If a driver supports both auto-identified and legacy - devices and both kinds are installed at once in one machine - then it is enough to describe in the config file the legacy - devices only. The auto-identified devices will be added - automatically.</para> - - <para>When an ISA bus is auto-configured the events happen as - follows:</para> - - <para>All the drivers' identify routines (including the PnP - identify routine which identifies all the PnP devices) are - called in random order. As they identify the devices they add - them to the list on the ISA bus. Normally the drivers' - identify routines associate their drivers with the new - devices. The PnP identify routine does not know about the - other drivers yet so it does not associate any with the new - devices it adds.</para> - - <para>The PnP devices are put to sleep using the PnP protocol to - prevent them from being probed as legacy devices.</para> - - <para>The probe routines of non-PnP devices marked as - <literal>sensitive</literal> are called. If probe for a device went - successfully, the attach routine is called for it.</para> - - <para>The probe and attach routines of all non-PNP devices are - called likewise.</para> - - <para>The PnP devices are brought back from the sleep state and - assigned the resources they request: I/O and memory address - ranges, IRQs and DRQs, all of them not conflicting with the - attached legacy devices.</para> - - <para>Then for each PnP device the probe routines of all the - present ISA drivers are called. The first one that claims the - device gets attached. It is possible that multiple drivers - would claim the device with different priority; in this case, the - highest-priority driver wins. The probe routines must call - <function>ISA_PNP_PROBE()</function> to compare the actual PnP - ID with the list of the IDs supported by the driver and if the - ID is not in the table return failure. That means that - absolutely every driver, even the ones not supporting any PnP - devices must call <function>ISA_PNP_PROBE()</function>, at - least with an empty PnP ID table to return failure on unknown - PnP devices.</para> - - <para>The probe routine returns a positive value (the error - code) on error, zero or negative value on success.</para> - - <para>The negative return values are used when a PnP device - supports multiple interfaces. For example, an older - compatibility interface and a newer advanced interface which - are supported by different drivers. Then both drivers would - detect the device. The driver which returns a higher value in - the probe routine takes precedence (in other words, the driver - returning 0 has highest precedence, returning -1 is next, - returning -2 is after it and so on). In result the devices - which support only the old interface will be handled by the - old driver (which should return -1 from the probe routine) - while the devices supporting the new interface as well will be - handled by the new driver (which should return 0 from the - probe routine). If multiple drivers return the same value then - the one called first wins. So if a driver returns value 0 it - may be sure that it won the priority arbitration.</para> - - <para>The device-specific identify routines can also assign not - a driver but a class of drivers to the device. Then all the - drivers in the class are probed for this device, like the case - with PnP. This feature is not implemented in any existing - driver and is not considered further in this document.</para> - - <para>As the PnP devices are disabled when probing the - legacy devices they will not be attached twice (once as legacy - and once as PnP). But in case of device-dependent identify - routines it is the responsibility of the driver to make sure - that the same device will not be attached by the driver twice: - once as legacy user-configured and once as - auto-identified.</para> - - <para>Another practical consequence for the auto-identified - devices (both PnP and device-specific) is that the flags can - not be passed to them from the kernel configuration file. So - they must either not use the flags at all or use the flags - from the device unit 0 for all the auto-identified devices or - use the sysctl interface instead of flags.</para> - - <para>Other unusual configurations may be accommodated by - accessing the configuration resources directly with functions - of families <function>resource_query_*()</function> and - <function>resource_*_value()</function>. Their implementations - are located in <filename>kern/subr_bus.c</filename>. The old IDE disk driver - <filename>i386/isa/wd.c</filename> contains examples of such use. But the standard - means of configuration must always be preferred. Leave parsing - the configuration resources to the bus configuration - code.</para> - - </sect1> - - <sect1 xml:id="isa-driver-resources"> - <title>Resources</title> - - <indexterm><primary>resources</primary></indexterm> - <indexterm><primary>device driver</primary><secondary>resources</secondary></indexterm> - - <para>The information that a user enters into the kernel - configuration file is processed and passed to the kernel as - configuration resources. This information is parsed by the bus - configuration code and transformed into a value of structure - device_t and the bus resources associated with it. The drivers - may access the configuration resources directly using - functions <function>resource_*</function> for more complex cases of - configuration. However, generally this is neither needed nor recommended, - so this issue is not discussed further here.</para> - - <para>The bus resources are associated with each device. They - are identified by type and number within the type. For the ISA - bus the following types are defined:</para> - - <indexterm><primary>DMA channel</primary></indexterm> - - <itemizedlist> - <listitem> - <para><emphasis>SYS_RES_IRQ</emphasis> - interrupt - number</para> - </listitem> - - <listitem> - <para><emphasis>SYS_RES_DRQ</emphasis> - ISA DMA channel - number</para> - </listitem> - - <listitem> - <para><emphasis>SYS_RES_MEMORY</emphasis> - range of - device memory mapped into the system memory space - </para> - </listitem> - - <listitem> - <para><emphasis>SYS_RES_IOPORT</emphasis> - range of - device I/O registers</para> - </listitem> - </itemizedlist> - - <para>The enumeration within types starts from 0, so if a device - has two memory regions it would have resources of type - <literal>SYS_RES_MEMORY</literal> numbered 0 and 1. The resource type has - nothing to do with the C language type, all the resource - values have the C language type <literal>unsigned long</literal> and must be - cast as necessary. The resource numbers do not have to be - contiguous, although for ISA they normally would be. The - permitted resource numbers for ISA devices are:</para> - - <programlisting> IRQ: 0-1 - DRQ: 0-1 - MEMORY: 0-3 - IOPORT: 0-7</programlisting> - - <para>All the resources are represented as ranges, with a start - value and count. For IRQ and DRQ resources the count would - normally be equal to 1. The values for memory refer to the - physical addresses.</para> - - <para>Three types of activities can be performed on - resources:</para> - - <itemizedlist> - <listitem><para>set/get</para></listitem> - <listitem><para>allocate/release</para></listitem> - <listitem><para>activate/deactivate</para></listitem> - </itemizedlist> - - <para>Setting sets the range used by the resource. Allocation - reserves the requested range that no other driver would be - able to reserve it (and checking that no other driver reserved - this range already). Activation makes the resource accessible - to the driver by doing whatever is necessary for that (for - example, for memory it would be mapping into the kernel - virtual address space).</para> - - <para>The functions to manipulate resources are:</para> - - <itemizedlist> - <listitem> - <para><function>int bus_set_resource(device_t dev, int type, - int rid, u_long start, u_long count)</function></para> - - <para>Set a range for a resource. Returns 0 if successful, - error code otherwise. Normally, this function will - return an error only if one of <literal>type</literal>, - <literal>rid</literal>, <literal>start</literal> or - <literal>count</literal> has a value that falls out of the - permitted range.</para> - - <itemizedlist> - <listitem> - <para> dev - driver's device</para> - </listitem> - <listitem> - <para> type - type of resource, SYS_RES_* </para> - </listitem> - <listitem> - <para> rid - resource number (ID) within type </para> - </listitem> - <listitem> - <para> start, count - resource range </para> - </listitem> - </itemizedlist> - </listitem> - - <listitem> - <para><function>int bus_get_resource(device_t dev, int type, - int rid, u_long *startp, u_long *countp)</function></para> - - <para>Get the range of resource. Returns 0 if successful, - error code if the resource is not defined yet.</para> - </listitem> - - <listitem> - <para><function>u_long bus_get_resource_start(device_t dev, - int type, int rid) u_long bus_get_resource_count (device_t - dev, int type, int rid)</function></para> - - <para>Convenience functions to get only the start or - count. Return 0 in case of error, so if the resource start - has 0 among the legitimate values it would be impossible - to tell if the value is 0 or an error occurred. Luckily, - no ISA resources for add-on drivers may have a start value - equal to 0.</para> - </listitem> - - <listitem> - <para><function>void bus_delete_resource(device_t dev, int - type, int rid)</function></para> - <para> Delete a resource, make it undefined.</para> - </listitem> - - <listitem> - <para><function>struct resource * - bus_alloc_resource(device_t dev, int type, int *rid, - u_long start, u_long end, u_long count, u_int - flags)</function></para> - - <para>Allocate a resource as a range of count values not - allocated by anyone else, somewhere between start and - end. Alas, alignment is not supported. If the resource - was not set yet it is automatically created. The special - values of start 0 and end ~0 (all ones) means that the - fixed values previously set by - <function>bus_set_resource()</function> must be used - instead: start and count as themselves and - end=(start+count), in this case if the resource was not - defined before then an error is returned. Although rid is - passed by reference it is not set anywhere by the resource - allocation code of the ISA bus. (The other buses may use a - different approach and modify it).</para> - </listitem> - </itemizedlist> - - <para>Flags are a bitmap, the flags interesting for the caller - are:</para> - - <itemizedlist> - <listitem> - <para><emphasis>RF_ACTIVE</emphasis> - causes the resource - to be automatically activated after allocation.</para> - </listitem> - - <listitem> - <para><emphasis>RF_SHAREABLE</emphasis> - resource may be - shared at the same time by multiple drivers.</para> - </listitem> - - <listitem> - <para><emphasis>RF_TIMESHARE</emphasis> - resource may be - time-shared by multiple drivers, i.e., allocated at the - same time by many but activated only by one at any given - moment of time.</para> - </listitem> -<!-- XXXDONT KNOW IT THESE SHOULD BE TWO SEPARATE LISTS OR NOT --> - <listitem> - <para>Returns 0 on error. The allocated values may be - obtained from the returned handle using methods - <function>rhand_*()</function>.</para> - </listitem> - <listitem> - <para><function>int bus_release_resource(device_t dev, int - type, int rid, struct resource *r)</function></para> - </listitem> - - <listitem> - <para>Release the resource, r is the handle returned by - <function>bus_alloc_resource()</function>. Returns 0 on - success, error code otherwise.</para> - </listitem> - - <listitem> - <para><function>int bus_activate_resource(device_t dev, int - type, int rid, struct resource *r)</function> - <function>int bus_deactivate_resource(device_t dev, int - type, int rid, struct resource *r)</function></para> - </listitem> - - <listitem> - <para>Activate or deactivate resource. Return 0 on success, - error code otherwise. If the resource is time-shared and - currently activated by another driver then <literal>EBUSY</literal> is - returned.</para> - </listitem> - - <listitem> - <para><function>int bus_setup_intr(device_t dev, struct - resource *r, int flags, driver_intr_t *handler, void *arg, - void **cookiep)</function> <function>int - bus_teardown_intr(device_t dev, struct resource *r, void - *cookie)</function></para> - </listitem> - - <listitem> - <para>Associate or de-associate the interrupt handler with a - device. Return 0 on success, error code otherwise.</para> - </listitem> - - <listitem> - <para>r - the activated resource handler describing the - IRQ</para> - <para>flags - the interrupt priority level, one of:</para> - - <itemizedlist> - <listitem> - <para><function>INTR_TYPE_TTY</function> - terminals and - other likewise character-type devices. To mask them - use <function>spltty()</function>.</para> - </listitem> - <listitem> - <para><function>(INTR_TYPE_TTY | - INTR_TYPE_FAST)</function> - terminal type devices - with small input buffer, critical to the data loss on - input (such as the old-fashioned serial ports). To - mask them use <function>spltty()</function>.</para> - </listitem> - <listitem> - <para><function>INTR_TYPE_BIO</function> - block-type - devices, except those on the CAM controllers. To mask - them use <function>splbio()</function>.</para> - </listitem> - <listitem> - <para><function>INTR_TYPE_CAM</function> - CAM (Common - Access Method) bus controllers. To mask them use - <function>splcam()</function>.</para> - </listitem> - <listitem> - <para><function>INTR_TYPE_NET</function> - network - interface controllers. To mask them use - <function>splimp()</function>.</para> - </listitem> - <listitem> - <para><function>INTR_TYPE_MISC</function> - - miscellaneous devices. There is no other way to mask - them than by <function>splhigh()</function> which - masks all interrupts.</para> - </listitem> - </itemizedlist> - </listitem> - </itemizedlist> - - <para>When an interrupt handler executes all the other - interrupts matching its priority level will be masked. The - only exception is the MISC level for which no other interrupts - are masked and which is not masked by any other - interrupt.</para> - - <itemizedlist> - <listitem> - <para><emphasis>handler</emphasis> - pointer to the handler - function, the type driver_intr_t is defined as <function>void - driver_intr_t(void *)</function></para> - </listitem> - <listitem> - <para><emphasis>arg</emphasis> - the argument passed to the - handler to identify this particular device. It is cast - from void* to any real type by the handler. The old - convention for the ISA interrupt handlers was to use the - unit number as argument, the new (recommended) convention - is using a pointer to the device softc structure.</para> - </listitem> - <listitem> - <para><emphasis>cookie[p]</emphasis> - the value received - from <function>setup()</function> is used to identify the - handler when passed to - <function>teardown()</function></para> - </listitem> - </itemizedlist> - - <para>A number of methods are defined to operate on the resource - handlers (struct resource *). Those of interest to the device - driver writers are:</para> - - <itemizedlist> - <listitem> - <para><function>u_long rman_get_start(r) u_long - rman_get_end(r)</function> Get the start and end of - allocated resource range.</para> - </listitem> - <listitem> - <para><function>void *rman_get_virtual(r)</function> Get - the virtual address of activated memory resource.</para> - </listitem> - </itemizedlist> - - </sect1> - - <sect1 xml:id="isa-driver-busmem"> - <title>Bus Memory Mapping</title> - - <para>In many cases data is exchanged between the driver and the - device through the memory. Two variants are possible:</para> - - <para>(a) memory is located on the device card</para> - <para>(b) memory is the main memory of the computer</para> - - <para>In case (a) the driver always copies the data back and - forth between the on-card memory and the main memory as - necessary. To map the on-card memory into the kernel virtual - address space the physical address and length of the on-card - memory must be defined as a <literal>SYS_RES_MEMORY</literal> resource. That - resource can then be allocated and activated, and its virtual - address obtained using - <function>rman_get_virtual()</function>. The older drivers - used the function <function>pmap_mapdev()</function> for this - purpose, which should not be used directly any more. Now it is - one of the internal steps of resource activation.</para> - - <para>Most of the ISA cards will have their memory configured - for physical location somewhere in range 640KB-1MB. Some of - the ISA cards require larger memory ranges which should be - placed somewhere under 16MB (because of the 24-bit address - limitation on the ISA bus). In that case if the machine has - more memory than the start address of the device memory (in - other words, they overlap) a memory hole must be configured at - the address range used by devices. Many BIOSes allow - configuration of a memory hole of 1MB starting at 14MB or - 15MB. FreeBSD can handle the memory holes properly if the BIOS - reports them properly (this feature may be broken on old BIOSes).</para> - - <para>In case (b) just the address of the data is sent to - the device, and the device uses DMA to actually access the - data in the main memory. Two limitations are present: First, - ISA cards can only access memory below 16MB. Second, the - contiguous pages in virtual address space may not be - contiguous in physical address space, so the device may have - to do scatter/gather operations. The bus subsystem provides - ready solutions for some of these problems, the rest has to be - done by the drivers themselves.</para> - - <para>Two structures are used for DMA memory allocation, - <varname>bus_dma_tag_t</varname> and <varname>bus_dmamap_t</varname>. Tag describes the properties - required for the DMA memory. Map represents a memory block - allocated according to these properties. Multiple maps may be - associated with the same tag.</para> - - <para>Tags are organized into a tree-like hierarchy with - inheritance of the properties. A child tag inherits all the - requirements of its parent tag, and may make them more strict - but never more loose.</para> - - <para>Normally one top-level tag (with no parent) is created for - each device unit. If multiple memory areas with different - requirements are needed for each device then a tag for each of - them may be created as a child of the parent tag.</para> - - <para>The tags can be used to create a map in two ways.</para> - - <para>First, a chunk of contiguous memory conformant with the - tag requirements may be allocated (and later may be - freed). This is normally used to allocate relatively - long-living areas of memory for communication with the - device. Loading of such memory into a map is trivial: it is - always considered as one chunk in the appropriate physical - memory range.</para> - - <para>Second, an arbitrary area of virtual memory may be loaded - into a map. Each page of this memory will be checked for - conformance to the map requirement. If it conforms then it is - left at its original location. If it is not then a fresh - conformant <quote>bounce page</quote> is allocated and used as intermediate - storage. When writing the data from the non-conformant - original pages they will be copied to their bounce pages first - and then transferred from the bounce pages to the device. When - reading the data would go from the device to the bounce pages - and then copied to their non-conformant original pages. The - process of copying between the original and bounce pages is - called synchronization. This is normally used on a per-transfer - basis: buffer for each transfer would be loaded, transfer done - and buffer unloaded.</para> - - <para>The functions working on the DMA memory are:</para> - - <itemizedlist> - <listitem> - <para><function>int bus_dma_tag_create(bus_dma_tag_t parent, - bus_size_t alignment, bus_size_t boundary, bus_addr_t - lowaddr, bus_addr_t highaddr, bus_dma_filter_t *filter, void - *filterarg, bus_size_t maxsize, int nsegments, bus_size_t - maxsegsz, int flags, bus_dma_tag_t *dmat)</function></para> - - <para>Create a new tag. Returns 0 on success, the error code - otherwise.</para> - - <itemizedlist> - <listitem> - <para><emphasis>parent</emphasis> - parent tag, or NULL to - create a top-level tag.</para> - </listitem> - - <listitem> - <para><emphasis>alignment</emphasis> - - required physical alignment of the memory area to be - allocated for this tag. Use value 1 for <quote>no specific - alignment</quote>. Applies only to the future - <function>bus_dmamem_alloc()</function> but not - <function>bus_dmamap_create()</function> calls.</para> - </listitem> - - <listitem> - <para><emphasis>boundary</emphasis> - physical address - boundary that must not be crossed when allocating the - memory. Use value 0 for <quote>no boundary</quote>. Applies only to - the future <function>bus_dmamem_alloc()</function> but - not <function>bus_dmamap_create()</function> calls. - Must be power of 2. If the memory is planned to be used - in non-cascaded DMA mode (i.e., the DMA addresses will be - supplied not by the device itself but by the ISA DMA - controller) then the boundary must be no larger than - 64KB (64*1024) due to the limitations of the DMA - hardware.</para> - </listitem> - - <listitem> - <para><emphasis>lowaddr, highaddr</emphasis> - the names - are slightly misleading; these values are used to limit - the permitted range of physical addresses used to - allocate the memory. The exact meaning varies depending - on the planned future use:</para> - - <itemizedlist> - <listitem> - <para>For <function>bus_dmamem_alloc()</function> all - the addresses from 0 to lowaddr-1 are considered - permitted, the higher ones are forbidden.</para> - </listitem> - - <listitem> - <para>For <function>bus_dmamap_create()</function> all - the addresses outside the inclusive range [lowaddr; - highaddr] are considered accessible. The addresses - of pages inside the range are passed to the filter - function which decides if they are accessible. If no - filter function is supplied then all the range is - considered unaccessible.</para> - </listitem> - - <listitem> - <para>For the ISA devices the normal values (with no - filter function) are:</para> - <para>lowaddr = BUS_SPACE_MAXADDR_24BIT</para> - <para>highaddr = BUS_SPACE_MAXADDR</para> - </listitem> - </itemizedlist> - - </listitem> - - <listitem> - <para><emphasis>filter, filterarg</emphasis> - the filter - function and its argument. If NULL is passed for filter - then the whole range [lowaddr, highaddr] is considered - unaccessible when doing - <function>bus_dmamap_create()</function>. Otherwise the - physical address of each attempted page in range - [lowaddr; highaddr] is passed to the filter function - which decides if it is accessible. The prototype of the - filter function is: <function>int filterfunc(void *arg, - bus_addr_t paddr)</function>. It must return 0 if the - page is accessible, non-zero otherwise.</para> - </listitem> - - <listitem> - <para><emphasis>maxsize</emphasis> - the maximal size of - memory (in bytes) that may be allocated through this - tag. In case it is difficult to estimate or could be - arbitrarily big, the value for ISA devices would be - <literal>BUS_SPACE_MAXSIZE_24BIT</literal>.</para> - </listitem> - - <listitem> - <para><emphasis>nsegments</emphasis> - maximal number of - scatter-gather segments supported by the device. If - unrestricted then the value <literal>BUS_SPACE_UNRESTRICTED</literal> - should be used. This value is recommended for the parent - tags, the actual restrictions would then be specified - for the descendant tags. Tags with nsegments equal to - <literal>BUS_SPACE_UNRESTRICTED</literal> may not be used to actually load - maps, they may be used only as parent tags. The - practical limit for nsegments seems to be about 250-300, - higher values will cause kernel stack overflow (the hardware - can not normally support that many - scatter-gather buffers anyway).</para> - </listitem> - - <listitem> - <para><emphasis>maxsegsz</emphasis> - maximal size of a - scatter-gather segment supported by the device. The - maximal value for ISA device would be - <literal>BUS_SPACE_MAXSIZE_24BIT</literal>.</para> - </listitem> - - <listitem> - <para><emphasis>flags</emphasis> - a bitmap of flags. The - only interesting flags are:</para> - - <itemizedlist> - <listitem> - <para><emphasis>BUS_DMA_ALLOCNOW</emphasis> - requests - to allocate all the potentially needed bounce pages - when creating the tag.</para> - </listitem> - - <listitem> - <para><emphasis>BUS_DMA_ISA</emphasis> - mysterious - flag used only on Alpha machines. It is not defined - for the i386 machines. Probably it should be used - by all the ISA drivers for Alpha machines but it - looks like there are no such drivers yet.</para> - </listitem> - </itemizedlist> - </listitem> - - <listitem> - <para><emphasis>dmat</emphasis> - pointer to the storage - for the new tag to be returned.</para> - </listitem> - - </itemizedlist> - - </listitem> - - <listitem> <!-- Second entry in list alpha --> - <para><function>int bus_dma_tag_destroy(bus_dma_tag_t - dmat)</function></para> - - <para>Destroy a tag. Returns 0 on success, the error code - otherwise.</para> - - <para>dmat - the tag to be destroyed.</para> - - </listitem> - - <listitem> <!-- Third entry in list alpha --> - <para><function>int bus_dmamem_alloc(bus_dma_tag_t dmat, - void** vaddr, int flags, bus_dmamap_t - *mapp)</function></para> - - <para>Allocate an area of contiguous memory described by the - tag. The size of memory to be allocated is tag's maxsize. - Returns 0 on success, the error code otherwise. The result - still has to be loaded by - <function>bus_dmamap_load()</function> before being used to get - the physical address of the memory.</para> - - <itemizedlist> - <listitem> - <para> - <emphasis>dmat</emphasis> - the tag - </para> - </listitem> - <listitem> - <para> - <emphasis>vaddr</emphasis> - pointer to the storage - for the kernel virtual address of the allocated area - to be returned. - </para> - </listitem> - <listitem> - <para> - flags - a bitmap of flags. The only interesting flag is: - </para> - <itemizedlist> - <listitem> - <para> - <emphasis>BUS_DMA_NOWAIT</emphasis> - if the - memory is not immediately available return the - error. If this flag is not set then the routine - is allowed to sleep until the memory - becomes available. - </para> - </listitem> - </itemizedlist> - </listitem> - <listitem> - <para> - <emphasis>mapp</emphasis> - pointer to the storage - for the new map to be returned. - </para> - </listitem> - </itemizedlist> - </listitem> - - <listitem> <!-- Fourth entry in list alpha --> - <para> - <function>void bus_dmamem_free(bus_dma_tag_t dmat, void - *vaddr, bus_dmamap_t map)</function> - </para> - <para> - Free the memory allocated by - <function>bus_dmamem_alloc()</function>. At present, - freeing of the memory allocated with ISA restrictions is - not implemented. Due to this the recommended model - of use is to keep and re-use the allocated areas for as - long as possible. Do not lightly free some area and then - shortly allocate it again. That does not mean that - <function>bus_dmamem_free()</function> should not be - used at all: hopefully it will be properly implemented - soon. - </para> - - <itemizedlist> - <listitem> - <para><emphasis>dmat</emphasis> - the tag - </para> - </listitem> - <listitem> - <para> - <emphasis>vaddr</emphasis> - the kernel virtual - address of the memory - </para> - </listitem> - <listitem> - <para> - <emphasis>map</emphasis> - the map of the memory (as - returned from - <function>bus_dmamem_alloc()</function>) - </para> - </listitem> - </itemizedlist> - </listitem> - - <listitem> <!-- The fifth entry in list alpha --> - <para> - <function>int bus_dmamap_create(bus_dma_tag_t dmat, int - flags, bus_dmamap_t *mapp)</function> - </para> - <para> - Create a map for the tag, to be used in - <function>bus_dmamap_load()</function> later. Returns 0 - on success, the error code otherwise. - </para> - <itemizedlist> - <listitem> - <para> - <emphasis>dmat</emphasis> - the tag - </para> - </listitem> - <listitem> - <para> - <emphasis>flags</emphasis> - theoretically, a bit map - of flags. But no flags are defined yet, so at present - it will be always 0. - </para> - </listitem> - <listitem> - <para> - <emphasis>mapp</emphasis> - pointer to the storage - for the new map to be returned - </para> - </listitem> - </itemizedlist> - </listitem> - - <listitem> <!-- Sixth entry in the alpha list --> - <para> - <function>int bus_dmamap_destroy(bus_dma_tag_t dmat, - bus_dmamap_t map)</function> - </para> - <para> - Destroy a map. Returns 0 on success, the error code otherwise. - </para> - - <itemizedlist> - <listitem> - <para> - dmat - the tag to which the map is associated - </para> - </listitem> - <listitem> - <para> - map - the map to be destroyed - </para> - </listitem> - </itemizedlist> - </listitem> - - <listitem> <!-- Seventh entry in list alpha --> - <para> - <function>int bus_dmamap_load(bus_dma_tag_t dmat, - bus_dmamap_t map, void *buf, bus_size_t buflen, - bus_dmamap_callback_t *callback, void *callback_arg, int - flags)</function> - </para> - <para> - Load a buffer into the map (the map must be previously - created by <function>bus_dmamap_create()</function> or - <function>bus_dmamem_alloc()</function>). All the pages - of the buffer are checked for conformance to the tag - requirements and for those not conformant the bounce - pages are allocated. An array of physical segment - descriptors is built and passed to the callback - routine. This callback routine is then expected to - handle it in some way. The number of bounce buffers in - the system is limited, so if the bounce buffers are - needed but not immediately available the request will be - queued and the callback will be called when the bounce - buffers will become available. Returns 0 if the callback - was executed immediately or <errorname>EINPROGRESS</errorname> if the request - was queued for future execution. In the latter case the - synchronization with queued callback routine is the - responsibility of the driver. - </para> - <!--<blockquote>--> - <itemizedlist> - <listitem> - <para> - <emphasis>dmat</emphasis> - the tag - </para> - </listitem> - <listitem> - <para> - <emphasis>map</emphasis> - the map - </para> - </listitem> - <listitem> - <para> - <emphasis>buf</emphasis> - kernel virtual address of - the buffer - </para> - </listitem> - <listitem> - <para> - <emphasis>buflen</emphasis> - length of the buffer - </para> - </listitem> - <listitem> - <para> - <emphasis>callback</emphasis>,<function> - callback_arg</function> - the callback function and - its argument - </para> - </listitem> - </itemizedlist> - <!--</blockquote>--> - <para> - The prototype of callback function is: - </para> - <para> - <function>void callback(void *arg, bus_dma_segment_t - *seg, int nseg, int error)</function> - </para> - <!-- <blockquote> --> - <itemizedlist> - <listitem> - <para> - <emphasis>arg</emphasis> - the same as callback_arg - passed to <function>bus_dmamap_load()</function> - </para> - </listitem> - <listitem> - <para> - <emphasis>seg</emphasis> - array of the segment - descriptors - </para> - </listitem> - <listitem> - <para> - <emphasis>nseg</emphasis> - number of descriptors in - array - </para> - </listitem> - <listitem> - <para> - <emphasis>error</emphasis> - indication of the - segment number overflow: if it is set to <errorname>EFBIG</errorname> then - the buffer did not fit into the maximal number of - segments permitted by the tag. In this case only the - permitted number of descriptors will be in the - array. Handling of this situation is up to the - driver: depending on the desired semantics it can - either consider this an error or split the buffer in - two and handle the second part separately - </para> - </listitem> - </itemizedlist> - <!-- </blockquote> --> - <para> - Each entry in the segments array contains the fields: - </para> - - <!-- <blockquote> --> - <itemizedlist> - <listitem> - <para> - <emphasis>ds_addr</emphasis> - physical bus address - of the segment - </para> - </listitem> - <listitem> - <para> - <emphasis>ds_len</emphasis> - length of the segment - </para> - </listitem> - </itemizedlist> - <!-- </blockquote>--> - </listitem> - - <listitem> <!-- Eighth entry in alpha list --> - <para> - <function>void bus_dmamap_unload(bus_dma_tag_t dmat, - bus_dmamap_t map)</function> - </para> - <para>unload the map. - </para> - <!-- <blockquote> --> - <itemizedlist> - <listitem> - <para> - <emphasis>dmat</emphasis> - tag - </para> - </listitem> - <listitem> - <para> - <emphasis>map</emphasis> - loaded map - </para> - </listitem> - </itemizedlist> - <!-- </blockquote> --> - </listitem> - - <listitem> <!-- Ninth entry list alpha --> - <para> - <function>void bus_dmamap_sync (bus_dma_tag_t dmat, - bus_dmamap_t map, bus_dmasync_op_t op)</function> - </para> - <para> - Synchronise a loaded buffer with its bounce pages before - and after physical transfer to or from device. This is - the function that does all the necessary copying of data - between the original buffer and its mapped version. The - buffers must be synchronized both before and after doing - the transfer. - </para> - <!-- <blockquote> --> - <itemizedlist> - <listitem> - <para> - <emphasis>dmat</emphasis> - tag - </para> - </listitem> - <listitem> - <para> - <emphasis>map</emphasis> - loaded map - </para> - </listitem> - <listitem> - <para> - <emphasis>op</emphasis> - type of synchronization - operation to perform: - </para> - </listitem> - </itemizedlist> - <!-- <blockquote> --> - <itemizedlist> - <listitem> - <para> - <function>BUS_DMASYNC_PREREAD</function> - before - reading from device into buffer - </para> - </listitem> - <listitem> - <para> - <function>BUS_DMASYNC_POSTREAD</function> - after - reading from device into buffer - </para> - </listitem> - <listitem> - <para> - <function>BUS_DMASYNC_PREWRITE</function> - before - writing the buffer to device - </para> - </listitem> - <listitem> - <para> - <function>BUS_DMASYNC_POSTWRITE</function> - after - writing the buffer to device - </para> - </listitem> - </itemizedlist> - </listitem> - </itemizedlist> <!-- End of list alpha --> -<!-- </blockquote> -</blockquote> --> - - <para> - As of now PREREAD and POSTWRITE are null operations but that - may change in the future, so they must not be ignored in the - driver. Synchronization is not needed for the memory - obtained from <function>bus_dmamem_alloc()</function>. - </para> - <para> - Before calling the callback function from - <function>bus_dmamap_load()</function> the segment array is - stored in the stack. And it gets pre-allocated for the - maximal number of segments allowed by the tag. As a result of - this the practical limit for the number of segments on i386 - architecture is about 250-300 (the kernel stack is 4KB minus - the size of the user structure, size of a segment array - entry is 8 bytes, and some space must be left). Since the - array is allocated based on the maximal number this value - must not be set higher than really needed. Fortunately, for - most of hardware the maximal supported number of segments is - much lower. But if the driver wants to handle buffers with a - very large number of scatter-gather segments it should do - that in portions: load part of the buffer, transfer it to - the device, load next part of the buffer, and so on. - </para> - <para> - Another practical consequence is that the number of segments - may limit the size of the buffer. If all the pages in the - buffer happen to be physically non-contiguous then the - maximal supported buffer size for that fragmented case would - be (nsegments * page_size). For example, if a maximal number - of 10 segments is supported then on i386 maximal guaranteed - supported buffer size would be 40K. If a higher size is - desired then special tricks should be used in the driver. - </para> - <para> - If the hardware does not support scatter-gather at all or - the driver wants to support some buffer size even if it is - heavily fragmented then the solution is to allocate a - contiguous buffer in the driver and use it as intermediate - storage if the original buffer does not fit. - </para> - <para> - Below are the typical call sequences when using a map depend - on the use of the map. The characters -> are used to show - the flow of time. - </para> - <para> - For a buffer which stays practically fixed during all the - time between attachment and detachment of a device:</para> - <para> - bus_dmamem_alloc -> bus_dmamap_load -> ...use buffer... -> - -> bus_dmamap_unload -> bus_dmamem_free - </para> - - <para>For a buffer that changes frequently and is passed from - outside the driver: - - <!-- XXX is this correct? --> - <programlisting> bus_dmamap_create -> - -> bus_dmamap_load -> bus_dmamap_sync(PRE...) -> do transfer -> - -> bus_dmamap_sync(POST...) -> bus_dmamap_unload -> - ... - -> bus_dmamap_load -> bus_dmamap_sync(PRE...) -> do transfer -> - -> bus_dmamap_sync(POST...) -> bus_dmamap_unload -> - -> bus_dmamap_destroy </programlisting> - - </para> - <para> - When loading a map created by - <function>bus_dmamem_alloc()</function> the passed address - and size of the buffer must be the same as used in - <function>bus_dmamem_alloc()</function>. In this case it is - guaranteed that the whole buffer will be mapped as one - segment (so the callback may be based on this assumption) - and the request will be executed immediately (EINPROGRESS - will never be returned). All the callback needs to do in - this case is to save the physical address. - </para> - <para> - A typical example would be: - </para> - - <programlisting> static void - alloc_callback(void *arg, bus_dma_segment_t *seg, int nseg, int error) - { - *(bus_addr_t *)arg = seg[0].ds_addr; - } - - ... - int error; - struct somedata { - .... - }; - struct somedata *vsomedata; /* virtual address */ - bus_addr_t psomedata; /* physical bus-relative address */ - bus_dma_tag_t tag_somedata; - bus_dmamap_t map_somedata; - ... - - error=bus_dma_tag_create(parent_tag, alignment, - boundary, lowaddr, highaddr, /*filter*/ NULL, /*filterarg*/ NULL, - /*maxsize*/ sizeof(struct somedata), /*nsegments*/ 1, - /*maxsegsz*/ sizeof(struct somedata), /*flags*/ 0, - &tag_somedata); - if(error) - return error; - - error = bus_dmamem_alloc(tag_somedata, &vsomedata, /* flags*/ 0, - &map_somedata); - if(error) - return error; - - bus_dmamap_load(tag_somedata, map_somedata, (void *)vsomedata, - sizeof (struct somedata), alloc_callback, - (void *) &psomedata, /*flags*/0); </programlisting> - - <para> - Looks a bit long and complicated but that is the way to do - it. The practical consequence is: if multiple memory areas - are allocated always together it would be a really good idea - to combine them all into one structure and allocate as one - (if the alignment and boundary limitations permit). - </para> - <para> - When loading an arbitrary buffer into the map created by - <function>bus_dmamap_create()</function> special measures - must be taken to synchronize with the callback in case it - would be delayed. The code would look like: - </para> - - <programlisting> { - int s; - int error; - - s = splsoftvm(); - error = bus_dmamap_load( - dmat, - dmamap, - buffer_ptr, - buffer_len, - callback, - /*callback_arg*/ buffer_descriptor, - /*flags*/0); - if (error == EINPROGRESS) { - /* - * Do whatever is needed to ensure synchronization - * with callback. Callback is guaranteed not to be started - * until we do splx() or tsleep(). - */ - } - splx(s); - } </programlisting> - - <para> - Two possible approaches for the processing of requests are: - </para> - <para> - 1. If requests are completed by marking them explicitly as - done (such as the CAM requests) then it would be simpler to - put all the further processing into the callback driver - which would mark the request when it is done. Then not much - extra synchronization is needed. For the flow control - reasons it may be a good idea to freeze the request queue - until this request gets completed. - </para> - <para> - 2. If requests are completed when the function returns (such - as classic read or write requests on character devices) then - a synchronization flag should be set in the buffer - descriptor and <function>tsleep()</function> called. Later - when the callback gets called it will do its processing and - check this synchronization flag. If it is set then the - callback should issue a wakeup. In this approach the - callback function could either do all the needed processing - (just like the previous case) or simply save the segments - array in the buffer descriptor. Then after callback - completes the calling function could use this saved segments - array and do all the processing. - - </para> - </sect1> -<!--_________________________________________________________________________--> -<!--~~~~~~~~~~~~~~~~~~~~END OF SECTION~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> - - <sect1 xml:id="isa-driver-dma"> - <title>DMA</title> - <!-- Section Marked up by Wylie --> - - <indexterm><primary>Direct Memory Access (DMA)</primary></indexterm> - - <para> - The Direct Memory Access (DMA) is implemented in the ISA bus - through the DMA controller (actually, two of them but that is - an irrelevant detail). To make the early ISA devices simple - and cheap the logic of the bus control and address - generation was concentrated in the DMA controller. - Fortunately, FreeBSD provides a set of functions that mostly - hide the annoying details of the DMA controller from the - device drivers. - </para> - - <para> - The simplest case is for the fairly intelligent - devices. Like the bus master devices on PCI they can - generate the bus cycles and memory addresses all by - themselves. The only thing they really need from the DMA - controller is bus arbitration. So for this purpose they - pretend to be cascaded slave DMA controllers. And the only - thing needed from the system DMA controller is to enable the - cascaded mode on a DMA channel by calling the following - function when attaching the driver: - </para> - - <para> - <function>void isa_dmacascade(int channel_number)</function> - </para> - - <para> - All the further activity is done by programming the - device. When detaching the driver no DMA-related functions - need to be called. - </para> - - <para> - For the simpler devices things get more complicated. The - functions used are: - </para> - - <itemizedlist> - - <listitem> - <para> - <function>int isa_dma_acquire(int chanel_number)</function> - </para> - <para> - Reserve a DMA channel. Returns 0 on success or EBUSY - if the channel was already reserved by this or a - different driver. Most of the ISA devices are not able - to share DMA channels anyway, so normally this - function is called when attaching a device. This - reservation was made redundant by the modern interface - of bus resources but still must be used in addition to - the latter. If not used then later, other DMA routines - will panic. - </para> - </listitem> - - <listitem> - <para> - <function>int isa_dma_release(int chanel_number)</function> - </para> - <para> - Release a previously reserved DMA channel. No - transfers must be in progress when the channel is - released (in addition the device must not try to - initiate transfer after the channel is released). - </para> - </listitem> - - <listitem> - <para> - <function>void isa_dmainit(int chan, u_int - bouncebufsize)</function> - </para> - <para> - Allocate a bounce buffer for use with the specified - channel. The requested size of the buffer can not exceed - 64KB. This bounce buffer will be automatically used - later if a transfer buffer happens to be not - physically contiguous or outside of the memory - accessible by the ISA bus or crossing the 64KB - boundary. If the transfers will be always done from - buffers which conform to these conditions (such as - those allocated by - <function>bus_dmamem_alloc()</function> with proper - limitations) then <function>isa_dmainit()</function> - does not have to be called. But it is quite convenient - to transfer arbitrary data using the DMA controller. - The bounce buffer will automatically care of the - scatter-gather issues. - </para> - <!-- <blockquote> --> - <itemizedlist> - <listitem> - <para> - <emphasis>chan</emphasis> - channel number - </para> - </listitem> - <listitem> - <para> - <emphasis>bouncebufsize</emphasis> - size of the - bounce buffer in bytes - </para> - </listitem> - </itemizedlist> -<!-- </blockquote> --> -<!--</para> --> - </listitem> - - <listitem> - <para> - <function>void isa_dmastart(int flags, caddr_t addr, u_int - nbytes, int chan)</function> - </para> - <para> - Prepare to start a DMA transfer. This function must be - called to set up the DMA controller before actually - starting transfer on the device. It checks that the - buffer is contiguous and falls into the ISA memory - range, if not then the bounce buffer is automatically - used. If bounce buffer is required but not set up by - <function>isa_dmainit()</function> or too small for - the requested transfer size then the system will - panic. In case of a write request with bounce buffer - the data will be automatically copied to the bounce - buffer. - </para> - </listitem> - <listitem> - <para>flags - a bitmask determining the type of operation to - be done. The direction bits B_READ and B_WRITE are mutually - exclusive. - </para> - <!-- <blockquote> --> - <itemizedlist> - <listitem> - <para> - B_READ - read from the ISA bus into memory - </para> - </listitem> - <listitem> - <para> - B_WRITE - write from the memory to the ISA bus - </para> - </listitem> - <listitem> - <para> - B_RAW - if set then the DMA controller will remember - the buffer and after the end of transfer will - automatically re-initialize itself to repeat transfer - of the same buffer again (of course, the driver may - change the data in the buffer before initiating - another transfer in the device). If not set then the - parameters will work only for one transfer, and - <function>isa_dmastart()</function> will have to be - called again before initiating the next - transfer. Using B_RAW makes sense only if the bounce - buffer is not used. - </para> - </listitem> - </itemizedlist> -<!-- </blockquote> --> - </listitem> - <listitem> - <para> - addr - virtual address of the buffer - </para> - </listitem> - <listitem> - <para> - nbytes - length of the buffer. Must be less or equal to - 64KB. Length of 0 is not allowed: the DMA controller will - understand it as 64KB while the kernel code will - understand it as 0 and that would cause unpredictable - effects. For channels number 4 and higher the length must - be even because these channels transfer 2 bytes at a - time. In case of an odd length the last byte will not be - transferred. - </para> - </listitem> - <listitem> - <para> - chan - channel number - </para> - </listitem> - - <listitem> - <para> - <function>void isa_dmadone(int flags, caddr_t addr, int - nbytes, int chan)</function> - </para> - <para> - Synchronize the memory after device reports that transfer - is done. If that was a read operation with a bounce buffer - then the data will be copied from the bounce buffer to the - original buffer. Arguments are the same as for - <function>isa_dmastart()</function>. Flag B_RAW is - permitted but it does not affect - <function>isa_dmadone()</function> in any way. - </para> - </listitem> - - <listitem> - <para> - <function>int isa_dmastatus(int channel_number)</function> - </para> - <para> - Returns the number of bytes left in the current transfer - to be transferred. In case the flag B_READ was set in - <function>isa_dmastart()</function> the number returned - will never be equal to zero. At the end of transfer it - will be automatically reset back to the length of - buffer. The normal use is to check the number of bytes - left after the device signals that the transfer is - completed. If the number of bytes is not 0 then something - probably went wrong with that transfer. - </para> - </listitem> - - <listitem> - <para> - <function>int isa_dmastop(int channel_number)</function> - </para> - <para> - Aborts the current transfer and returns the number of - bytes left untransferred. - </para> - </listitem> - </itemizedlist> - </sect1> - - <sect1 xml:id="isa-driver-probe"> - <title>xxx_isa_probe</title> - <!-- Section marked up by Wylie --> - - <para> - This function probes if a device is present. If the driver - supports auto-detection of some part of device configuration - (such as interrupt vector or memory address) this - auto-detection must be done in this routine. - </para> - - <para> - As for any other bus, if the device cannot be detected or - is detected but failed the self-test or some other problem - happened then it returns a positive value of error. The - value <errorname>ENXIO</errorname> must be returned if the device is not - present. Other error values may mean other conditions. Zero - or negative values mean success. Most of the drivers return - zero as success. - </para> - - <para> - The negative return values are used when a PnP device - supports multiple interfaces. For example, an older - compatibility interface and a newer advanced interface which - are supported by different drivers. Then both drivers would - detect the device. The driver which returns a higher value - in the probe routine takes precedence (in other words, the - driver returning 0 has highest precedence, one returning -1 - is next, one returning -2 is after it and so on). In result - the devices which support only the old interface will be - handled by the old driver (which should return -1 from the - probe routine) while the devices supporting the new - interface as well will be handled by the new driver (which - should return 0 from the probe routine). - </para> - - <para> - The device descriptor struct xxx_softc is allocated by the - system before calling the probe routine. If the probe - routine returns an error the descriptor will be - automatically deallocated by the system. So if a probing - error occurs the driver must make sure that all the - resources it used during probe are deallocated and that - nothing keeps the descriptor from being safely - deallocated. If the probe completes successfully the - descriptor will be preserved by the system and later passed - to the routine <function>xxx_isa_attach()</function>. If a - driver returns a negative value it can not be sure that it - will have the highest priority and its attach routine will - be called. So in this case it also must release all the - resources before returning and if necessary allocate them - again in the attach routine. When - <function>xxx_isa_probe()</function> returns 0 releasing the - resources before returning is also a good idea and a - well-behaved driver should do so. But in cases where there is - some problem with releasing the resources the driver is - allowed to keep resources between returning 0 from the probe - routine and execution of the attach routine. - </para> - - <para> - A typical probe routine starts with getting the device - descriptor and unit: - </para> - - <programlisting> struct xxx_softc *sc = device_get_softc(dev); - int unit = device_get_unit(dev); - int pnperror; - int error = 0; - - sc->dev = dev; /* link it back */ - sc->unit = unit; </programlisting> - - <para> - Then check for the PnP devices. The check is carried out by - a table containing the list of PnP IDs supported by this - driver and human-readable descriptions of the device models - corresponding to these IDs. - </para> - - <programlisting> - pnperror=ISA_PNP_PROBE(device_get_parent(dev), dev, - xxx_pnp_ids); if(pnperror == ENXIO) return ENXIO; - </programlisting> - - <para> - The logic of ISA_PNP_PROBE is the following: If this card - (device unit) was not detected as PnP then ENOENT will be - returned. If it was detected as PnP but its detected ID does - not match any of the IDs in the table then ENXIO is - returned. Finally, if it has PnP support and it matches on - of the IDs in the table, 0 is returned and the appropriate - description from the table is set by - <function>device_set_desc()</function>. - </para> - - <para> - If a driver supports only PnP devices then the condition - would look like: - </para> - - <programlisting> if(pnperror != 0) - return pnperror; </programlisting> - - <para> - No special treatment is required for the drivers which do not - support PnP because they pass an empty PnP ID table and will - always get ENXIO if called on a PnP card. - </para> - - <para> - The probe routine normally needs at least some minimal set - of resources, such as I/O port number to find the card and - probe it. Depending on the hardware the driver may be able - to discover the other necessary resources automatically. The - PnP devices have all the resources pre-set by the PnP - subsystem, so the driver does not need to discover them by - itself. - </para> - - <para> - Typically the minimal information required to get access to - the device is the I/O port number. Then some devices allow - to get the rest of information from the device configuration - registers (though not all devices do that). So first we try - to get the port start value: - </para> - - <programlisting> sc->port0 = bus_get_resource_start(dev, - SYS_RES_IOPORT, 0 /*rid*/); if(sc->port0 == 0) return ENXIO; - </programlisting> - - <para> - The base port address is saved in the structure softc for - future use. If it will be used very often then calling the - resource function each time would be prohibitively slow. If - we do not get a port we just return an error. Some device - drivers can instead be clever and try to probe all the - possible ports, like this: - </para> - - <programlisting> - /* table of all possible base I/O port addresses for this device */ - static struct xxx_allports { - u_short port; /* port address */ - short used; /* flag: if this port is already used by some unit */ - } xxx_allports = { - { 0x300, 0 }, - { 0x320, 0 }, - { 0x340, 0 }, - { 0, 0 } /* end of table */ - }; - - ... - int port, i; - ... - - port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0 /*rid*/); - if(port !=0 ) { - for(i=0; xxx_allports[i].port!=0; i++) { - if(xxx_allports[i].used || xxx_allports[i].port != port) - continue; - - /* found it */ - xxx_allports[i].used = 1; - /* do probe on a known port */ - return xxx_really_probe(dev, port); - } - return ENXIO; /* port is unknown or already used */ - } - - /* we get here only if we need to guess the port */ - for(i=0; xxx_allports[i].port!=0; i++) { - if(xxx_allports[i].used) - continue; - - /* mark as used - even if we find nothing at this port - * at least we won't probe it in future - */ - xxx_allports[i].used = 1; - - error = xxx_really_probe(dev, xxx_allports[i].port); - if(error == 0) /* found a device at that port */ - return 0; - } - /* probed all possible addresses, none worked */ - return ENXIO;</programlisting> - - <para> - Of course, normally the driver's - <function>identify()</function> routine should be used for - such things. But there may be one valid reason why it may be - better to be done in <function>probe()</function>: if this - probe would drive some other sensitive device crazy. The - probe routines are ordered with consideration of the - <literal>sensitive</literal> flag: the sensitive devices get probed first and - the rest of the devices later. But the - <function>identify()</function> routines are called before - any probes, so they show no respect to the sensitive devices - and may upset them. - </para> - - <para> - Now, after we got the starting port we need to set the port - count (except for PnP devices) because the kernel does not - have this information in the configuration file. - </para> - - <programlisting> - if(pnperror /* only for non-PnP devices */ - && bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port0, - XXX_PORT_COUNT)<0) - return ENXIO;</programlisting> - - <para> - Finally allocate and activate a piece of port address space - (special values of start and end mean <quote>use those we set by - <function>bus_set_resource()</function></quote>): - </para> - - <programlisting> - sc->port0_rid = 0; - sc->port0_r = bus_alloc_resource(dev, SYS_RES_IOPORT, - &sc->port0_rid, - /*start*/ 0, /*end*/ ~0, /*count*/ 0, RF_ACTIVE); - - if(sc->port0_r == NULL) - return ENXIO;</programlisting> - - <para> - Now having access to the port-mapped registers we can poke - the device in some way and check if it reacts like it is - expected to. If it does not then there is probably some - other device or no device at all at this address. - </para> - - <para> - Normally drivers do not set up the interrupt handlers until - the attach routine. Instead they do probes in the polling - mode using the <function>DELAY()</function> function for - timeout. The probe routine must never hang forever, all the - waits for the device must be done with timeouts. If the - device does not respond within the time it is probably broken - or misconfigured and the driver must return error. When - determining the timeout interval give the device some extra - time to be on the safe side: although - <function>DELAY()</function> is supposed to delay for the - same amount of time on any machine it has some margin of - error, depending on the exact CPU. - </para> - - <para> - If the probe routine really wants to check that the - interrupts really work it may configure and probe the - interrupts too. But that is not recommended. - </para> - - <programlisting> - /* implemented in some very device-specific way */ - if(error = xxx_probe_ports(sc)) - goto bad; /* will deallocate the resources before returning */ - </programlisting> - - <para> - The function <function>xxx_probe_ports()</function> may also - set the device description depending on the exact model of - device it discovers. But if there is only one supported - device model this can be as well done in a hardcoded way. - Of course, for the PnP devices the PnP support sets the - description from the table automatically. - </para> - - - <programlisting> if(pnperror) - device_set_desc(dev, "Our device model 1234"); - </programlisting> - - <para> - Then the probe routine should either discover the ranges of - all the resources by reading the device configuration - registers or make sure that they were set explicitly by the - user. We will consider it with an example of on-board - memory. The probe routine should be as non-intrusive as - possible, so allocation and check of functionality of the - rest of resources (besides the ports) would be better left - to the attach routine. - </para> - - <para> - The memory address may be specified in the kernel - configuration file or on some devices it may be - pre-configured in non-volatile configuration registers. If - both sources are available and different, which one should - be used? Probably if the user bothered to set the address - explicitly in the kernel configuration file they know what - they are doing and this one should take precedence. An - example of implementation could be: - </para> - <programlisting> - /* try to find out the config address first */ - sc->mem0_p = bus_get_resource_start(dev, SYS_RES_MEMORY, 0 /*rid*/); - if(sc->mem0_p == 0) { /* nope, not specified by user */ - sc->mem0_p = xxx_read_mem0_from_device_config(sc); - - - if(sc->mem0_p == 0) - /* can't get it from device config registers either */ - goto bad; - } else { - if(xxx_set_mem0_address_on_device(sc) < 0) - goto bad; /* device does not support that address */ - } - - /* just like the port, set the memory size, - * for some devices the memory size would not be constant - * but should be read from the device configuration registers instead - * to accommodate different models of devices. Another option would - * be to let the user set the memory size as "msize" configuration - * resource which will be automatically handled by the ISA bus. - */ - if(pnperror) { /* only for non-PnP devices */ - sc->mem0_size = bus_get_resource_count(dev, SYS_RES_MEMORY, 0 /*rid*/); - if(sc->mem0_size == 0) /* not specified by user */ - sc->mem0_size = xxx_read_mem0_size_from_device_config(sc); - - if(sc->mem0_size == 0) { - /* suppose this is a very old model of device without - * auto-configuration features and the user gave no preference, - * so assume the minimalistic case - * (of course, the real value will vary with the driver) - */ - sc->mem0_size = 8*1024; - } - - if(xxx_set_mem0_size_on_device(sc) < 0) - goto bad; /* device does not support that size */ - - if(bus_set_resource(dev, SYS_RES_MEMORY, /*rid*/0, - sc->mem0_p, sc->mem0_size)<0) - goto bad; - } else { - sc->mem0_size = bus_get_resource_count(dev, SYS_RES_MEMORY, 0 /*rid*/); - } </programlisting> - - <para> - Resources for IRQ and DRQ are easy to check by analogy. - </para> - - <para> - If all went well then release all the resources and return success. - </para> - - <programlisting> xxx_free_resources(sc); - return 0;</programlisting> - - <para> - Finally, handle the troublesome situations. All the - resources should be deallocated before returning. We make - use of the fact that before the structure softc is passed to - us it gets zeroed out, so we can find out if some resource - was allocated: then its descriptor is non-zero. - </para> - - <programlisting> bad: - - xxx_free_resources(sc); - if(error) - return error; - else /* exact error is unknown */ - return ENXIO;</programlisting> - - <para> - That would be all for the probe routine. Freeing of - resources is done from multiple places, so it is moved to a - function which may look like: - </para> - -<programlisting>static void - xxx_free_resources(sc) - struct xxx_softc *sc; - { - /* check every resource and free if not zero */ - - /* interrupt handler */ - if(sc->intr_r) { - bus_teardown_intr(sc->dev, sc->intr_r, sc->intr_cookie); - bus_release_resource(sc->dev, SYS_RES_IRQ, sc->intr_rid, - sc->intr_r); - sc->intr_r = 0; - } - - /* all kinds of memory maps we could have allocated */ - if(sc->data_p) { - bus_dmamap_unload(sc->data_tag, sc->data_map); - sc->data_p = 0; - } - if(sc->data) { /* sc->data_map may be legitimately equal to 0 */ - /* the map will also be freed */ - bus_dmamem_free(sc->data_tag, sc->data, sc->data_map); - sc->data = 0; - } - if(sc->data_tag) { - bus_dma_tag_destroy(sc->data_tag); - sc->data_tag = 0; - } - - ... free other maps and tags if we have them ... - - if(sc->parent_tag) { - bus_dma_tag_destroy(sc->parent_tag); - sc->parent_tag = 0; - } - - /* release all the bus resources */ - if(sc->mem0_r) { - bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->mem0_rid, - sc->mem0_r); - sc->mem0_r = 0; - } - ... - if(sc->port0_r) { - bus_release_resource(sc->dev, SYS_RES_IOPORT, sc->port0_rid, - sc->port0_r); - sc->port0_r = 0; - } - }</programlisting> - - </sect1> - - <sect1 xml:id="isa-driver-attach"> - <title>xxx_isa_attach</title> - <!-- Section Marked up by Wylie --> - - <para>The attach routine actually connects the driver to the - system if the probe routine returned success and the system - had chosen to attach that driver. If the probe routine - returned 0 then the attach routine may expect to receive the - device structure softc intact, as it was set by the probe - routine. Also if the probe routine returns 0 it may expect - that the attach routine for this device shall be called at - some point in the future. If the probe routine returns a - negative value then the driver may make none of these - assumptions. - </para> - - <para>The attach routine returns 0 if it completed successfully or - error code otherwise. - </para> - - <para>The attach routine starts just like the probe routine, - with getting some frequently used data into more accessible - variables. - </para> - - <programlisting> struct xxx_softc *sc = device_get_softc(dev); - int unit = device_get_unit(dev); - int error = 0;</programlisting> - - <para>Then allocate and activate all the necessary - resources. As normally the port range will be released - before returning from probe, it has to be allocated - again. We expect that the probe routine had properly set all - the resource ranges, as well as saved them in the structure - softc. If the probe routine had left some resource allocated - then it does not need to be allocated again (which would be - considered an error). - </para> - - <programlisting> sc->port0_rid = 0; - sc->port0_r = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port0_rid, - /*start*/ 0, /*end*/ ~0, /*count*/ 0, RF_ACTIVE); - - if(sc->port0_r == NULL) - return ENXIO; - - /* on-board memory */ - sc->mem0_rid = 0; - sc->mem0_r = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem0_rid, - /*start*/ 0, /*end*/ ~0, /*count*/ 0, RF_ACTIVE); - - if(sc->mem0_r == NULL) - goto bad; - - /* get its virtual address */ - sc->mem0_v = rman_get_virtual(sc->mem0_r);</programlisting> - - <para>The DMA request channel (DRQ) is allocated likewise. To - initialize it use functions of the - <function>isa_dma*()</function> family. For example: - </para> - - <para><function>isa_dmacascade(sc->drq0);</function></para> - - <para>The interrupt request line (IRQ) is a bit - special. Besides allocation the driver's interrupt handler - should be associated with it. Historically in the old ISA - drivers the argument passed by the system to the interrupt - handler was the device unit number. But in modern drivers - the convention suggests passing the pointer to structure - softc. The important reason is that when the structures - softc are allocated dynamically then getting the unit number - from softc is easy while getting softc from the unit number is - difficult. Also this convention makes the drivers for - different buses look more uniform and allows them to share - the code: each bus gets its own probe, attach, detach and - other bus-specific routines while the bulk of the driver - code may be shared among them. - </para> - - <programlisting> - sc->intr_rid = 0; - sc->intr_r = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->intr_rid, - /*start*/ 0, /*end*/ ~0, /*count*/ 0, RF_ACTIVE); - - if(sc->intr_r == NULL) - goto bad; - - /* - * XXX_INTR_TYPE is supposed to be defined depending on the type of - * the driver, for example as INTR_TYPE_CAM for a CAM driver - */ - error = bus_setup_intr(dev, sc->intr_r, XXX_INTR_TYPE, - (driver_intr_t *) xxx_intr, (void *) sc, &sc->intr_cookie); - if(error) - goto bad; - - </programlisting> - - - <para>If the device needs to make DMA to the main memory then - this memory should be allocated like described before: - </para> - - <programlisting> error=bus_dma_tag_create(NULL, /*alignment*/ 4, - /*boundary*/ 0, /*lowaddr*/ BUS_SPACE_MAXADDR_24BIT, - /*highaddr*/ BUS_SPACE_MAXADDR, /*filter*/ NULL, /*filterarg*/ NULL, - /*maxsize*/ BUS_SPACE_MAXSIZE_24BIT, - /*nsegments*/ BUS_SPACE_UNRESTRICTED, - /*maxsegsz*/ BUS_SPACE_MAXSIZE_24BIT, /*flags*/ 0, - &sc->parent_tag); - if(error) - goto bad; - - /* many things get inherited from the parent tag - * sc->data is supposed to point to the structure with the shared data, - * for example for a ring buffer it could be: - * struct { - * u_short rd_pos; - * u_short wr_pos; - * char bf[XXX_RING_BUFFER_SIZE] - * } *data; - */ - error=bus_dma_tag_create(sc->parent_tag, 1, - 0, BUS_SPACE_MAXADDR, 0, /*filter*/ NULL, /*filterarg*/ NULL, - /*maxsize*/ sizeof(* sc->data), /*nsegments*/ 1, - /*maxsegsz*/ sizeof(* sc->data), /*flags*/ 0, - &sc->data_tag); - if(error) - goto bad; - - error = bus_dmamem_alloc(sc->data_tag, &sc->data, /* flags*/ 0, - &sc->data_map); - if(error) - goto bad; - - /* xxx_alloc_callback() just saves the physical address at - * the pointer passed as its argument, in this case &sc->data_p. - * See details in the section on bus memory mapping. - * It can be implemented like: - * - * static void - * xxx_alloc_callback(void *arg, bus_dma_segment_t *seg, - * int nseg, int error) - * { - * *(bus_addr_t *)arg = seg[0].ds_addr; - * } - */ - bus_dmamap_load(sc->data_tag, sc->data_map, (void *)sc->data, - sizeof (* sc->data), xxx_alloc_callback, (void *) &sc->data_p, - /*flags*/0);</programlisting> - - - <para>After all the necessary resources are allocated the - device should be initialized. The initialization may include - testing that all the expected features are functional.</para> - - <programlisting> if(xxx_initialize(sc) < 0) - goto bad; </programlisting> - - - <para>The bus subsystem will automatically print on the - console the device description set by probe. But if the - driver wants to print some extra information about the - device it may do so, for example:</para> - - <programlisting> - device_printf(dev, "has on-card FIFO buffer of %d bytes\n", sc->fifosize); - </programlisting> - - <para>If the initialization routine experiences any problems - then printing messages about them before returning error is - also recommended.</para> - - <para>The final step of the attach routine is attaching the - device to its functional subsystem in the kernel. The exact - way to do it depends on the type of the driver: a character - device, a block device, a network device, a CAM SCSI bus - device and so on.</para> - - <para>If all went well then return success.</para> - - <programlisting> error = xxx_attach_subsystem(sc); - if(error) - goto bad; - - return 0; </programlisting> - - <para>Finally, handle the troublesome situations. All the - resources should be deallocated before returning an - error. We make use of the fact that before the structure - softc is passed to us it gets zeroed out, so we can find out - if some resource was allocated: then its descriptor is - non-zero.</para> - - <programlisting> bad: - - xxx_free_resources(sc); - if(error) - return error; - else /* exact error is unknown */ - return ENXIO;</programlisting> - - <para>That would be all for the attach routine.</para> - - </sect1> - - - <sect1 xml:id="isa-driver-detach"> - <title>xxx_isa_detach</title> - - <para> - If this function is present in the driver and the driver is - compiled as a loadable module then the driver gets the - ability to be unloaded. This is an important feature if the - hardware supports hot plug. But the ISA bus does not support - hot plug, so this feature is not particularly important for - the ISA devices. The ability to unload a driver may be - useful when debugging it, but in many cases installation of - the new version of the driver would be required only after - the old version somehow wedges the system and a reboot will be - needed anyway, so the efforts spent on writing the detach - routine may not be worth it. Another argument that - unloading would allow upgrading the drivers on a production - machine seems to be mostly theoretical. Installing a new - version of a driver is a dangerous operation which should - never be performed on a production machine (and which is not - permitted when the system is running in secure mode). Still, - the detach routine may be provided for the sake of - completeness. - </para> - - <para> - The detach routine returns 0 if the driver was successfully - detached or the error code otherwise. - </para> - - <para> - The logic of detach is a mirror of the attach. The first - thing to do is to detach the driver from its kernel - subsystem. If the device is currently open then the driver - has two choices: refuse to be detached or forcibly close and - proceed with detach. The choice used depends on the ability - of the particular kernel subsystem to do a forced close and - on the preferences of the driver's author. Generally the - forced close seems to be the preferred alternative. - <programlisting> struct xxx_softc *sc = device_get_softc(dev); - int error; - - error = xxx_detach_subsystem(sc); - if(error) - return error;</programlisting> - </para> - <para> - Next the driver may want to reset the hardware to some - consistent state. That includes stopping any ongoing - transfers, disabling the DMA channels and interrupts to - avoid memory corruption by the device. For most of the - drivers this is exactly what the shutdown routine does, so - if it is included in the driver we can just call it. - </para> - <para><function>xxx_isa_shutdown(dev);</function></para> - - <para> - And finally release all the resources and return success. - <programlisting> xxx_free_resources(sc); - return 0;</programlisting> - - </para> - </sect1> - - <sect1 xml:id="isa-driver-shutdown"> - <title>xxx_isa_shutdown</title> - - <para> - This routine is called when the system is about to be shut - down. It is expected to bring the hardware to some - consistent state. For most of the ISA devices no special - action is required, so the function is not really necessary - because the device will be re-initialized on reboot - anyway. But some devices have to be shut down with a special - procedure, to make sure that they will be properly detected - after soft reboot (this is especially true for many devices - with proprietary identification protocols). In any case - disabling DMA and interrupts in the device registers and - stopping any ongoing transfers is a good idea. The exact - action depends on the hardware, so we do not consider it here - in any detail. - </para> - </sect1> - - <sect1 xml:id="isa-driver-intr"> - <title>xxx_intr</title> - - <indexterm><primary>interrupt handler</primary></indexterm> - - <para> - The interrupt handler is called when an interrupt is - received which may be from this particular device. The ISA - bus does not support interrupt sharing (except in some special - cases) so in practice if the interrupt handler is called - then the interrupt almost for sure came from its - device. Still, the interrupt handler must poll the device - registers and make sure that the interrupt was generated by - its device. If not it should just return. - </para> - - <para> - The old convention for the ISA drivers was getting the - device unit number as an argument. This is obsolete, and the - new drivers receive whatever argument was specified for them - in the attach routine when calling - <function>bus_setup_intr()</function>. By the new convention - it should be the pointer to the structure softc. So the - interrupt handler commonly starts as: - </para> - - <programlisting> - static void - xxx_intr(struct xxx_softc *sc) - { - - </programlisting> - - <para> - It runs at the interrupt priority level specified by the - interrupt type parameter of - <function>bus_setup_intr()</function>. That means that all - the other interrupts of the same type as well as all the - software interrupts are disabled. - </para> - - <para> - To avoid races it is commonly written as a loop: - </para> - - <programlisting> - while(xxx_interrupt_pending(sc)) { - xxx_process_interrupt(sc); - xxx_acknowledge_interrupt(sc); - } </programlisting> - - <para> - The interrupt handler has to acknowledge interrupt to the - device only but not to the interrupt controller, the system - takes care of the latter. - </para> - - </sect1> -</chapter> diff --git a/en_US.ISO8859-1/books/arch-handbook/jail/chapter.xml b/en_US.ISO8859-1/books/arch-handbook/jail/chapter.xml deleted file mode 100644 index a54476d45b..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/jail/chapter.xml +++ /dev/null @@ -1,794 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1"?> -<!-- - The FreeBSD Documentation Project - - $FreeBSD$ ---> -<chapter xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" - xml:id="jail"> - <info> - <title>The Jail Subsystem</title> - - <author> - <personname> - <firstname>Evan</firstname> - <surname>Sarmiento</surname> - </personname> - <affiliation> - <address> - <email>evms@cs.bu.edu</email> - </address> - </affiliation> - </author> - <copyright> - <year>2001</year> - <holder role="mailto:evms@cs.bu.edu">Evan Sarmiento</holder> - </copyright> - </info> - - <indexterm><primary>security</primary></indexterm> - <indexterm><primary>Jail</primary></indexterm> - <indexterm><primary>root</primary></indexterm> - - <para>On most &unix; systems, <literal>root</literal> has omnipotent - power. This promotes insecurity. If an attacker gained - <literal>root</literal> on a system, he would have every function - at his fingertips. In FreeBSD there are sysctls which dilute the - power of <literal>root</literal>, in order to minimize the damage - caused by an attacker. Specifically, one of these functions is - called <literal>secure levels</literal>. Similarly, another - function which is present from FreeBSD 4.0 and onward, is a - utility called &man.jail.8;. <application>Jail</application> - chroots an environment and sets certain restrictions on processes - which are forked within the <application>jail</application>. For - example, a jailed process cannot affect processes outside the - <application>jail</application>, utilize certain system calls, or - inflict any damage on the host environment.</para> - - <para><application>Jail</application> is becoming the new security - model. People are running potentially vulnerable servers such as - <application>Apache</application>, - <application>BIND</application>, and - <application>sendmail</application> within jails, so that if an - attacker gains <literal>root</literal> within the - <application>jail</application>, it is only an annoyance, and not - a devastation. This article mainly focuses on the internals - (source code) of <application>jail</application>. For information - on how to set up a jail see the <link - xlink:href="&url.books.handbook;/jails.html">handbook entry on - jails</link>.</para> - - <sect1 xml:id="jail-arch"> - <title>Architecture</title> - - <para><application>Jail</application> consists of two realms: the - userland program, &man.jail.8;, and the code implemented within - the kernel: the &man.jail.2; system call and associated - restrictions. I will be discussing the userland program and - then how <application>jail</application> is implemented within - the kernel.</para> - - <sect2> - <title>Userland Code</title> - - <indexterm><primary>Jail</primary> - <secondary>Userland Program</secondary></indexterm> - - <para>The source for the userland - <application>jail</application> is located in - <filename>/usr/src/usr.sbin/jail</filename>, consisting of one - file, <filename>jail.c</filename>. The program takes these - arguments: the path of the <application>jail</application>, - hostname, IP address, and the command to be executed.</para> - - <sect3> - <title>Data Structures</title> - - <para>In <filename>jail.c</filename>, the first thing I would - note is the declaration of an important structure - <literal>struct jail j;</literal> which was included from - <filename>/usr/include/sys/jail.h</filename>.</para> - - <para>The definition of the <literal>jail</literal> structure - is:</para> - - <programlisting><filename>/usr/include/sys/jail.h</filename>: - -struct jail { - u_int32_t version; - char *path; - char *hostname; - u_int32_t ip_number; -};</programlisting> - - <para>As you can see, there is an entry for each of the - arguments passed to the &man.jail.8; program, and indeed, - they are set during its execution.</para> - - <programlisting><filename>/usr/src/usr.sbin/jail/jail.c</filename> -char path[PATH_MAX]; -... -if (realpath(argv[0], path) == NULL) - err(1, "realpath: %s", argv[0]); -if (chdir(path) != 0) - err(1, "chdir: %s", path); -memset(&j, 0, sizeof(j)); -j.version = 0; -j.path = path; -j.hostname = argv[1];</programlisting> - </sect3> - - <sect3> - <title>Networking</title> - - <para>One of the arguments passed to the &man.jail.8; program - is an IP address with which the - <application>jail</application> can be accessed over the - network. &man.jail.8; translates the IP address given into - host byte order and then stores it in <literal>j</literal> - (the <literal>jail</literal> structure).</para> - - <programlisting><filename>/usr/src/usr.sbin/jail/jail.c</filename>: -struct in_addr in; -... -if (inet_aton(argv[2], &in) == 0) - errx(1, "Could not make sense of ip-number: %s", argv[2]); -j.ip_number = ntohl(in.s_addr);</programlisting> - - <para>The &man.inet.aton.3; function "interprets the specified - character string as an Internet address, placing the address - into the structure provided." The - <literal>ip_number</literal> member in the - <literal>jail</literal> structure is set only when the IP - address placed onto the <literal>in</literal> structure by - &man.inet.aton.3; is translated into host byte order by - &man.ntohl.3;.</para> - </sect3> - - <sect3> - <title>Jailing the Process</title> - - <para>Finally, the userland program jails the process. - <application>Jail</application> now becomes an imprisoned - process itself and then executes the command given using - &man.execv.3;.</para> - - <programlisting><filename>/usr/src/usr.sbin/jail/jail.c</filename> -i = jail(&j); -... -if (execv(argv[3], argv + 3) != 0) - err(1, "execv: %s", argv[3]);</programlisting> - - <para>As you can see, the <literal>jail()</literal> function - is called, and its argument is the <literal>jail</literal> - structure which has been filled with the arguments given to - the program. Finally, the program you specify is executed. - I will now discuss how <application>jail</application> is - implemented within the kernel.</para> - </sect3> - </sect2> - - <sect2> - <title>Kernel Space</title> - - <indexterm><primary>Jail</primary> - <secondary>Kernel Architecture</secondary></indexterm> - - <para>We will now be looking at the file - <filename>/usr/src/sys/kern/kern_jail.c</filename>. This is - the file where the &man.jail.2; system call, appropriate - sysctls, and networking functions are defined.</para> - - <sect3> - <title>Sysctls</title> - - <indexterm><primary>sysctl</primary></indexterm> - - <para>In <filename>kern_jail.c</filename>, the following - sysctls are defined:</para> - - <programlisting><filename>/usr/src/sys/kern/kern_jail.c:</filename> -int jail_set_hostname_allowed = 1; -SYSCTL_INT(_security_jail, OID_AUTO, set_hostname_allowed, CTLFLAG_RW, - &jail_set_hostname_allowed, 0, - "Processes in jail can set their hostnames"); - -int jail_socket_unixiproute_only = 1; -SYSCTL_INT(_security_jail, OID_AUTO, socket_unixiproute_only, CTLFLAG_RW, - &jail_socket_unixiproute_only, 0, - "Processes in jail are limited to creating UNIX/IPv4/route sockets only"); - -int jail_sysvipc_allowed = 0; -SYSCTL_INT(_security_jail, OID_AUTO, sysvipc_allowed, CTLFLAG_RW, - &jail_sysvipc_allowed, 0, - "Processes in jail can use System V IPC primitives"); - -static int jail_enforce_statfs = 2; -SYSCTL_INT(_security_jail, OID_AUTO, enforce_statfs, CTLFLAG_RW, - &jail_enforce_statfs, 0, - "Processes in jail cannot see all mounted file systems"); - -int jail_allow_raw_sockets = 0; -SYSCTL_INT(_security_jail, OID_AUTO, allow_raw_sockets, CTLFLAG_RW, - &jail_allow_raw_sockets, 0, - "Prison root can create raw sockets"); - -int jail_chflags_allowed = 0; -SYSCTL_INT(_security_jail, OID_AUTO, chflags_allowed, CTLFLAG_RW, - &jail_chflags_allowed, 0, - "Processes in jail can alter system file flags"); - -int jail_mount_allowed = 0; -SYSCTL_INT(_security_jail, OID_AUTO, mount_allowed, CTLFLAG_RW, - &jail_mount_allowed, 0, - "Processes in jail can mount/unmount jail-friendly file systems");</programlisting> - - <para>Each of these sysctls can be accessed by the user - through the &man.sysctl.8; program. Throughout the kernel, - these specific sysctls are recognized by their name. For - example, the name of the first sysctl is - <literal>security.jail.set_hostname_allowed</literal>.</para> - </sect3> - - <sect3> - <title>&man.jail.2; System Call</title> - - <para>Like all system calls, the &man.jail.2; system call - takes two arguments, <literal>struct thread *td</literal> - and <literal>struct jail_args *uap</literal>. - <literal>td</literal> is a pointer to the - <literal>thread</literal> structure which describes the - calling thread. In this context, <literal>uap</literal> is - a pointer to the structure in which a pointer to the - <literal>jail</literal> structure passed by the userland - <filename>jail.c</filename> is contained. When I described - the userland program before, you saw that the &man.jail.2; - system call was given a <literal>jail</literal> structure as - its own argument.</para> - - <programlisting><filename>/usr/src/sys/kern/kern_jail.c:</filename> -/* - * struct jail_args { - * struct jail *jail; - * }; - */ -int -jail(struct thread *td, struct jail_args *uap)</programlisting> - - <para>Therefore, <literal>uap->jail</literal> can be used - to access the <literal>jail</literal> structure which was - passed to the system call. Next, the system call copies the - <literal>jail</literal> structure into kernel space using - the &man.copyin.9; function. &man.copyin.9; takes three - arguments: the address of the data which is to be copied - into kernel space, <literal>uap->jail</literal>, where to - store it, <literal>j</literal> and the size of the storage. - The <literal>jail</literal> structure pointed by - <literal>uap->jail</literal> is copied into kernel space - and is stored in another <literal>jail</literal> structure, - <literal>j</literal>.</para> - - <programlisting><filename>/usr/src/sys/kern/kern_jail.c:</filename> -error = copyin(uap->jail, &j, sizeof(j));</programlisting> - - <para>There is another important structure defined in - <filename>jail.h</filename>. It is the - <literal>prison</literal> structure. The - <literal>prison</literal> structure is used exclusively - within kernel space. Here is the definition of the - <literal>prison</literal> structure.</para> - - <programlisting><filename>/usr/include/sys/jail.h</filename>: -struct prison { - LIST_ENTRY(prison) pr_list; /* (a) all prisons */ - int pr_id; /* (c) prison id */ - int pr_ref; /* (p) refcount */ - char pr_path[MAXPATHLEN]; /* (c) chroot path */ - struct vnode *pr_root; /* (c) vnode to rdir */ - char pr_host[MAXHOSTNAMELEN]; /* (p) jail hostname */ - u_int32_t pr_ip; /* (c) ip addr host */ - void *pr_linux; /* (p) linux abi */ - int pr_securelevel; /* (p) securelevel */ - struct task pr_task; /* (d) destroy task */ - struct mtx pr_mtx; - void **pr_slots; /* (p) additional data */ -};</programlisting> - - <para>The &man.jail.2; system call then allocates memory for a - <literal>prison</literal> structure and copies data between - the <literal>jail</literal> and <literal>prison</literal> - structure.</para> - - <programlisting><filename>/usr/src/sys/kern/kern_jail.c</filename>: -MALLOC(pr, struct prison *, sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); -... -error = copyinstr(j.path, &pr->pr_path, sizeof(pr->pr_path), 0); -if (error) - goto e_killmtx; -... -error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0); -if (error) - goto e_dropvnref; -pr->pr_ip = j.ip_number;</programlisting> - - <para>Next, we will discuss another important system call - &man.jail.attach.2;, which implements the function to put a - process into the <application>jail</application>.</para> - - <programlisting><filename>/usr/src/sys/kern/kern_jail.c</filename>: -/* - * struct jail_attach_args { - * int jid; - * }; - */ -int -jail_attach(struct thread *td, struct jail_attach_args *uap)</programlisting> - - <para>This system call makes the changes that can distinguish - a jailed process from those unjailed ones. To understand - what &man.jail.attach.2; does for us, certain background - information is needed.</para> - - <para>On FreeBSD, each kernel visible thread is identified by - its <literal>thread</literal> structure, while the processes - are described by their <literal>proc</literal> structures. - You can find the definitions of the - <literal>thread</literal> and <literal>proc</literal> - structure in <filename>/usr/include/sys/proc.h</filename>. - For example, the <literal>td</literal> argument in any - system call is actually a pointer to the calling thread's - <literal>thread</literal> structure, as stated before. The - <literal>td_proc</literal> member in the - <literal>thread</literal> structure pointed by - <literal>td</literal> is a pointer to the - <literal>proc</literal> structure which represents the - process that contains the thread represented by - <literal>td</literal>. The <literal>proc</literal> - structure contains members which can describe the owner's - identity(<literal>p_ucred</literal>), the process resource - limits(<literal>p_limit</literal>), and so on. In the - <literal>ucred</literal> structure pointed by - <literal>p_ucred</literal> member in the - <literal>proc</literal> structure, there is a pointer to the - <literal>prison</literal> - structure(<literal>cr_prison</literal>).</para> - - <programlisting><filename>/usr/include/sys/proc.h:</filename> -struct thread { - ... - struct proc *td_proc; - ... -}; -struct proc { - ... - struct ucred *p_ucred; - ... -}; -<filename>/usr/include/sys/ucred.h</filename> -struct ucred { - ... - struct prison *cr_prison; - ... -};</programlisting> - - <para>In <filename>kern_jail.c</filename>, the function - <literal>jail()</literal> then calls function - <literal>jail_attach()</literal> with a given - <literal>jid</literal>. And - <literal>jail_attach()</literal> calls function - <literal>change_root()</literal> to change the root - directory of the calling process. The - <literal>jail_attach()</literal> then creates a new - <literal>ucred</literal> structure, and attaches the newly - created <literal>ucred</literal> structure to the calling - process after it has successfully attached the - <literal>prison</literal> structure to the - <literal>ucred</literal> structure. From then on, the - calling process is recognized as jailed. When the kernel - routine <literal>jailed()</literal> is called in the kernel - with the newly created <literal>ucred</literal> structure as - its argument, it returns 1 to tell that the credential is - connected with a <application>jail</application>. The - public ancestor process of all the process forked within the - <application>jail</application>, is the process which runs - &man.jail.8;, as it calls the &man.jail.2; system call. - When a program is executed through &man.execve.2;, it - inherits the jailed property of its parent's - <literal>ucred</literal> structure, therefore it has a - jailed <literal>ucred</literal> structure.</para> - - <programlisting><filename>/usr/src/sys/kern/kern_jail.c</filename> -int -jail(struct thread *td, struct jail_args *uap) -{ -... - struct jail_attach_args jaa; -... - error = jail_attach(td, &jaa); - if (error) - goto e_dropprref; -... -} - -int -jail_attach(struct thread *td, struct jail_attach_args *uap) -{ - struct proc *p; - struct ucred *newcred, *oldcred; - struct prison *pr; -... - p = td->td_proc; -... - pr = prison_find(uap->jid); -... - change_root(pr->pr_root, td); -... - newcred->cr_prison = pr; - p->p_ucred = newcred; -... -}</programlisting> - - <para>When a process is forked from its parent process, the - &man.fork.2; system call uses <literal>crhold()</literal> to - maintain the credential for the newly forked process. It - inherently keep the newly forked child's credential - consistent with its parent, so the child process is also - jailed.</para> - - <programlisting><filename>/usr/src/sys/kern/kern_fork.c</filename>: -p2->p_ucred = crhold(td->td_ucred); -... -td2->td_ucred = crhold(p2->p_ucred);</programlisting> - </sect3> - </sect2> - </sect1> - - <sect1 xml:id="jail-restrictions"> - <title>Restrictions</title> - - <para>Throughout the kernel there are access restrictions relating - to jailed processes. Usually, these restrictions only check - whether the process is jailed, and if so, returns an error. For - example:</para> - - <programlisting>if (jailed(td->td_ucred)) - return (EPERM);</programlisting> - - <sect2> - <title>SysV IPC</title> - - <indexterm><primary>System V IPC</primary></indexterm> - - <para>System 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: &man.msgctl.3;, - &man.msgget.3;, &man.msgsnd.3; and &man.msgrcv.3;. Earlier, I - mentioned that there were certain sysctls you could turn on or - off in order to affect the behavior of - <application>jail</application>. One of these sysctls was - <literal>security.jail.sysvipc_allowed</literal>. By default, - this sysctl is set to 0. If it were set to 1, it would defeat - the whole purpose of having a <application>jail</application>; - privileged users from the <application>jail</application> - would be able to affect processes outside the jailed - environment. The difference between a message and a signal is - that the message only consists of the signal number.</para> - - <para><filename>/usr/src/sys/kern/sysv_msg.c</filename>:</para> - - <itemizedlist> - <listitem> - <para><literal>msgget(key, msgflg)</literal>: - <literal>msgget</literal> returns (and possibly creates) a - message descriptor that designates a message queue for use - in other functions.</para> - </listitem> - - <listitem> - <para><literal>msgctl(msgid, cmd, buf)</literal>: Using this - function, a process can query the status of a message - descriptor.</para> - </listitem> - - <listitem> - <para><literal>msgsnd(msgid, msgp, msgsz, msgflg)</literal>: - <literal>msgsnd</literal> sends a message to a - process.</para> - </listitem> - - <listitem> - <para><literal>msgrcv(msgid, msgp, msgsz, msgtyp, - msgflg)</literal>: a process receives messages using - this function</para> - </listitem> - </itemizedlist> - - <para>In each of the system calls corresponding to these - functions, there is this conditional:</para> - - <programlisting><filename>/usr/src/sys/kern/sysv_msg.c</filename>: -if (!jail_sysvipc_allowed && jailed(td->td_ucred)) - return (ENOSYS);</programlisting> - - <indexterm><primary>semaphores</primary></indexterm> - - <para>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 <application>jail</application>: - &man.semget.2;, &man.semctl.2; and &man.semop.2;.</para> - - <para><filename>/usr/src/sys/kern/sysv_sem.c</filename>:</para> - - <itemizedlist> - <listitem> - <para><literal>semctl(semid, semnum, cmd, ...)</literal>: - <literal>semctl</literal> does the specified - <literal>cmd</literal> on the semaphore queue indicated by - <literal>semid</literal>.</para></listitem> - - <listitem> - <para><literal>semget(key, nsems, flag)</literal>: - <literal>semget</literal> creates an array of semaphores, - corresponding to <literal>key</literal>.</para> - - <para><literal>key and flag take on the same meaning as they - do in msgget.</literal></para> - </listitem> - - <listitem><para><literal>semop(semid, array, nops)</literal>: - <literal>semop</literal> performs a group of operations - indicated by <literal>array</literal>, to the set of - semaphores identified by - <literal>semid</literal>.</para></listitem> - </itemizedlist> - - <indexterm><primary>shared memory</primary></indexterm> - - <para>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: &man.shmdt.2;, - &man.shmat.2;, &man.shmctl.2; and &man.shmget.2;.</para> - - <para><filename>/usr/src/sys/kern/sysv_shm.c</filename>:</para> - - <itemizedlist> - <listitem><para><literal>shmctl(shmid, cmd, buf)</literal>: - <literal>shmctl</literal> does various control operations - on the shared memory region identified by - <literal>shmid</literal>.</para> - </listitem> - - <listitem><para><literal>shmget(key, size, flag)</literal>: - <literal>shmget</literal> accesses or creates a shared - memory region of <literal>size</literal> - bytes.</para> - </listitem> - - <listitem><para><literal>shmat(shmid, addr, flag)</literal>: - <literal>shmat</literal> attaches a shared memory region - identified by <literal>shmid</literal> to the address - space of a process.</para> - </listitem> - - <listitem><para><literal>shmdt(addr)</literal>: - <literal>shmdt</literal> detaches the shared memory region - previously attached at - <literal>addr</literal>.</para> - </listitem> - </itemizedlist> - </sect2> - - <sect2> - <title>Sockets</title> - - <indexterm><primary>sockets</primary></indexterm> - - <para><application>Jail</application> 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 - <literal>security.jail.socket_unixiproute_only</literal> is - set. If set, sockets are only allowed to be created if the - family specified is either <literal>PF_LOCAL</literal>, - <literal>PF_INET</literal> or <literal>PF_ROUTE</literal>. - Otherwise, it returns an error.</para> - - <programlisting><filename>/usr/src/sys/kern/uipc_socket.c</filename>: -int -socreate(int dom, struct socket **aso, int type, int proto, - struct ucred *cred, struct thread *td) -{ - struct protosw *prp; -... - if (jailed(cred) && jail_socket_unixiproute_only && - prp->pr_domain->dom_family != PF_LOCAL && - prp->pr_domain->dom_family != PF_INET && - prp->pr_domain->dom_family != PF_ROUTE) { - return (EPROTONOSUPPORT); - } -... -}</programlisting> - </sect2> - - <sect2> - <title>Berkeley Packet Filter</title> - - <indexterm><primary>Berkeley Packet Filter</primary></indexterm> - <indexterm><primary>data link layer</primary></indexterm> - - <para>The <application>Berkeley Packet Filter</application> - provides a raw interface to data link layers in a protocol - independent fashion. <application>BPF</application> is now - controlled by the &man.devfs.8; whether it can be used in a - jailed environment.</para> - - </sect2> - - <sect2> - <title>Protocols</title> - - <indexterm><primary>protocols</primary></indexterm> - - <para>There 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 address only if the - <literal>nam</literal> parameter is set. - <literal>nam</literal> is a pointer to a - <literal>sockaddr</literal> structure, which describes the - address on which to bind the service. A more exact definition - is that <literal>sockaddr</literal> "may be used as a template - for referring to the identifying tag and length of each - address". In the function - <literal>in_pcbbind_setup()</literal>, <literal>sin</literal> - is a pointer to a <literal>sockaddr_in</literal> structure, - which contains the port, address, length and domain family of - the socket which is to be bound. Basically, this disallows - any processes from <application>jail</application> to be able - to specify the address that does not belong to the - <application>jail</application> in which the calling process - exists.</para> - - <programlisting><filename>/usr/src/sys/netinet/in_pcb.c</filename>: -int -in_pcbbind_setup(struct inpcb *inp, struct sockaddr *nam, in_addr_t *laddrp, - u_short *lportp, struct ucred *cred) -{ - ... - struct sockaddr_in *sin; - ... - if (nam) { - sin = (struct sockaddr_in *)nam; - ... - if (sin->sin_addr.s_addr != INADDR_ANY) - if (prison_ip(cred, 0, &sin->sin_addr.s_addr)) - return(EINVAL); - ... - if (lport) { - ... - if (prison && prison_ip(cred, 0, &sin->sin_addr.s_addr)) - return (EADDRNOTAVAIL); - ... - } - } - if (lport == 0) { - ... - if (laddr.s_addr != INADDR_ANY) - if (prison_ip(cred, 0, &laddr.s_addr)) - return (EINVAL); - ... - } -... - if (prison_ip(cred, 0, &laddr.s_addr)) - return (EINVAL); -... -}</programlisting> - - <para>You might be wondering what function - <literal>prison_ip()</literal> does. - <literal>prison_ip()</literal> is given three arguments, a - pointer to the credential(represented by - <literal>cred</literal>), any flags, and an IP address. It - returns 1 if the IP address does NOT belong to the - <application>jail</application> or 0 otherwise. As you can - see from the code, if it is indeed an IP address not belonging - to the <application>jail</application>, the protocol is not - allowed to bind to that address.</para> - - <programlisting><filename>/usr/src/sys/kern/kern_jail.c:</filename> -int -prison_ip(struct ucred *cred, int flag, u_int32_t *ip) -{ - u_int32_t tmp; - - if (!jailed(cred)) - return (0); - if (flag) - tmp = *ip; - else - tmp = ntohl(*ip); - if (tmp == INADDR_ANY) { - if (flag) - *ip = cred->cr_prison->pr_ip; - else - *ip = htonl(cred->cr_prison->pr_ip); - return (0); - } - if (tmp == INADDR_LOOPBACK) { - if (flag) - *ip = cred->cr_prison->pr_ip; - else - *ip = htonl(cred->cr_prison->pr_ip); - return (0); - } - if (cred->cr_prison->pr_ip != tmp) - return (1); - return (0); -}</programlisting> - </sect2> - - <sect2> - <title>Filesystem</title> - - <indexterm><primary>filesystem</primary></indexterm> - - <para>Even <literal>root</literal> users within the - <application>jail</application> are not allowed to unset or - modify any file flags, such as immutable, append-only, and - undeleteable flags, if the securelevel is greater than - 0.</para> - - <programlisting><filename>/usr/src/sys/ufs/ufs/ufs_vnops.c:</filename> -static int -ufs_setattr(ap) - ... -{ - ... - if (!priv_check_cred(cred, PRIV_VFS_SYSFLAGS, 0)) { - if (ip->i_flags - & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) { - error = securelevel_gt(cred, 0); - if (error) - return (error); - } - ... - } -} -<filename>/usr/src/sys/kern/kern_priv.c</filename> -int -priv_check_cred(struct ucred *cred, int priv, int flags) -{ - ... - error = prison_priv_check(cred, priv); - if (error) - return (error); - ... -} -<filename>/usr/src/sys/kern/kern_jail.c</filename> -int -prison_priv_check(struct ucred *cred, int priv) -{ - ... - switch (priv) { - ... - case PRIV_VFS_SYSFLAGS: - if (jail_chflags_allowed) - return (0); - else - return (EPERM); - ... - } - ... -}</programlisting> - </sect2> - </sect1> -</chapter> diff --git a/en_US.ISO8859-1/books/arch-handbook/kobj/chapter.xml b/en_US.ISO8859-1/books/arch-handbook/kobj/chapter.xml deleted file mode 100644 index e52d1603d4..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/kobj/chapter.xml +++ /dev/null @@ -1,304 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1"?> -<!-- - The FreeBSD Documentation Project - - $FreeBSD$ ---> -<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xml:id="kernel-objects"> - <title>Kernel Objects</title> - - <indexterm><primary>Kernel Objects</primary></indexterm> - <indexterm><primary>Object-Oriented</primary></indexterm> - <indexterm><primary>binary compatibility</primary></indexterm> - <para>Kernel Objects, or <firstterm>Kobj</firstterm> provides an - object-oriented C programming system for the kernel. As such the - data being operated on carries the description of how to operate - on it. This allows operations to be added and removed from an - interface at run time and without breaking binary - compatibility.</para> - - <sect1 xml:id="kernel-objects-term"> - <title>Terminology</title> - - <indexterm><primary>object</primary></indexterm> - <indexterm><primary>method</primary></indexterm> - <indexterm><primary>class</primary></indexterm> - <indexterm><primary>interface</primary></indexterm> - - <variablelist> - <varlistentry> - <term>Object</term> - <listitem><para>A set of data - data structure - data - allocation.</para> - </listitem> - </varlistentry> - <varlistentry> - <term>Method</term> - <listitem> - <para>An operation - function.</para> - </listitem> - </varlistentry> - <varlistentry> - <term>Class</term> - <listitem> - <para>One or more methods.</para> - </listitem> - </varlistentry> - <varlistentry> - <term>Interface</term> - <listitem> - <para>A standard set of one or more methods.</para> - </listitem> - </varlistentry> - </variablelist> - </sect1> - - <sect1 xml:id="kernel-objects-operation"> - <title>Kobj Operation</title> - - <para>Kobj works by generating descriptions of methods. Each - description holds a unique id as well as a default function. The - description's address is used to uniquely identify the method - within a class' method table.</para> - - <para>A class is built by creating a method table associating one - or more functions with method descriptions. Before use the class - is compiled. The compilation allocates a cache and associates it - with the class. A unique id is assigned to each method - description within the method table of the class if not already - done so by another referencing class compilation. For every - method to be used a function is generated by script to qualify - arguments and automatically reference the method description for - a lookup. The generated function looks up the method by using - the unique id associated with the method description as a hash - into the cache associated with the object's class. If the method - is not cached the generated function proceeds to use the class' - table to find the method. If the method is found then the - associated function within the class is used; otherwise, the - default function associated with the method description is - used.</para> - - <para>These indirections can be visualized as the - following:</para> - - <programlisting>object->cache<->class</programlisting> - - </sect1> - - <sect1 xml:id="kernel-objects-using"> - <title>Using Kobj</title> - - <sect2> - <title>Structures</title> - - <programlisting>struct kobj_method</programlisting> - </sect2> - - <sect2> - <title>Functions</title> - - <programlisting>void kobj_class_compile(kobj_class_t cls); -void kobj_class_compile_static(kobj_class_t cls, kobj_ops_t ops); -void kobj_class_free(kobj_class_t cls); -kobj_t kobj_create(kobj_class_t cls, struct malloc_type *mtype, int mflags); -void kobj_init(kobj_t obj, kobj_class_t cls); -void kobj_delete(kobj_t obj, struct malloc_type *mtype);</programlisting> - </sect2> - - <sect2> - <title>Macros</title> - - <programlisting>KOBJ_CLASS_FIELDS -KOBJ_FIELDS -DEFINE_CLASS(name, methods, size) -KOBJMETHOD(NAME, FUNC)</programlisting> - </sect2> - - <sect2> - <title>Headers</title> - - <programlisting><sys/param.h> -<sys/kobj.h></programlisting> - </sect2> - - <sect2> - <title>Creating an Interface Template</title> - - <indexterm><primary>Kernel Objects</primary> - <secondary>interface</secondary></indexterm> - - <para>The first step in using Kobj is to create an - Interface. Creating the interface involves creating a template - that the script - <filename>src/sys/kern/makeobjops.pl</filename> can use to - generate the header and code for the method declarations and - method lookup functions.</para> - - <para>Within this template the following keywords are used: - <literal>#include</literal>, <literal>INTERFACE</literal>, - <literal>CODE</literal>, <literal>METHOD</literal>, - <literal>STATICMETHOD</literal>, and - <literal>DEFAULT</literal>.</para> - - <para>The <literal>#include</literal> statement and what follows - it is copied verbatim to the head of the generated code - file.</para> - - <para>For example:</para> - - <programlisting>#include <sys/foo.h></programlisting> - - <para>The <literal>INTERFACE</literal> keyword is used to define - the interface name. This name is concatenated with each method - name as [interface name]_[method name]. Its syntax is - INTERFACE [interface name];.</para> - - <para>For example:</para> - - <programlisting>INTERFACE foo;</programlisting> - - <para>The <literal>CODE</literal> keyword copies its arguments - verbatim into the code file. Its syntax is - <literal>CODE { [whatever] };</literal></para> - - <para>For example:</para> - - <programlisting>CODE { - struct foo * foo_alloc_null(struct bar *) - { - return NULL; -} -};</programlisting> - - <para>The <literal>METHOD</literal> keyword describes a method. Its syntax is - <literal>METHOD [return type] [method name] { [object [, - arguments]] };</literal></para> - - <para>For example:</para> - - <programlisting>METHOD int bar { - struct object *; - struct foo *; - struct bar; -};</programlisting> - - <para>The <literal>DEFAULT</literal> keyword may follow the - <literal>METHOD</literal> keyword. It extends the - <literal>METHOD</literal> key word to include the default - function for method. The extended syntax is - <literal>METHOD [return type] [method name] { - [object; [other arguments]] }DEFAULT [default - function];</literal></para> - - <para>For example:</para> - - <programlisting>METHOD int bar { - struct object *; - struct foo *; - int bar; -} DEFAULT foo_hack;</programlisting> - - <para>The <literal>STATICMETHOD</literal> keyword is used like - the <literal>METHOD</literal> keyword except the kobj data is not - at the head of the object structure so casting to kobj_t would - be incorrect. Instead <literal>STATICMETHOD</literal> relies on the Kobj data being - referenced as 'ops'. This is also useful for calling - methods directly out of a class's method table.</para> - - <para>Other complete examples:</para> - - <programlisting>src/sys/kern/bus_if.m -src/sys/kern/device_if.m</programlisting> - - </sect2> - - <sect2> - <title>Creating a Class</title> - - <indexterm><primary>Kernel Objects</primary> - <secondary>class</secondary></indexterm> - - <para>The second step in using Kobj is to create a class. A - class consists of a name, a table of methods, and the size of - objects if Kobj's object handling facilities are used. To - create the class use the macro - <function>DEFINE_CLASS()</function>. To create the method - table create an array of kobj_method_t terminated by a NULL - entry. Each non-NULL entry may be created using the macro - <function>KOBJMETHOD()</function>.</para> - - <para>For example:</para> - - <programlisting>DEFINE_CLASS(fooclass, foomethods, sizeof(struct foodata)); - -kobj_method_t foomethods[] = { - KOBJMETHOD(bar_doo, foo_doo), - KOBJMETHOD(bar_foo, foo_foo), - { NULL, NULL} -};</programlisting> - - <para>The class must be <quote>compiled</quote>. Depending on - the state of the system at the time that the class is to be - initialized a statically allocated cache, <quote>ops - table</quote> have to be used. This can be accomplished by - declaring a <varname remap="structname">struct kobj_ops</varname> and using - <function>kobj_class_compile_static();</function> otherwise, - <function>kobj_class_compile()</function> should be used.</para> - </sect2> - - <sect2> - <title>Creating an Object</title> - - <indexterm><primary>Kernel Objects</primary> - <secondary>object</secondary></indexterm> - - <para>The third step in using Kobj involves how to define the - object. Kobj object creation routines assume that Kobj data is - at the head of an object. If this in not appropriate you will - have to allocate the object yourself and then use - <function>kobj_init()</function> on the Kobj portion of it; - otherwise, you may use <function>kobj_create()</function> to - allocate and initialize the Kobj portion of the object - automatically. <function>kobj_init()</function> may also be - used to change the class that an object uses.</para> - - <para>To integrate Kobj into the object you should use the macro - KOBJ_FIELDS.</para> - - <para>For example</para> - - <programlisting>struct foo_data { - KOBJ_FIELDS; - foo_foo; - foo_bar; -};</programlisting> - </sect2> - - <sect2> - <title>Calling Methods</title> - - <para>The last step in using Kobj is to simply use the generated - functions to use the desired method within the object's - class. This is as simple as using the interface name and the - method name with a few modifications. The interface name - should be concatenated with the method name using a '_' - between them, all in upper case.</para> - - <para>For example, if the interface name was foo and the method - was bar then the call would be:</para> - - <programlisting>[return value = ] FOO_BAR(object [, other parameters]);</programlisting> - - </sect2> - - <sect2> - <title>Cleaning Up</title> - - <para>When an object allocated through - <function>kobj_create()</function> is no longer needed - <function>kobj_delete()</function> may be called on it, and - when a class is no longer being used - <function>kobj_class_free()</function> may be called on it.</para> - </sect2> - </sect1> -</chapter> diff --git a/en_US.ISO8859-1/books/arch-handbook/locking/chapter.xml b/en_US.ISO8859-1/books/arch-handbook/locking/chapter.xml deleted file mode 100644 index e45f45ecf8..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/locking/chapter.xml +++ /dev/null @@ -1,391 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1"?> -<!-- - The FreeBSD Documentation Project - The FreeBSD SMP Next Generation Project - - $FreeBSD$ ---> -<chapter xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" - xml:id="locking"> - <title>Locking Notes</title> - - <indexterm> - <primary>SMP Next Generation Project</primary> - </indexterm> - - <para><emphasis>This chapter is maintained by the FreeBSD SMP Next - Generation Project.</emphasis></para> - - <indexterm><primary>locking</primary></indexterm> - <indexterm><primary>multi-processing</primary></indexterm> - <indexterm><primary>mutexes</primary></indexterm> - <indexterm><primary>lockmgr</primary></indexterm> - <indexterm><primary>atomic operations</primary></indexterm> - <para>This document outlines the locking used in the FreeBSD kernel - to permit effective multi-processing within the kernel. Locking - can be achieved via several means. Data structures can be - protected by mutexes or &man.lockmgr.9; locks. A few variables - are protected simply by always using atomic operations to access - them.</para> - - <sect1 xml:id="locking-mutexes"> - <title>Mutexes</title> - - <para>A mutex is simply a lock used to guarantee mutual exclusion. - Specifically, a mutex may only be owned by one entity at a time. - If another entity wishes to obtain a mutex that is already - owned, it must wait until the mutex is released. In the FreeBSD - kernel, mutexes are owned by processes.</para> - - <para>Mutexes may be recursively acquired, but they are intended - to be held for a short period of time. Specifically, one may - not sleep while holding a mutex. If you need to hold a lock - across a sleep, use a &man.lockmgr.9; lock.</para> - - <para>Each mutex has several properties of interest:</para> - - <variablelist> - <varlistentry> - <term>Variable Name</term> - <listitem> - <para>The name of the <type>struct mtx</type> variable in - the kernel source.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term>Logical Name</term> - <listitem> - <para>The name of the mutex assigned to it by - <function>mtx_init</function>. This name is displayed in - KTR trace messages and witness errors and warnings and is - used to distinguish mutexes in the witness code.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term>Type</term> - <listitem> - <para>The type of the mutex in terms of the - <constant>MTX_*</constant> flags. The meaning for each - flag is related to its meaning as documented in - &man.mutex.9;.</para> - - <variablelist> - <varlistentry> - <term><constant>MTX_DEF</constant></term> - <listitem> - <para>A sleep mutex</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><constant>MTX_SPIN</constant></term> - <listitem> - <para>A spin mutex</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><constant>MTX_RECURSE</constant></term> - <listitem> - <para>This mutex is allowed to recurse.</para> - </listitem> - </varlistentry> - </variablelist> - </listitem> - </varlistentry> - - <varlistentry> - <term>Protectees</term> - <listitem> - <para>A list of data structures or data structure members - that this entry protects. For data structure members, the - name will be in the form of <varname - remap="structname">structure name</varname>.<varname - remap="structfield">member name</varname>.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term>Dependent Functions</term> - <listitem> - <para>Functions that can only be called if this mutex is - held.</para> - </listitem> - </varlistentry> - </variablelist> - - <table frame="all" colsep="1" rowsep="1" pgwide="1"> - <title>Mutex List</title> - - <indexterm> - <primary>locks</primary> - <secondary>sched_lock</secondary> - </indexterm> - - <indexterm> - <primary>locks</primary> - <secondary>vm86pcb_lock</secondary> - </indexterm> - - <indexterm> - <primary>locks</primary> - <secondary>Giant</secondary> - </indexterm> - - <indexterm> - <primary>locks</primary> - <secondary>callout_lock</secondary> - </indexterm> - - <tgroup cols="5"> - <thead> - <row> - <entry>Variable Name</entry> - <entry>Logical Name</entry> - <entry>Type</entry> - <entry>Protectees</entry> - <entry>Dependent Functions</entry> - </row> - </thead> - - <!-- The scheduler lock --> - <tbody> - <row> - <entry>sched_lock</entry> - <entry> - <quote>sched lock</quote></entry> - <entry> - <constant>MTX_SPIN</constant> | - <constant>MTX_RECURSE</constant></entry> - <entry> - <varname>_gmonparam</varname>, - <varname>cnt.v_swtch</varname>, - <varname>cp_time</varname>, - <varname>curpriority</varname>, - <varname remap="structname">mtx</varname>.<varname - remap="structfield">mtx_blocked</varname>, - <varname remap="structname">mtx</varname>.<varname - remap="structfield">mtx_contested</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_procq</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_slpq</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_sflag</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_stat</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_estcpu</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_cpticks</varname> - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_pctcpu</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_wchan</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_wmesg</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_swtime</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_slptime</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_runtime</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_uu</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_su</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_iu</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_uticks</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_sticks</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_iticks</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_oncpu</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_lastcpu</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_rqindex</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_heldmtx</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_blocked</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_mtxname</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_contested</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_priority</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_usrpri</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_nativepri</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_nice</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_rtprio</varname>, - <varname>pscnt</varname>, - <varname>slpque</varname>, - <varname>itqueuebits</varname>, - <varname>itqueues</varname>, - <varname>rtqueuebits</varname>, - <varname>rtqueues</varname>, - <varname>queuebits</varname>, - <varname>queues</varname>, - <varname>idqueuebits</varname>, - <varname>idqueues</varname>, - <varname>switchtime</varname>, - <varname>switchticks</varname></entry> - <entry> - <function>setrunqueue</function>, - <function>remrunqueue</function>, - <function>mi_switch</function>, - <function>chooseproc</function>, - <function>schedclock</function>, - <function>resetpriority</function>, - <function>updatepri</function>, - <function>maybe_resched</function>, - <function>cpu_switch</function>, - <function>cpu_throw</function>, - <function>need_resched</function>, - <function>resched_wanted</function>, - <function>clear_resched</function>, - <function>aston</function>, - <function>astoff</function>, - <function>astpending</function>, - <function>calcru</function>, - <function>proc_compare</function></entry> - </row> - - <!-- The vm86 pcb lock --> - <row> - <entry>vm86pcb_lock</entry> - <entry><quote>vm86pcb lock</quote></entry> - <entry> - <constant>MTX_DEF</constant></entry> - <entry> - <varname>vm86pcb</varname></entry> - <entry> - <function>vm86_bioscall</function></entry> - </row> - - <!-- Giant --> - <row> - <entry>Giant</entry> - <entry><quote>Giant</quote></entry> - <entry> - <constant>MTX_DEF</constant> | - <constant>MTX_RECURSE</constant></entry> - <entry>nearly everything</entry> - <entry>lots</entry> - </row> - - <!-- The callout lock --> - <row> - <entry>callout_lock</entry> - <entry><quote>callout lock</quote></entry> - <entry> - <constant>MTX_SPIN</constant> | - <constant>MTX_RECURSE</constant></entry> - <entry> - <varname>callfree</varname>, - <varname>callwheel</varname>, - <varname>nextsoftcheck</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_itcallout</varname>, - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_slpcallout</varname>, - <varname>softticks</varname>, - <varname>ticks</varname></entry> - <entry></entry> - </row> - </tbody> - </tgroup> - </table> - </sect1> - - <sect1 xml:id="locking-sx"> - <title>Shared Exclusive Locks</title> - - <para>These locks provide basic reader-writer type functionality - and may be held by a sleeping process. Currently they are - backed by &man.lockmgr.9;.</para> - <indexterm> - <primary>locks</primary> - <secondary>shared exclusive</secondary> - </indexterm> - - <table> - <title>Shared Exclusive Lock List</title> - - <indexterm> - <primary>locks</primary> - <secondary>allproc_lock</secondary> - </indexterm> - <indexterm> - <primary>locks</primary> - <secondary>proctree_lock</secondary> - </indexterm> - - <tgroup cols="2"> - <thead> - <row> - <entry>Variable Name</entry> - <entry>Protectees</entry> - </row> - </thead> - <tbody> - <row> - <entry><varname>allproc_lock</varname></entry> - <entry> - <varname>allproc</varname> - <varname>zombproc</varname> - <varname>pidhashtbl</varname> - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_list</varname> - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_hash</varname> - <varname>nextpid</varname></entry> - </row> - - <row> - <entry><varname>proctree_lock</varname></entry> - <entry> - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_children</varname> - <varname remap="structname">proc</varname>.<varname - remap="structfield">p_sibling</varname></entry> - </row> - </tbody> - </tgroup> - </table> - </sect1> - - <sect1 xml:id="locking-atomic"> - <title>Atomically Protected Variables</title> - - <indexterm> - <primary>atomically protected variables</primary> - </indexterm> - - <para>An atomically protected variable is a special variable that - is not protected by an explicit lock. Instead, all data - accesses to the variables use special atomic operations as - described in &man.atomic.9;. Very few variables are treated - this way, although other synchronization primitives such as - mutexes are implemented with atomically protected - variables.</para> - - <itemizedlist> - <listitem> - <para><varname remap="structname">mtx</varname>.<varname - remap="structfield">mtx_lock</varname></para> - </listitem> - </itemizedlist> - </sect1> -</chapter> diff --git a/en_US.ISO8859-1/books/arch-handbook/mac.ent b/en_US.ISO8859-1/books/arch-handbook/mac.ent deleted file mode 100644 index 76a5938a76..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/mac.ent +++ /dev/null @@ -1,111 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1"?> -<!-- $FreeBSD$ --> - -<!ENTITY mac.mpo "mpo"> -<!ENTITY mac.thead ' - <colspec xmlns="http://docbook.org/ns/docbook" colname="first" colwidth="0"/> - <colspec xmlns="http://docbook.org/ns/docbook" colwidth="0"/> - <colspec xmlns="http://docbook.org/ns/docbook" colname="last" colwidth="0"/> - - <thead xmlns="http://docbook.org/ns/docbook"> - <row> - <entry>Parameter</entry> - <entry>Description</entry> - <entry>Locking</entry> - </row> - </thead> -'> - -<!ENTITY mac.externalize.paramdefs ' - <paramdef xmlns="http://docbook.org/ns/docbook">struct label *<parameter>label</parameter></paramdef> - <paramdef xmlns="http://docbook.org/ns/docbook">char *<parameter>element_name</parameter></paramdef> - <paramdef xmlns="http://docbook.org/ns/docbook">struct sbuf *<parameter>sb</parameter></paramdef> - <paramdef xmlns="http://docbook.org/ns/docbook">int <parameter>*claimed</parameter></paramdef> -'> - -<!ENTITY mac.externalize.tbody ' - <tbody xmlns="http://docbook.org/ns/docbook"> - <row> - <entry><parameter>label</parameter></entry> - <entry>Label to be externalized</entry> - </row> - - <row> - <entry><parameter>element_name</parameter></entry> - <entry>Name of the policy whose label should be externalized</entry> - </row> - - <row> - <entry><parameter>sb</parameter></entry> - <entry>String buffer to be filled with a text representation of - label</entry> - </row> - - <row> - <entry><parameter>claimed</parameter></entry> - <entry>Should be incremented when <parameter>element_data</parameter> - can be filled in.</entry> - </row> - </tbody> -'> - -<!ENTITY mac.externalize.para ' - <para xmlns="http://docbook.org/ns/docbook">Produce an externalized label based on the label structure passed. - An externalized label consists of a text representation of the label - contents that can be used with userland applications and read by the - user. Currently, all policies' <function>externalize</function> entry - points will be called, so the implementation should check the contents - of <parameter>element_name</parameter> before attempting to fill in - <parameter>sb</parameter>. If - <parameter>element_name</parameter> does not match the name of your - policy, simply return <returnvalue>0</returnvalue>. Only return nonzero - if an error occurs while externalizing the label data. Once the policy - fills in <parameter>element_data</parameter>, <varname>*claimed</varname> - should be incremented.</para> -'> - -<!ENTITY mac.internalize.paramdefs ' - <paramdef xmlns="http://docbook.org/ns/docbook">struct label *<parameter>label</parameter></paramdef> - <paramdef xmlns="http://docbook.org/ns/docbook">char *<parameter>element_name</parameter></paramdef> - <paramdef xmlns="http://docbook.org/ns/docbook">char *<parameter>element_data</parameter></paramdef> - <paramdef xmlns="http://docbook.org/ns/docbook">int *<parameter>claimed</parameter></paramdef> -'> - -<!ENTITY mac.internalize.tbody ' - <tbody xmlns="http://docbook.org/ns/docbook"> - <row> - <entry><parameter>label</parameter></entry> - <entry>Label to be filled in</entry> - </row> - - <row> - <entry><parameter>element_name</parameter></entry> - <entry>Name of the policy whose label should be internalized</entry> - </row> - - <row> - <entry><parameter>element_data</parameter></entry> - <entry>Text data to be internalized</entry> - </row> - - <row> - <entry><parameter>claimed</parameter></entry> - <entry>Should be incremented when data can be successfully - internalized.</entry> - </row> - </tbody> -'> - -<!ENTITY mac.internalize.para ' - <para xmlns="http://docbook.org/ns/docbook">Produce an internal label structure based on externalized label data - in text format. Currently, all policies' <function>internalize</function> - entry points are called when internalization is requested, so the - implementation should compare the contents of - <parameter>element_name</parameter> to its own name in order to be sure - it should be internalizing the data in <parameter>element_data</parameter>. - Just as in the <function>externalize</function> entry points, the entry - point should return <returnvalue>0</returnvalue> if - <parameter>element_name</parameter> does not match its own name, or when - data can successfully be internalized, in which case - <varname>*claimed</varname> should be incremented.</para> -'> diff --git a/en_US.ISO8859-1/books/arch-handbook/mac/chapter.xml b/en_US.ISO8859-1/books/arch-handbook/mac/chapter.xml deleted file mode 100644 index 9f1c6beb44..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/mac/chapter.xml +++ /dev/null @@ -1,8068 +0,0 @@ -<?xml version="1.0" encoding="iso-8859-1"?> -<!-- - Copyright (c) 2002-2005 Networks Associates Technology, Inc. - All rights reserved. - - This software was developed for the FreeBSD Project by - Chris Costello at Safeport Network Services and Network Associates Labs, - 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 and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form 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 SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``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 THE AUTHORS OR CONTRIBUTORS 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 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - $FreeBSD$ ---> -<chapter xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" - xml:id="mac"> - <info> - <title>The TrustedBSD MAC Framework</title> - - <authorgroup> - <author> - <personname> - <firstname>Chris</firstname> - <surname>Costello</surname> - </personname> - <affiliation> - <orgname>TrustedBSD Project</orgname> - <address> - <email>chris@FreeBSD.org</email> - </address> - </affiliation> - </author> - - <author> - <personname> - <firstname>Robert</firstname> - <surname>Watson</surname> - </personname> - <affiliation> - <orgname>TrustedBSD Project</orgname> - <address> - <email>rwatson@FreeBSD.org</email> - </address> - </affiliation> - </author> - </authorgroup> - </info> - - <sect1 xml:id="mac-copyright"> - <title>MAC Documentation Copyright</title> - - <para>This 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 (<quote>CBOSS</quote>), as part of the DARPA - CHATS research program.</para> - - <para>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:</para> - - <orderedlist> - <listitem> - <para>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.</para> - </listitem> - - <listitem> - <para>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.</para> - </listitem> - </orderedlist> - - <important> - <para>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.</para> - </important> - </sect1> - - <sect1 xml:id="mac-synopsis"> - <title>Synopsis</title> - - <para>FreeBSD 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 is 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 security policies, including the ability to easily - tag security labels (such as confidentiality information) onto - system objects.</para> - - <para>This chapter introduces the MAC policy framework and - provides documentation for a sample MAC policy module.</para> - </sect1> - - - <sect1 xml:id="mac-introduction"> - <title>Introduction</title> - - <para>The 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.</para> - - <para>This chapter provides information appropriate for developers - of policy modules, as well as potential consumers of MAC-enabled - environments, to learn about how the MAC Framework supports - access control extension of the kernel.</para> - </sect1> - - <sect1 xml:id="mac-background"> - <title>Policy Background</title> - - <para>Mandatory 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), Domain and - Type Enforcement (DTE), 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.</para> - - <para>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, which may use existing - security attributes, such as user and group IDs, as well as - extended attributes on files, and other system properties. 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.</para> - </sect1> - - <sect1 xml:id="mac-framework-kernel-arch"> - <title>MAC Framework Kernel Architecture</title> - - <para>The 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.</para> - - <sect2 xml:id="mac-framework-kernel-arch-elements"> - <title>Kernel Elements</title> - - <para>The MAC Framework contains a number of kernel - elements:</para> - - <itemizedlist> - <listitem> - <para>Framework management interfaces</para> - </listitem> - <listitem> - <para>Concurrency and synchronization primitives.</para> - </listitem> - <listitem> - <para>Policy registration</para> - </listitem> - <listitem> - <para>Extensible security label for kernel objects</para> - </listitem> - <listitem> - <para>Policy entry point composition operators</para> - </listitem> - <listitem> - <para>Label management primitives</para> - </listitem> - <listitem> - <para>Entry point API invoked by kernel services</para> - </listitem> - <listitem> - <para>Entry point API to policy modules</para> - </listitem> - <listitem> - <para>Entry points implementations (policy life cycle, - object life cycle/label management, access control - checks).</para> - </listitem> - <listitem> - <para>Policy-agnostic label-management system calls</para> - </listitem> - <listitem> - <para><function>mac_syscall()</function> multiplex system - call</para> - </listitem> - <listitem> - <para>Various security policies implemented as MAC policy - modules</para> - </listitem> - </itemizedlist> - </sect2> - - <sect2 xml:id="mac-framework-kernel-arch-management"> - <title>Framework Management Interfaces</title> - - <para>The TrustedBSD MAC Framework may be directly managed using - sysctl's, loader tunables, and system calls.</para> - - <para>In most cases, sysctl's and loader tunables of the same - name 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, several counters will be maintained tracking - label allocation. It is generally advisable 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, as they provide - greater granularity and greater operational consistency for - policy modules.</para> - - <para>Loading and unloading of policy modules is performed using - the system module management system calls and other system - interfaces, including boot loader variables; policy modules - will have the opportunity to influence load and unload events, - including preventing undesired unloading of the policy.</para> - </sect2> - - <sect2 xml:id="mac-framework-kernel-arch-synchronization"> - <title>Policy List Concurrency and Synchronization</title> - - <para>As the set of active policies may change at run-time, and - the invocation of entry points is non-atomic, synchronization - is required to prevent loading or unloading of policies while - an entry point invocation is in progress, freezing the set of - active 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. One side effect of this - synchronization model is that recursion into the MAC Framework - from within a policy module is permitted, although not - generally used.</para> - - <para>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). A compile-time option - is also provided which prevents any change in the set of - loaded policies at run-time, which eliminates the mutex - locking costs associated with supporting dynamically loaded - and unloaded policies as synchronization is no longer - required.</para> - - <para>As the MAC Framework is not permitted to block in some - entry points, a normal sleep lock cannot be used; as a result, - it is possible for the load or unload attempt to block for a - substantial period of time waiting for the framework to become - idle.</para> - </sect2> - - <sect2 xml:id="mac-framework-kernel-arch-label-synchronization"> - <title>Label Synchronization</title> - - <para>As kernel objects of interest may generally be accessed - from more than one thread at a time, and simultaneous entry of - more than one thread into the MAC Framework is permitted, - security attribute storage maintained by the MAC Framework is - carefully synchronized. In general, existing kernel - synchronization on kernel object data is used to protect MAC - Framework security labels on the object: for example, MAC - labels on sockets are protected using the existing socket - mutex. Likewise, semantics for concurrent access are - generally identical to those of the container objects: for - credentials, copy-on-write semantics are maintained for label - contents as with the remainder of the credential structure. - The MAC Framework asserts necessary locks on objects when - invoked with an object reference. Policy authors must be - aware of these synchronization semantics, as they will - sometimes limit the types of accesses permitted on labels: for - example, when a read-only reference to a credential is passed - to a policy via an entry point, only read operations are - permitted on the label state attached to the - credential.</para> - </sect2> - - <sect2 xml:id="mac-framework-kernel-arch-policy-synchronization"> - <title>Policy Synchronization and Concurrency</title> - - <para>Policy modules must be written to assume that many kernel - threads may simultaneously enter one more policy entry points - due to the parallel and preemptive nature of the FreeBSD - kernel. If the policy module makes use of mutable state, this - may require the use of synchronization primitives within the - policy to prevent inconsistent views on that state resulting - in incorrect operation of the policy. Policies will generally - be able to make use of existing FreeBSD synchronization - primitives for this purpose, including mutexes, sleep locks, - condition variables, and counting semaphores. However, - policies should be written to employ these primitives - carefully, respecting existing kernel lock orders, and - recognizing that some entry points are not permitted to sleep, - limiting the use of primitives in those entry points to - mutexes and wakeup operations.</para> - - <para>When policy modules call out to other kernel subsystems, - they will generally need to release any in-policy locks in - order to avoid violating the kernel lock order or risking lock - recursion. This will maintain policy locks as leaf locks in - the global lock order, helping to avoid deadlock.</para> - </sect2> - - <sect2 xml:id="mac-framework-kernel-arch-registration"> - <title>Policy Registration</title> - - <para>The 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 <literal>SYSINIT</literal> to - invoke a registration function; when a policy module is - unloaded, <literal>SYSINIT</literal> 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 is flagged as not - unloadable.</para> - </sect2> - - <sect2 xml:id="mac-framework-kernel-arch-entrypoints"> - <title>Entry Points</title> - - <para>Kernel services interact with the MAC Framework in two - ways: they invoke a series of APIs to notify the framework of - relevant events, and they provide a policy-agnostic label - structure pointer in security-relevant objects. The label - pointer 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 pointers 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). Most of these security critical - decisions will be explicit access control checks; however, - some affect more general decision functions such as packet - matching for sockets and label transition at program - execution.</para> - </sect2> - - <sect2 xml:id="mac-framework-kernel-arch-composition"> - <title>Policy Composition</title> - - <para>When 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 return success. As policies - may return a variety of error conditions (success, access - denied, object does not exist, ...), a precedence operator - selects the resulting error from the set of errors returned by - policies. In general, errors indicating that an object does - not exist will be preferred to errors indicating that access - to an object is denied. While it is not guaranteed that the - resulting composition will be useful or secure, we have found - that it is for many useful selections of policies. For - example, traditional trusted systems often ship with two or - more policies using a similar composition.</para> - </sect2> - - <sect2 xml:id="mac-framework-kernel-arch-labels"> - <title>Labeling Support</title> - - <para>As 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. By policy agnostic, - we mean that policy modules are able to completely define the - semantics of meta-data associated with an object. 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.</para> - - <para>In-memory labels are stored in slab-allocated <varname - remap="structname">struct label</varname>, which consists of - a fixed-length array of unions, each holding a <literal>void - *</literal> pointer and a <literal>long</literal>. 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 models. Direct - access to the object structure 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. The primary - exception to this rule is the process credential, which must - be manually dereferenced to access the credential label. This - may change in future revisions of the MAC Framework.</para> - - <para>Initialization entry points frequently include a sleeping - disposition flag indicating whether or not an initialization - is permitted to sleep; if sleeping is not permitted, a failure - may be returned to cancel allocation of the label (and hence - object). This may occur, for example, in the network stack - during interrupt handling, where sleeping is not permitted, or - while the caller holds a mutex. 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. The MAC Framework - guarantees that uninitialized label slots will hold a 0 or - NULL value, which policies may use to detect uninitialized - values. However, as allocation of Mbuf labels is conditional, - policies must also be able to handle a NULL label pointer for - Mbufs if they have been loaded dynamically.</para> - - <para>In the case of file system labels, special support is - provided for the persistent storage of security labels in - extended attributes. Where available, extended attribute - transactions are used to permit consistent compound updates of - security labels on vnodes--currently this support is present - only in the UFS2 file system. Policy authors may choose to - implement multilabel file system object labels using one (or - more) extended attributes. For efficiency reasons, the vnode - label (<literal>v_label</literal>) is a cache of any on-disk - label; policies are able to load values into the cache when - the vnode is instantiated, and update the cache as needed. As - a result, the extended attribute need not be directly accessed - with every access control check.</para> - - <note> - <para>Currently, if a labeled policy permits dynamic - unloading, its state slot cannot be reclaimed, which places - a strict (and relatively low) bound on the number of - unload-reload operations for labeled policies.</para> - </note> - </sect2> - - <sect2 xml:id="mac-framework-kernel-arch-syscalls"> - <title>System Calls</title> - - <para>The 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.</para> - - <para>The label management calls accept a label description - structure, <varname remap="structname">struct mac</varname>, - 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, simplifying user applications that must - manage labels.</para> - - <para>The following MAC-related system calls are present in the - FreeBSD kernel:</para> - - <itemizedlist> - <listitem> - <para><function>mac_get_proc()</function> may be used to - retrieve the label of the current process.</para> - </listitem> - - <listitem> - <para><function>mac_set_proc()</function> may be used to - request a change in the label of the current - process.</para> - </listitem> - - <listitem> - <para><function>mac_get_fd()</function> may be used to - retrieve the label of an object (file, socket, pipe, ...) - referenced by a file descriptor.</para> - </listitem> - - <listitem> - <para><function>mac_get_file()</function> may be used to - retrieve the label of an object referenced by a file - system path.</para> - </listitem> - - <listitem> - <para><function>mac_set_fd()</function> may be used to - request a change in the label of an object (file, socket, - pipe, ...) referenced by a file descriptor.</para> - </listitem> - - <listitem> - <para><function>mac_set_file()</function> may be used to - request a change in the label of an object referenced by a - file system path.</para> - </listitem> - - <listitem> - <para><function>mac_syscall()</function> permits policy - modules to create new system calls without modifying the - system call table; it accepts a target policy name, - operation number, and opaque argument for use by the - policy.</para> - </listitem> - - <listitem> - <para><function>mac_get_pid()</function> may be used to - request the label of another process by process id.</para> - </listitem> - - <listitem> - <para><function>mac_get_link()</function> is identical to - <function>mac_get_file()</function>, only it will not - follow a symbolic link if it is the final entry in the - path, so may be used to retrieve the label on a - symlink.</para> - </listitem> - - <listitem> - <para><function>mac_set_link()</function> is identical to - <function>mac_set_file()</function>, only it will not - follow a symbolic link if it is the final entry in a path, - so may be used to manipulate the label on a - symlink.</para> - </listitem> - - <listitem> - <para><function>mac_execve()</function> is identical to the - <function>execve()</function> system call, only it also - accepts a requested label to set the process label to when - beginning execution of a new program. This change in - label on execution is referred to as a - "transition".</para> - </listitem> - - <listitem> - <para><function>mac_get_peer()</function>, actually - implemented via a socket option, retrieves the label of a - remote peer on a socket, if available.</para> - </listitem> - </itemizedlist> - - <para>In addition to these system calls, the - <literal>SIOCSIGMAC</literal> and - <literal>SIOCSIFMAC</literal> network interface ioctls permit - the labels on network interfaces to be retrieved and - set.</para> - </sect2> - </sect1> - - <sect1 xml:id="mac-policy-architecture"> - <title>MAC Policy Architecture</title> - - <para>Security 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:</para> - - <itemizedlist> - <listitem> - <para>Optional configuration parameters for - policy.</para> - </listitem> - <listitem> - <para>Centralized implementation of the policy logic and - parameters.</para> - </listitem> - <listitem> - <para>Optional implementation of policy life cycle events, - such as initialization and destruction.</para> - </listitem> - <listitem> - <para>Optional support for initializing, maintaining, and - destroying labels on selected kernel - objects.</para> - </listitem> - <listitem> - <para>Optional support for user process inspection and - modification of labels on selected - objects.</para> - </listitem> - <listitem> - <para>Implementation of selected access control entry points - that are of interest to the policy.</para> - </listitem> - <listitem> - <para>Declaration of policy identity, module entry points, and - policy properties.</para> - </listitem> - </itemizedlist> - - <sect2 xml:id="mac-policy-declaration"> - <title>Policy Declaration</title> - - <para>Modules may be declared using the - <function>MAC_POLICY_SET()</function> 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.</para> - - <programlisting>static struct mac_policy_ops mac_<replaceable>policy</replaceable>_ops = -{ - .mpo_destroy = mac_<replaceable>policy</replaceable>_destroy, - .mpo_init = mac_<replaceable>policy</replaceable>_init, - .mpo_init_bpfdesc_label = mac_<replaceable>policy</replaceable>_init_bpfdesc_label, - .mpo_init_cred_label = mac_<replaceable>policy</replaceable>_init_label, -/* ... */ - .mpo_check_vnode_setutimes = mac_<replaceable>policy</replaceable>_check_vnode_setutimes, - .mpo_check_vnode_stat = mac_<replaceable>policy</replaceable>_check_vnode_stat, - .mpo_check_vnode_write = mac_<replaceable>policy</replaceable>_check_vnode_write, -};</programlisting> - - <para>The MAC policy entry point vector, - <varname>mac_<replaceable>policy</replaceable>_ops</varname> - 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 <symbol>.mpo_destroy</symbol> and - <symbol>.mpo_init</symbol> entry points. - <symbol>.mpo_init</symbol> 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. - <symbol>.mpo_destroy</symbol> 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.</para> - - <para>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.</para> - </sect2> - - <sect2 xml:id="mac-policy-flags"> - <title>Policy Flags</title> - - <para>The 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:</para> - - <variablelist> - <varlistentry> - <term>MPC_LOADTIME_FLAG_UNLOADOK</term> - - <listitem> - <para>This 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.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term>MPC_LOADTIME_FLAG_NOTLATE</term> - - <listitem> - <para>This 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.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term>MPC_LOADTIME_FLAG_LABELMBUFS</term> - - <listitem> - <para>This 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, - <literal>MAC_ALWAYS_LABEL_MBUF</literal>, 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.</para> - </listitem> - </varlistentry> - </variablelist> - - <note> - <para>Policies using the - <literal>MPC_LOADTIME_FLAG_LABELMBUFS</literal> without the - <literal>MPC_LOADTIME_FLAG_NOTLATE</literal> flag set must - be able to correctly handle <literal>NULL</literal> 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.</para> - </note> - </sect2> - - <sect2 xml:id="mac-policy-entry-points"> - <title>Policy Entry Points</title> - - <para>Four 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 <function>mac_syscall()</function> entry point is - provided so that policies may extend the kernel interface - without registering new system calls.</para> - - <para>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.</para> - - <para>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.</para> - </sect2> - </sect1> - - <sect1 xml:id="mac-entry-point-reference"> - <title>MAC Policy Entry Point Reference</title> - - <sect2 xml:id="mac-mpo-general"> - <title>General-Purpose Module Entry Points</title> - - <sect3 xml:id="mac-mpo-init"> - <title><function>&mac.mpo;_init</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_init</function></funcdef> - - <paramdef>struct mac_policy_conf - *<parameter>conf</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>conf</parameter></entry> - <entry>MAC policy definition</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Policy load event. The policy list mutex is held, so - sleep operations cannot be performed, and calls out to other - kernel subsystems must be made with caution. If potentially - sleeping memory allocations are required during policy - initialization, they should be made using a separate module - SYSINIT().</para> - </sect3> - - <sect3 xml:id="mpo-destroy"> - <title><function>&mac.mpo;_destroy</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_destroy</function></funcdef> - - <paramdef>struct mac_policy_conf - *<parameter>conf</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>conf</parameter></entry> - <entry>MAC policy definition</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Policy load event. The policy list mutex is held, so - caution should be applied.</para> - </sect3> - - <sect3 xml:id="mac-mpo-syscall"> - <title><function>&mac.mpo;_syscall</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_syscall</function></funcdef> - - <paramdef>struct thread - *<parameter>td</parameter></paramdef> - <paramdef>int <parameter>call</parameter></paramdef> - <paramdef>void *<parameter>arg</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> &mac.thead; - - <tbody> - <row> - <entry><parameter>td</parameter></entry> - <entry>Calling thread</entry> - </row> - - <row> - <entry><parameter>call</parameter></entry> - <entry>Policy-specific syscall number</entry> - </row> - - <row> - <entry><parameter>arg</parameter></entry> - <entry>Pointer to syscall arguments</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>This 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.</para> - - <note> - <para>Modules must currently perform the - <function>copyin()</function> of the syscall data on their - own.</para> - </note> - </sect3> - - <sect3 xml:id="mac-mpo-thread-userret"> - <title><function>&mac.mpo;_thread_userret</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_thread_userret</function></funcdef> - - <paramdef>struct thread - *<parameter>td</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>td</parameter></entry> - <entry>Returning thread</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <!-- XXX: Maybe rewrite this section. --> - <para>This entry point permits policy modules to perform - MAC-related events when a thread returns to user space, via - a system call return, trap return, or otherwise. This is - required for policies that have floating process labels, as - it is 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. To employ - this mechanism, intended changes to the process credential - label may be stored in the <literal>p_label</literal> - protected by a per-policy spin lock, and then set the - per-thread <literal>TDF_ASTPENDING</literal> flag and - per-process <literal>PS_MACPENDM</literal> flag to schedule - a call to the userret entry point. From this entry point, - the policy may create a replacement credential with less - concern about the locking context. Policy writers are - cautioned that event ordering relating to scheduling an AST - and the AST being performed may be complex and interlaced in - multithreaded applications.</para> - </sect3> - </sect2> - - <sect2 xml:id="mac-label-ops"> - <title>Label Operations</title> - - <sect3 xml:id="mac-mpo-init-bpfdesc"> - <title><function>&mac.mpo;_init_bpfdesc_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_init_bpfdesc_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>New label to apply</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Initialize the label on a newly instantiated bpfdesc - (BPF descriptor). Sleeping is permitted.</para> - </sect3> - - <sect3 xml:id="mac-mpo-init-cred-label"> - <title><function>&mac.mpo;_init_cred_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_init_cred_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>New label to initialize</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Initialize the label for a newly instantiated user - credential. Sleeping is permitted.</para> - </sect3> - - <sect3 xml:id="mac-mpo-init-devfsdirent"> - <title><function>&mac.mpo;_init_devfsdirent_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_init_devfsdirent_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>New label to apply</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Initialize the label on a newly instantiated devfs - entry. Sleeping is permitted.</para> - </sect3> - - <sect3 xml:id="mac-mpo-init-ifnet"> - <title><function>&mac.mpo;_init_ifnet_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_init_ifnet_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>New label to apply</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Initialize the label on a newly instantiated network - interface. Sleeping is permitted.</para> - </sect3> - - <sect3 xml:id="mac-mpo-init-ipq"> - <title><function>&mac.mpo;_init_ipq_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_init_ipq_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>int <parameter>flag</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>New label to apply</entry> - </row> - - <row> - <entry><parameter>flag</parameter></entry> - <entry>Sleeping/non-sleeping &man.malloc.9;; see - below</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Initialize the label on a newly instantiated IP fragment - reassembly queue. The <parameter>flag</parameter> field may - be one of <symbol>M_WAITOK</symbol> and - <symbol>M_NOWAIT</symbol>, and should be employed to avoid - performing a sleeping &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 sleeping or long-lived operations. This entry point - is permitted to fail resulting in the failure to allocate - the IP fragment reassembly queue.</para> - </sect3> - - <sect3 xml:id="mac-mpo-init-mbuf"> - <title><function>&mac.mpo;_init_mbuf_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_init_mbuf_label</function></funcdef> - - <paramdef>int <parameter>flag</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>flag</parameter></entry> - <entry>Sleeping/non-sleeping &man.malloc.9;; see - below</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label to initialize</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Initialize the label on a newly instantiated mbuf packet - header (<parameter>mbuf</parameter>). The - <parameter>flag</parameter> field may be one of - <symbol>M_WAITOK</symbol> and <symbol>M_NOWAIT</symbol>, and - should be employed to avoid performing a sleeping - &man.malloc.9; during this initialization call. Mbuf - allocation frequently occurs in performance sensitive - environments, and the implementation should be careful to - avoid sleeping or long-lived operations. This entry point - is permitted to fail resulting in the failure to allocate - the mbuf header.</para> - </sect3> - - <sect3 xml:id="mac-mpo-init-mount"> - <title><function>&mac.mpo;_init_mount_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_init_mount_label</function></funcdef> - - <paramdef>struct label - *<parameter>mntlabel</parameter></paramdef> - <paramdef>struct label - *<parameter>fslabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <!-- XXX: Wording on label descriptions. --> - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>mntlabel</parameter></entry> - <entry>Policy label to be initialized for the mount - itself</entry> - </row> - - <row> - <entry><parameter>fslabel</parameter></entry> - <entry>Policy label to be initialized for the file - system</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Initialize the labels on a newly instantiated mount - point. Sleeping is permitted.</para> - </sect3> - - <sect3 xml:id="mac-mpo-init-mount-fs-label"> - <title><function>&mac.mpo;_init_mount_fs_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_init_mount_fs_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>Label to be initialized</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Initialize the label on a newly mounted file system. - Sleeping is permitted</para> - </sect3> - - <sect3 xml:id="mac-mpo-init-pipe-label"> - <title><function>&mac.mpo;_init_pipe_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_init_pipe_label</function></funcdef> - - <paramdef>struct - label*<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>Label to be filled in</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Initialize a label for a newly instantiated pipe. - Sleeping is permitted.</para> - </sect3> - - <sect3 xml:id="mac-mpo-init-socket"> - <title><function>&mac.mpo;_init_socket_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_init_socket_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>int <parameter>flag</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>New label to initialize</entry> - </row> - - <row> - <entry><parameter>flag</parameter></entry> - <entry>&man.malloc.9; flags</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Initialize a label for a newly instantiated socket. The - <parameter>flag</parameter> field may be one of - <symbol>M_WAITOK</symbol> and <symbol>M_NOWAIT</symbol>, and - should be employed to avoid performing a sleeping - &man.malloc.9; during this initialization call.</para> - </sect3> - - <sect3 xml:id="mac-mpo-init-socket-peer-label"> - <title><function>&mac.mpo;_init_socket_peer_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_init_socket_peer_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>int <parameter>flag</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>New label to initialize</entry> - </row> - - <row> - <entry><parameter>flag</parameter></entry> - <entry>&man.malloc.9; flags</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Initialize the peer label for a newly instantiated - socket. The <parameter>flag</parameter> field may be one of - <symbol>M_WAITOK</symbol> and <symbol>M_NOWAIT</symbol>, and - should be employed to avoid performing a sleeping - &man.malloc.9; during this initialization call.</para> - </sect3> - - <sect3 xml:id="mac-mpo-init-proc-label"> - <title><function>&mac.mpo;_init_proc_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_init_proc_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>New label to initialize</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Initialize the label for a newly instantiated process. - Sleeping is permitted.</para> - </sect3> - - - <sect3 xml:id="mac-mpo-init-vnode"> - <title><function>&mac.mpo;_init_vnode_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_init_vnode_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>New label to initialize</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Initialize the label on a newly instantiated vnode. - Sleeping is permitted.</para> - </sect3> - - <sect3 xml:id="mac-mpo-destroy-bpfdesc"> - <title><function>&mac.mpo;_destroy_bpfdesc_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_destroy_bpfdesc_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>bpfdesc label</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Destroy the label on a BPF descriptor. In this entry - point a policy should free any internal storage associated - with <parameter>label</parameter> so that it may be - destroyed.</para> - </sect3> - - <sect3 xml:id="mac-mpo-destroy-cred"> - <title><function>&mac.mpo;_destroy_cred_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_destroy_cred_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>Label being destroyed</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Destroy the label on a credential. In this entry point, - a policy module should free any internal storage associated - with <parameter>label</parameter> so that it may be - destroyed.</para> - </sect3> - - <sect3 xml:id="mac-mpo-destroy-devfsdirent"> - <title><function>&mac.mpo;_destroy_devfsdirent_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_destroy_devfsdirent_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>Label being destroyed</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Destroy the label on a devfs entry. In this entry - point, a policy module should free any internal storage - associated with <parameter>label</parameter> so that it may - be destroyed.</para> - </sect3> - - <sect3 xml:id="mac-mpo-destroy-ifnet-label"> - <title><function>&mac.mpo;_destroy_ifnet_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_destroy_ifnet_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>Label being destroyed</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Destroy the label on a removed interface. In this entry - point, a policy module should free any internal storage - associated with <parameter>label</parameter> so that it may - be destroyed.</para> - </sect3> - - <sect3 xml:id="mac-mpo-destroy-ipq-label"> - <title><function>&mac.mpo;_destroy_ipq_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_destroy_ipq_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>Label being destroyed</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Destroy the label on an IP fragment queue. In this - entry point, a policy module should free any internal - storage associated with <parameter>label</parameter> so that - it may be destroyed.</para> - </sect3> - - <sect3 xml:id="mac-mpo-destroy-mbuf-label"> - <title><function>&mac.mpo;_destroy_mbuf_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_destroy_mbuf_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>Label being destroyed</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Destroy the label on an mbuf header. In this entry - point, a policy module should free any internal storage - associated with <parameter>label</parameter> so that it may - be destroyed.</para> - </sect3> - - <sect3 xml:id="mac-mpo-destroy-mount-label"> - <title><function>&mac.mpo;_destroy_mount_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_destroy_mount_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>Mount point label being destroyed</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Destroy the labels on a mount point. In this entry - point, a policy module should free the internal storage - associated with <parameter>mntlabel</parameter> so that they - may be destroyed.</para> - </sect3> - - <sect3 xml:id="mac-mpo-destroy-mount"> - <title><function>&mac.mpo;_destroy_mount_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_destroy_mount_label</function></funcdef> - - <paramdef>struct label - *<parameter>mntlabel</parameter></paramdef> - <paramdef>struct label - *<parameter>fslabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>mntlabel</parameter></entry> - <entry>Mount point label being destroyed</entry> - </row> - - <row> - <entry><parameter>fslabel</parameter></entry> - <entry>File system label being destroyed></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Destroy the labels on a mount point. In this entry - point, a policy module should free the internal storage - associated with <parameter>mntlabel</parameter> and - <parameter>fslabel</parameter> so that they may be - destroyed.</para> - </sect3> - - <sect3 xml:id="mac-mpo-destroy-socket"> - <title><function>&mac.mpo;_destroy_socket_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_destroy_socket_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>Socket label being destroyed</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Destroy the label on a socket. In this entry point, a - policy module should free any internal storage associated - with <parameter>label</parameter> so that it may be - destroyed.</para> - </sect3> - - <sect3 xml:id="mac-mpo-destroy-socket-peer-label"> - <title><function>&mac.mpo;_destroy_socket_peer_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_destroy_socket_peer_label</function></funcdef> - - <paramdef>struct label - *<parameter>peerlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>peerlabel</parameter></entry> - <entry>Socket peer label being destroyed</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Destroy the peer label on a socket. In this entry - point, a policy module should free any internal storage - associated with <parameter>label</parameter> so that it may - be destroyed.</para> - </sect3> - - <sect3 xml:id="mac-mpo-destroy-pipe-label"> - <title><function>&mac.mpo;_destroy_pipe_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_destroy_pipe_label</function></funcdef> - - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>Pipe label</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Destroy the label on a pipe. In this entry point, a - policy module should free any internal storage associated - with <parameter>label</parameter> so that it may be - destroyed.</para> - </sect3> - - <sect3 xml:id="mac-mpo-destroy-proc-label"> - <title><function>&mac.mpo;_destroy_proc_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_destroy_proc_label</function></funcdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>Process label</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Destroy the label on a process. In this entry point, a - policy module should free any internal storage associated - with <parameter>label</parameter> so that it may be - destroyed.</para> - </sect3> - - <sect3 xml:id="mac-mpo-destroy-vnode-label"> - <title><function>&mac.mpo;_destroy_vnode_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_destroy_vnode_label</function></funcdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>label</parameter></entry> - <entry>Process label</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Destroy the label on a vnode. In this entry point, a - policy module should free any internal storage associated - with <parameter>label</parameter> so that it may be - destroyed.</para> - </sect3> - - <sect3 xml:id="mac-mpo-copy-mbuf-label"> - <title><function>&mac.mpo;_copy_mbuf_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_copy_mbuf_label</function></funcdef> - - <paramdef>struct label - *<parameter>src</parameter></paramdef> - <paramdef>struct label - *<parameter>dest</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>src</parameter></entry> - <entry>Source label</entry> - </row> - - <row> - <entry><parameter>dest</parameter></entry> - <entry>Destination label</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Copy the label information in <parameter>src</parameter> - into <parameter>dest</parameter>.</para> - </sect3> - - <sect3 xml:id="mac-mpo-copy-pipe-label"> - <title><function>&mac.mpo;_copy_pipe_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_copy_pipe_label</function></funcdef> - - <paramdef>struct label - *<parameter>src</parameter></paramdef> - <paramdef>struct label - *<parameter>dest</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>src</parameter></entry> - <entry>Source label</entry> - </row> - - <row> - <entry><parameter>dest</parameter></entry> - <entry>Destination label</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Copy the label information in <parameter>src</parameter> - into <parameter>dest</parameter>.</para> - </sect3> - - <sect3 xml:id="mac-mpo-copy-vnode-label"> - <title><function>&mac.mpo;_copy_vnode_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_copy_vnode_label</function></funcdef> - - <paramdef>struct label - *<parameter>src</parameter></paramdef> - <paramdef>struct label - *<parameter>dest</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>src</parameter></entry> - <entry>Source label</entry> - </row> - - <row> - <entry><parameter>dest</parameter></entry> - <entry>Destination label</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Copy the label information in <parameter>src</parameter> - into <parameter>dest</parameter>.</para> - </sect3> - - <sect3 xml:id="mac-mpo-externalize-cred-label"> - <title><function>&mac.mpo;_externalize_cred_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_externalize_cred_label</function></funcdef> - - &mac.externalize.paramdefs; - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - &mac.externalize.tbody; - </tgroup> - </informaltable> - - &mac.externalize.para; - </sect3> - - <sect3 xml:id="mac-mpo-externalize-ifnet-label"> - <title><function>&mac.mpo;_externalize_ifnet_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_externalize_ifnet_label</function></funcdef> - - &mac.externalize.paramdefs; - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - &mac.externalize.tbody; - </tgroup> - </informaltable> - - &mac.externalize.para; - </sect3> - - <sect3 xml:id="mac-mpo-externalize-pipe-label"> - <title><function>&mac.mpo;_externalize_pipe_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_externalize_pipe_label</function></funcdef> - - &mac.externalize.paramdefs; - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - &mac.externalize.tbody; - </tgroup> - </informaltable> - - &mac.externalize.para; - </sect3> - - <sect3 xml:id="mac-mpo-externalize-socket-label"> - <title><function>&mac.mpo;_externalize_socket_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_externalize_socket_label</function></funcdef> - - &mac.externalize.paramdefs; - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - &mac.externalize.tbody; - </tgroup> - </informaltable> - - &mac.externalize.para; - </sect3> - - <sect3 xml:id="mac-mpo-externalize-socket-peer-label"> - <title><function>&mac.mpo;_externalize_socket_peer_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_externalize_socket_peer_label</function></funcdef> - &mac.externalize.paramdefs; - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - &mac.externalize.tbody; - </tgroup> - </informaltable> - - &mac.externalize.para; - </sect3> - - <sect3 xml:id="mac-mpo-externalize-vnode-label"> - <title><function>&mac.mpo;_externalize_vnode_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_externalize_vnode_label</function></funcdef> - - &mac.externalize.paramdefs; - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - &mac.externalize.tbody; - </tgroup> - </informaltable> - - &mac.externalize.para; - </sect3> - - <sect3 xml:id="mac-mpo-internalize-cred-label"> - <title><function>&mac.mpo;_internalize_cred_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_internalize_cred_label</function></funcdef> - - &mac.internalize.paramdefs; - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - &mac.internalize.tbody; - </tgroup> - </informaltable> - - &mac.internalize.para; - </sect3> - - <sect3 xml:id="mac-mpo-internalize-ifnet-label"> - <title><function>&mac.mpo;_internalize_ifnet_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_internalize_ifnet_label</function></funcdef> - - &mac.internalize.paramdefs; - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - &mac.internalize.tbody; - </tgroup> - </informaltable> - - &mac.internalize.para; - </sect3> - - <sect3 xml:id="mac-mpo-internalize-pipe-label"> - <title><function>&mac.mpo;_internalize_pipe_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_internalize_pipe_label</function></funcdef> - - &mac.internalize.paramdefs; - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - &mac.internalize.tbody; - </tgroup> - </informaltable> - - &mac.internalize.para; - </sect3> - - <sect3 xml:id="mac-mpo-internalize-socket-label"> - <title><function>&mac.mpo;_internalize_socket_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_internalize_socket_label</function></funcdef> - - &mac.internalize.paramdefs; - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - &mac.internalize.tbody; - </tgroup> - </informaltable> - - &mac.internalize.para; - </sect3> - - <sect3 xml:id="mac-mpo-internalize-vnode-label"> - <title><function>&mac.mpo;_internalize_vnode_label</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_internalize_vnode_label</function></funcdef> - - &mac.internalize.paramdefs; - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - &mac.internalize.tbody; - </tgroup> - </informaltable> - - &mac.internalize.para; - </sect3> - </sect2> - - <sect2 xml:id="mac-label-events"> - <title>Label Events</title> - - <para>This 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:</para> - - <programlisting>Label initialization o -(object-specific wait) \ -Label creation o - \ -Relabel events, o--<--. -Various object-specific, | | -Access control events ~-->--o - \ -Label destruction o</programlisting> - - <para>Label 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.</para> - - <para>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.</para> - - <para>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 - <symbol>MAC_UPDATE_IPQ</symbol> entry point as a result of the - acceptance of an additional mbuf to that queue.</para> - - <para>Access control events are discussed in detail in the - following section.</para> - - <para>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.</para> - - <para>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 - <symbol>MAC_INTERNALIZE</symbol>, which accepts a user label - to be converted to an in-kernel representation.</para> - - <sect3 xml:id="mac-fs-label-event-ops"> - <title>File System Object Labeling Event Operations</title> - - <sect4 xml:id="mac-mpo-associate-vnode-devfs"> - <title><function>&mac.mpo;_associate_vnode_devfs</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_associate_vnode_devfs</function></funcdef> - - <paramdef>struct mount - *<parameter>mp</parameter></paramdef> - <paramdef>struct label - *<parameter>fslabel</parameter></paramdef> - <paramdef>struct devfs_dirent - *<parameter>de</parameter></paramdef> - <paramdef>struct label - *<parameter>delabel</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>vlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>mp</parameter></entry> - <entry>Devfs mount point</entry> - </row> - - <row> - <entry><parameter>fslabel</parameter></entry> - <entry>Devfs file system label - (<varname>mp->mnt_fslabel</varname>)</entry> - </row> - - <row> - <entry><parameter>de</parameter></entry> - <entry>Devfs directory entry</entry> - </row> - - <row> - <entry><parameter>delabel</parameter></entry> - <entry>Policy label associated with - <parameter>de</parameter></entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>vnode associated with - <parameter>de</parameter></entry> - </row> - - <row> - <entry><parameter>vlabel</parameter></entry> - <entry>Policy label associated with - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Fill in the label (<parameter>vlabel</parameter>) for - a newly created devfs vnode based on the devfs directory - entry passed in <parameter>de</parameter> and its - label.</para> - </sect4> - - <sect4 xml:id="mac-mpo-associate-vnode-extattr"> - <title><function>&mac.mpo;_associate_vnode_extattr</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_associate_vnode_extattr</function></funcdef> - - <paramdef>struct mount - *<parameter>mp</parameter></paramdef> - <paramdef>struct label - *<parameter>fslabel</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>vlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>mp</parameter></entry> - <entry>File system mount point</entry> - </row> - - <row> - <entry><parameter>fslabel</parameter></entry> - <entry>File system label</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Vnode to label</entry> - </row> - - <row> - <entry><parameter>vlabel</parameter></entry> - <entry>Policy label associated with - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Attempt to retrieve the label for - <parameter>vp</parameter> from the file system extended - attributes. Upon success, the value <literal>0</literal> - is returned. Should extended attribute retrieval not be - supported, an accepted fallback is to copy - <parameter>fslabel</parameter> into - <parameter>vlabel</parameter>. In the event of an error, - an appropriate value for <varname>errno</varname> should - be returned.</para> - </sect4> - - <sect4 xml:id="mac-mpo-associate-vnode-singlelabel"> - <title><function>&mac.mpo;_associate_vnode_singlelabel</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_associate_vnode_singlelabel</function></funcdef> - <paramdef>struct mount - *<parameter>mp</parameter></paramdef> - <paramdef>struct label - *<parameter>fslabel</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>vlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>mp</parameter></entry> - <entry>File system mount point</entry> - </row> - - <row> - <entry><parameter>fslabel</parameter></entry> - <entry>File system label</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Vnode to label</entry> - </row> - - <row> - <entry><parameter>vlabel</parameter></entry> - <entry>Policy label associated with - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>On non-multilabel file systems, this entry point is - called to set the policy label for - <parameter>vp</parameter> based on the file system label, - <parameter>fslabel</parameter>.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-devfs-device"> - <title><function>&mac.mpo;_create_devfs_device</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_devfs_device</function></funcdef> - - <paramdef>dev_t <parameter>dev</parameter></paramdef> - <paramdef>struct devfs_dirent - *<parameter>devfs_dirent</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>dev</parameter></entry> - <entry>Device corresponding with - <parameter>devfs_dirent</parameter></entry> - </row> - - <row> - <entry><parameter>devfs_dirent</parameter></entry> - <entry>Devfs directory entry to be labeled.</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Label for <parameter>devfs_dirent</parameter> - to be filled in.</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>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.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-devfs-directory"> - <title><function>&mac.mpo;_create_devfs_directory</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_devfs_directory</function></funcdef> - - <paramdef>char - *<parameter>dirname</parameter></paramdef> - <paramdef>int - <parameter>dirnamelen</parameter></paramdef> - <paramdef>struct devfs_dirent - *<parameter>devfs_dirent</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>dirname</parameter></entry> - <entry>Name of directory being created</entry> - </row> - - <row> - <entry><parameter>namelen</parameter></entry> - <entry>Length of string - <parameter>dirname</parameter></entry> - </row> - - <row> - <entry><parameter>devfs_dirent</parameter></entry> - <entry>Devfs directory entry for directory being - created.</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>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.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-devfs-symlink"> - <title><function>&mac.mpo;_create_devfs_symlink</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_devfs_symlink</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct mount - *<parameter>mp</parameter></paramdef> - <paramdef>struct devfs_dirent - *<parameter>dd</parameter></paramdef> - <paramdef>struct label - *<parameter>ddlabel</parameter></paramdef> - <paramdef>struct devfs_dirent - *<parameter>de</parameter></paramdef> - <paramdef>struct label - *<parameter>delabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>mp</parameter></entry> - <entry>Devfs mount point</entry> - </row> - - <row> - <entry><parameter>dd</parameter></entry> - <entry>Link destination</entry> - </row> - - <row> - <entry><parameter>ddlabel</parameter></entry> - <entry>Label associated with - <parameter>dd</parameter></entry> - </row> - - <row> - <entry><parameter>de</parameter></entry> - <entry>Symlink entry</entry> - </row> - - <row> - <entry><parameter>delabel</parameter></entry> - <entry>Label associated with - <parameter>de</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Fill in the label (<parameter>delabel</parameter>) for - a newly created &man.devfs.5; symbolic link entry.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-vnode-extattr"> - <title><function>&mac.mpo;_create_vnode_extattr</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_create_vnode_extattr</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct mount - *<parameter>mp</parameter></paramdef> - <paramdef>struct label - *<parameter>fslabel</parameter></paramdef> - <paramdef>struct vnode - *<parameter>dvp</parameter></paramdef> - <paramdef>struct label - *<parameter>dlabel</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>vlabel</parameter></paramdef> - <paramdef>struct componentname - *<parameter>cnp</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>mount</parameter></entry> - <entry>File system mount point</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>File system label</entry> - </row> - - <row> - <entry><parameter>dvp</parameter></entry> - <entry>Parent directory vnode</entry> - </row> - - <row> - <entry><parameter>dlabel</parameter></entry> - <entry>Label associated with - <parameter>dvp</parameter></entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Newly created vnode</entry> - </row> - - <row> - <entry><parameter>vlabel</parameter></entry> - <entry>Policy label associated with - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>cnp</parameter></entry> - <entry>Component name for - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Write out the label for <parameter>vp</parameter> to - the appropriate extended attribute. If the write - succeeds, fill in <parameter>vlabel</parameter> with the - label, and return <returnvalue>0</returnvalue>. - Otherwise, return an appropriate error.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-mount"> - <title><function>&mac.mpo;_create_mount</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_mount</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct mount - *<parameter>mp</parameter></paramdef> - <paramdef>struct - label *<parameter>mnt</parameter></paramdef> - <paramdef>struct label - *<parameter>fslabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>mp</parameter></entry> - <entry>Object; file system being mounted</entry> - </row> - - <row> - <entry><parameter>mntlabel</parameter></entry> - <entry>Policy label to be filled in for - <parameter>mp</parameter></entry> - </row> - - <row> - <entry><parameter>fslabel</parameter></entry> - <entry>Policy label for the file system - <parameter>mp</parameter> mounts.</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>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.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-root-mount"> - <title><function>&mac.mpo;_create_root_mount</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_root_mount</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct mount - *<parameter>mp</parameter></paramdef> - <paramdef>struct label - *<parameter>mntlabel</parameter></paramdef> - <paramdef>struct label - *<parameter>fslabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry namest="first" nameend="last">See <xref - linkend="mac-mpo-create-mount"/>.</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>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;.</para> - </sect4> - - <sect4 xml:id="mac-mpo-relabel-vnode"> - <title><function>&mac.mpo;_relabel_vnode</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_relabel_vnode</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>vnodelabel</parameter></paramdef> - <paramdef>struct label - *<parameter>newlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>vnode to relabel</entry> - </row> - - <row> - <entry><parameter>vnodelabel</parameter></entry> - <entry>Existing policy label for - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>newlabel</parameter></entry> - <entry>New, possibly partial label to replace - <parameter>vnodelabel</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Update the label on the passed vnode given the passed - update vnode label and the passed subject - credential.</para> - </sect4> - - <sect4 xml:id="mac-mpo-setlabel-vnode-extattr"> - <title><function>&mac.mpo;_setlabel_vnode_extattr</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_setlabel_vnode_extattr</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>vlabel</parameter></paramdef> - <paramdef>struct label - *<parameter>intlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Vnode for which the label is being - written</entry> - </row> - - <row> - <entry><parameter>vlabel</parameter></entry> - <entry>Policy label associated with - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>intlabel</parameter></entry> - <entry>Label to write out</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Write out the policy from - <parameter>intlabel</parameter> to an extended attribute. - This is called from - <function>vop_stdcreatevnode_ea</function>.</para> - </sect4> - - <sect4 xml:id="mac-mpo-update-devfsdirent"> - <title><function>&mac.mpo;_update_devfsdirent</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_update_devfsdirent</function></funcdef> - - <paramdef>struct devfs_dirent - *<parameter>devfs_dirent</parameter></paramdef> - <paramdef>struct label - *<parameter>direntlabel</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>vnodelabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>devfs_dirent</parameter></entry> - <entry>Object; devfs directory entry</entry> - </row> - - <row> - <entry><parameter>direntlabel</parameter></entry> - <entry>Policy label for - <parameter>devfs_dirent</parameter> to be - updated.</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Parent vnode</entry> - <entry>Locked</entry> - </row> - - <row> - <entry><parameter>vnodelabel</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Update the <parameter>devfs_dirent</parameter> 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 a symlink is - created in devfs, following a call to - <function>mac_vnode_create_from_vnode</function> to - initialize the vnode label.</para> - </sect4> - </sect3> - - <sect3 xml:id="mac-ipc-label-ops"> - <title>IPC Object Labeling Event Operations</title> - - <sect4 xml:id="mac-mpo-create-mbuf-from-socket"> - <title><function>&mac.mpo;_create_mbuf_from_socket</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_mbuf_from_socket</function></funcdef> - - <paramdef>struct socket - *<parameter>so</parameter></paramdef> - <paramdef>struct label - *<parameter>socketlabel</parameter></paramdef> - <paramdef>struct mbuf - *<parameter>m</parameter></paramdef> - <paramdef>struct label - *<parameter>mbuflabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>socket</parameter></entry> - <entry>Socket</entry> - <entry>Socket locking WIP</entry> - </row> - - <row> - <entry><parameter>socketlabel</parameter></entry> - <entry>Policy label for - <parameter>socket</parameter></entry> - </row> - - <row> - <entry><parameter>m</parameter></entry> - <entry>Object; mbuf</entry> - </row> - - <row> - <entry><parameter>mbuflabel</parameter></entry> - <entry>Policy label to fill in for - <parameter>m</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set 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.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-pipe"> - <title><function>&mac.mpo;_create_pipe</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_pipe</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct pipe - *<parameter>pipe</parameter></paramdef> - <paramdef>struct label - *<parameter>pipelabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>pipe</parameter></entry> - <entry>Pipe</entry> - </row> - - <row> - <entry><parameter>pipelabel</parameter></entry> - <entry>Policy label associated with - <parameter>pipe</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set the label on a newly created pipe from the passed - subject credential. This call is made when a new pipe is - created.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-socket"> - <title><function>&mac.mpo;_create_socket</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_socket</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct socket - *<parameter>so</parameter></paramdef> - <paramdef>struct label - *<parameter>socketlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - <entry>Immutable</entry> - </row> - - <row> - <entry><parameter>so</parameter></entry> - <entry>Object; socket to label</entry> - </row> - - <row> - <entry><parameter>socketlabel</parameter></entry> - <entry>Label to fill in for - <parameter>so</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set the label on a newly created socket from the - passed subject credential. This call is made when a - socket is created.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-socket-from-socket"> - <title><function>&mac.mpo;_create_socket_from_socket</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_socket_from_socket</function></funcdef> - - <paramdef>struct socket - *<parameter>oldsocket</parameter></paramdef> - <paramdef>struct label - *<parameter>oldsocketlabel</parameter></paramdef> - <paramdef>struct socket - *<parameter>newsocket</parameter></paramdef> - <paramdef>struct label - *<parameter>newsocketlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>oldsocket</parameter></entry> - <entry>Listening socket</entry> - </row> - - <row> - <entry><parameter>oldsocketlabel</parameter></entry> - <entry>Policy label associated with - <parameter>oldsocket</parameter></entry> - </row> - - <row> - <entry><parameter>newsocket</parameter></entry> - <entry>New socket</entry> - </row> - - <row> - <entry><parameter>newsocketlabel</parameter></entry> - <entry>Policy label associated with - <parameter>newsocketlabel</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Label a socket, <parameter>newsocket</parameter>, - newly &man.accept.2;ed, based on the &man.listen.2; - socket, <parameter>oldsocket</parameter>.</para> - </sect4> - - <sect4 xml:id="mac-mpo-relabel-pipe"> - <title><function>&mac.mpo;_relabel_pipe</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_relabel_pipe</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct pipe - *<parameter>pipe</parameter></paramdef> - <paramdef>struct label - *<parameter>oldlabel</parameter></paramdef> - <paramdef>struct label - *<parameter>newlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>pipe</parameter></entry> - <entry>Pipe</entry> - </row> - - <row> - <entry><parameter>oldlabel</parameter></entry> - <entry>Current policy label associated with - <parameter>pipe</parameter></entry> - </row> - - <row> - <entry><parameter>newlabel</parameter></entry> - <entry>Policy label update to apply to - <parameter>pipe</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Apply a new label, <parameter>newlabel</parameter>, to - <parameter>pipe</parameter>.</para> - </sect4> - - <sect4 xml:id="mac-mpo-relabel-socket"> - <title><function>&mac.mpo;_relabel_socket</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_relabel_socket</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct socket - *<parameter>so</parameter></paramdef> - <paramdef>struct label - *<parameter>oldlabel</parameter></paramdef> - <paramdef>struct label - *<parameter>newlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - <entry>Immutable</entry> - </row> - - <row> - <entry><parameter>so</parameter></entry> - <entry>Object; socket</entry> - </row> - - <row> - <entry><parameter>oldlabel</parameter></entry> - <entry>Current label for - <parameter>so</parameter></entry> - </row> - - <row> - <entry><parameter>newlabel</parameter></entry> - <entry>Label update for - <parameter>so</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Update the label on a socket from the passed socket - label update.</para> - </sect4> - - <sect4 xml:id="mpo-set-socket-peer-from-mbuf"> - <title><function>&mac.mpo;_set_socket_peer_from_mbuf</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_set_socket_peer_from_mbuf</function></funcdef> - - <paramdef>struct mbuf - *<parameter>mbuf</parameter></paramdef> - <paramdef>struct label - *<parameter>mbuflabel</parameter></paramdef> - <paramdef>struct label - *<parameter>oldlabel</parameter></paramdef> - <paramdef>struct label - *<parameter>newlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>mbuf</parameter></entry> - <entry>First datagram received over socket</entry> - </row> - - <row> - <entry><parameter>mbuflabel</parameter></entry> - <entry>Label for <parameter>mbuf</parameter></entry> - </row> - - <row> - <entry><parameter>oldlabel</parameter></entry> - <entry>Current label for the socket</entry> - </row> - - <row> - <entry><parameter>newlabel</parameter></entry> - <entry>Policy label to be filled out for the - socket</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set 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.</para> - </sect4> - - <sect4 xml:id="mac-mpo-set-socket-peer-from-socket"> - <title><function>&mac.mpo;_set_socket_peer_from_socket</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_set_socket_peer_from_socket</function></funcdef> - <paramdef>struct socket - *<parameter>oldsocket</parameter></paramdef> - <paramdef>struct label - *<parameter>oldsocketlabel</parameter></paramdef> - <paramdef>struct socket - *<parameter>newsocket</parameter></paramdef> - <paramdef>struct label - *<parameter>newsocketpeerlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>oldsocket</parameter></entry> - <entry>Local socket</entry> - </row> - - <row> - <entry><parameter>oldsocketlabel</parameter></entry> - <entry>Policy label for - <parameter>oldsocket</parameter></entry> - </row> - - <row> - <entry><parameter>newsocket</parameter></entry> - <entry>Peer socket</entry> - </row> - - <row> - <entry><parameter>newsocketpeerlabel</parameter></entry> - <entry>Policy label to fill in for - <parameter>newsocket</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <!-- XXX Passed _remote_ socket endpoint ? --> - <para>Set 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.</para> - </sect4> - </sect3> - - <sect3 xml:id="mac-net-labeling-event-ops"> - <title>Network Object Labeling Event Operations</title> - - <sect4 xml:id="mac-mpo-create-bpfdesc"> - <title><function>&mac.mpo;_create_bpfdesc</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_bpfdesc</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct bpf_d - *<parameter>bpf_d</parameter></paramdef> - <paramdef>struct label - *<parameter>bpflabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - <entry>Immutable</entry> - </row> - - <row> - <entry><parameter>bpf_d</parameter></entry> - <entry>Object; bpf descriptor</entry> - </row> - - <row> - <entry><parameter>bpf</parameter></entry> - <entry>Policy label to be filled in for - <parameter>bpf_d</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set 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.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-ifnet"> - <title><function>&mac.mpo;_create_ifnet</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_ifnet</function></funcdef> - - <paramdef>struct ifnet - *<parameter>ifnet</parameter></paramdef> - <paramdef>struct label - *<parameter>ifnetlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>ifnet</parameter></entry> - <entry>Network interface</entry> - </row> - - <row> - <entry><parameter>ifnetlabel</parameter></entry> - <entry>Policy label to fill in for - <parameter>ifnet</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set 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.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-ipq"> - <title><function>&mac.mpo;_create_ipq</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_ipq</function></funcdef> - - <paramdef>struct mbuf - *<parameter>fragment</parameter></paramdef> - <paramdef>struct label - *<parameter>fragmentlabel</parameter></paramdef> - <paramdef>struct ipq - *<parameter>ipq</parameter></paramdef> - <paramdef>struct label - *<parameter>ipqlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>fragment</parameter></entry> - <entry>First received IP fragment</entry> - </row> - - <row> - <entry><parameter>fragmentlabel</parameter></entry> - <entry>Policy label for - <parameter>fragment</parameter></entry> - </row> - - <row> - <entry><parameter>ipq</parameter></entry> - <entry>IP reassembly queue to be labeled</entry> - </row> - - <row> - <entry><parameter>ipqlabel</parameter></entry> - <entry>Policy label to be filled in for - <parameter>ipq</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set the label on a newly created IP fragment - reassembly queue from the mbuf header of the first - received fragment.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-datagram-from-ipq"> - <title><function>&mac.mpo;_create_datagram_from_ipq</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_create_datagram_from_ipq</function></funcdef> - - <paramdef>struct ipq - *<parameter>ipq</parameter></paramdef> - <paramdef>struct label - *<parameter>ipqlabel</parameter></paramdef> - <paramdef>struct mbuf - *<parameter>datagram</parameter></paramdef> - <paramdef>struct label - *<parameter>datagramlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>ipq</parameter></entry> - <entry>IP reassembly queue</entry> - </row> - - <row> - <entry><parameter>ipqlabel</parameter></entry> - <entry>Policy label for - <parameter>ipq</parameter></entry> - </row> - - <row> - <entry><parameter>datagram</parameter></entry> - <entry>Datagram to be labeled</entry> - </row> - - <row> - <entry><parameter>datagramlabel</parameter></entry> - <entry>Policy label to be filled in for - <parameter>datagramlabel</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set the label on a newly reassembled IP datagram from - the IP fragment reassembly queue from which it was - generated.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-fragment"> - <title><function>&mac.mpo;_create_fragment</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_fragment</function></funcdef> - - <paramdef>struct mbuf - *<parameter>datagram</parameter></paramdef> - <paramdef>struct label - *<parameter>datagramlabel</parameter></paramdef> - <paramdef>struct mbuf - *<parameter>fragment</parameter></paramdef> - <paramdef>struct label - *<parameter>fragmentlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>datagram</parameter></entry> - <entry>Datagram</entry> - </row> - - <row> - <entry><parameter>datagramlabel</parameter></entry> - <entry>Policy label for - <parameter>datagram</parameter></entry> - </row> - - <row> - <entry><parameter>fragment</parameter></entry> - <entry>Fragment to be labeled</entry> - </row> - - <row> - <entry><parameter>fragmentlabel</parameter></entry> - <entry>Policy label to be filled in for - <parameter>datagram</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set 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.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-mbuf-from-mbuf"> - <title><function>&mac.mpo;_create_mbuf_from_mbuf</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_mbuf_from_mbuf</function></funcdef> - - <paramdef>struct mbuf - *<parameter>oldmbuf</parameter></paramdef> - <paramdef>struct label - *<parameter>oldmbuflabel</parameter></paramdef> - <paramdef>struct mbuf - *<parameter>newmbuf</parameter></paramdef> - <paramdef>struct label - *<parameter>newmbuflabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>oldmbuf</parameter></entry> - <entry>Existing (source) mbuf</entry> - </row> - - <row> - <entry><parameter>oldmbuflabel</parameter></entry> - <entry>Policy label for - <parameter>oldmbuf</parameter></entry> - </row> - - <row> - <entry><parameter>newmbuf</parameter></entry> - <entry>New mbuf to be labeled</entry> - </row> - - <row> - <entry><parameter>newmbuflabel</parameter></entry> - <entry>Policy label to be filled in for - <parameter>newmbuf</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set 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.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-mbuf-linklayer"> - <title><function>&mac.mpo;_create_mbuf_linklayer</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_mbuf_linklayer</function></funcdef> - - <paramdef>struct ifnet - *<parameter>ifnet</parameter></paramdef> - <paramdef>struct label - *<parameter>ifnetlabel</parameter></paramdef> - <paramdef>struct mbuf - *<parameter>mbuf</parameter></paramdef> - <paramdef>struct label - *<parameter>mbuflabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>ifnet</parameter></entry> - <entry>Network interface</entry> - </row> - - <row> - <entry><parameter>ifnetlabel</parameter></entry> - <entry>Policy label for - <parameter>ifnet</parameter></entry> - </row> - - <row> - <entry><parameter>mbuf</parameter></entry> - <entry>mbuf header for new datagram</entry> - </row> - - <row> - <entry><parameter>mbuflabel</parameter></entry> - <entry>Policy label to be filled in for - <parameter>mbuf</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set 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.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-mbuf-from-bpfdesc"> - <title><function>&mac.mpo;_create_mbuf_from_bpfdesc</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_mbuf_from_bpfdesc</function></funcdef> - - <paramdef>struct bpf_d - *<parameter>bpf_d</parameter></paramdef> - <paramdef>struct label - *<parameter>bpflabel</parameter></paramdef> - <paramdef>struct mbuf - *<parameter>mbuf</parameter></paramdef> - <paramdef>struct label - *<parameter>mbuflabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>bpf_d</parameter></entry> - <entry>BPF descriptor</entry> - </row> - - <row> - <entry><parameter>bpflabel</parameter></entry> - <entry>Policy label for - <parameter>bpflabel</parameter></entry> - </row> - - <row> - <entry><parameter>mbuf</parameter></entry> - <entry>New mbuf to be labeled</entry> - </row> - - <row> - <entry><parameter>mbuflabel</parameter></entry> - <entry>Policy label to fill in for - <parameter>mbuf</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set 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.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-mbuf-from-ifnet"> - <title><function>&mac.mpo;_create_mbuf_from_ifnet</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_mbuf_from_ifnet</function></funcdef> - - <paramdef>struct ifnet - *<parameter>ifnet</parameter></paramdef> - <paramdef>struct label - *<parameter>ifnetlabel</parameter></paramdef> - <paramdef>struct mbuf - *<parameter>mbuf</parameter></paramdef> - <paramdef>struct label - *<parameter>mbuflabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>ifnet</parameter></entry> - <entry>Network interface</entry> - </row> - - <row> - <entry><parameter>ifnetlabel</parameter></entry> - <entry>Policy label for - <parameter>ifnetlabel</parameter></entry> - </row> - - <row> - <entry><parameter>mbuf</parameter></entry> - <entry>mbuf header for new datagram</entry> - </row> - - <row> - <entry><parameter>mbuflabel</parameter></entry> - <entry>Policy label to be filled in for - <parameter>mbuf</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set the label on the mbuf header of a newly created - datagram generated from the passed network - interface.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-mbuf-multicast-encap"> - <title><function>&mac.mpo;_create_mbuf_multicast_encap</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_mbuf_multicast_encap</function></funcdef> - <paramdef>struct mbuf - *<parameter>oldmbuf</parameter></paramdef> - <paramdef>struct label - *<parameter>oldmbuflabel</parameter></paramdef> - <paramdef>struct ifnet - *<parameter>ifnet</parameter></paramdef> - <paramdef>struct label - *<parameter>ifnetlabel</parameter></paramdef> - <paramdef>struct mbuf - *<parameter>newmbuf</parameter></paramdef> - <paramdef>struct label - *<parameter>newmbuflabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>oldmbuf</parameter></entry> - <entry>mbuf header for existing datagram</entry> - </row> - - <row> - <entry><parameter>oldmbuflabel</parameter></entry> - <entry>Policy label for - <parameter>oldmbuf</parameter></entry> - </row> - - <row> - <entry><parameter>ifnet</parameter></entry> - <entry>Network interface</entry> - </row> - - <row> - <entry><parameter>ifnetlabel</parameter></entry> - <entry>Policy label for - <parameter>ifnet</parameter></entry> - </row> - - <row> - <entry><parameter>newmbuf</parameter></entry> - <entry>mbuf header to be labeled for new - datagram</entry> - </row> - - <row> - <entry><parameter>newmbuflabel</parameter></entry> - <entry>Policy label to be filled in for - <parameter>newmbuf</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set 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.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-mbuf-netlayer"> - <title><function>&mac.mpo;_create_mbuf_netlayer</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_mbuf_netlayer</function></funcdef> - - <paramdef>struct mbuf - *<parameter>oldmbuf</parameter></paramdef> - <paramdef>struct label - *<parameter>oldmbuflabel</parameter></paramdef> - <paramdef>struct mbuf - *<parameter>newmbuf</parameter></paramdef> - <paramdef>struct label - *<parameter>newmbuflabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>oldmbuf</parameter></entry> - <entry>Received datagram</entry> - </row> - - <row> - <entry><parameter>oldmbuflabel</parameter></entry> - <entry>Policy label for - <parameter>oldmbuf</parameter></entry> - </row> - - <row> - <entry><parameter>newmbuf</parameter></entry> - <entry>Newly created datagram</entry> - </row> - - <row> - <entry><parameter>newmbuflabel</parameter></entry> - <entry>Policy label for - <parameter>newmbuf</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set the label on the mbuf header of a newly created - datagram generated by the IP stack in response to an - existing received datagram - (<parameter>oldmbuf</parameter>). This call may be made - in a number of situations, including when responding to - ICMP request datagrams.</para> - </sect4> - - <sect4 xml:id="mac-mpo-fragment-match"> - <title><function>&mac.mpo;_fragment_match</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_fragment_match</function></funcdef> - - <paramdef>struct mbuf - *<parameter>fragment</parameter></paramdef> - <paramdef>struct label - *<parameter>fragmentlabel</parameter></paramdef> - <paramdef>struct ipq - *<parameter>ipq</parameter></paramdef> - <paramdef>struct label - *<parameter>ipqlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>fragment</parameter></entry> - <entry>IP datagram fragment</entry> - </row> - - <row> - <entry><parameter>fragmentlabel</parameter></entry> - <entry>Policy label for - <parameter>fragment</parameter></entry> - </row> - - <row> - <entry><parameter>ipq</parameter></entry> - <entry>IP fragment reassembly queue</entry> - </row> - - <row> - <entry><parameter>ipqlabel</parameter></entry> - <entry>Policy label for - <parameter>ipq</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether an mbuf header containing an IP - datagram (<parameter>fragment</parameter>) fragment - matches the label of the passed IP fragment reassembly - queue (<parameter>ipq</parameter>). Return - (<returnvalue>1</returnvalue>) for a successful match, or - (<returnvalue>0</returnvalue>) 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.</para> - </sect4> - - <sect4 xml:id="mac-mpo-ifnet-relabel"> - <title><function>&mac.mpo;_relabel_ifnet</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_relabel_ifnet</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct ifnet - *<parameter>ifnet</parameter></paramdef> - <paramdef>struct label - *<parameter>ifnetlabel</parameter></paramdef> - <paramdef>struct label - *<parameter>newlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>ifnet</parameter></entry> - <entry>Object; Network interface</entry> - </row> - - <row> - <entry><parameter>ifnetlabel</parameter></entry> - <entry>Policy label for - <parameter>ifnet</parameter></entry> - </row> - - <row> - <entry><parameter>newlabel</parameter></entry> - <entry>Label update to apply to - <parameter>ifnet</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Update the label of network interface, - <parameter>ifnet</parameter>, based on the passed update - label, <parameter>newlabel</parameter>, and the passed - subject credential, <parameter>cred</parameter>.</para> - </sect4> - - <sect4 xml:id="mac-mpo-update-ipq"> - <title><function>&mac.mpo;_update_ipq</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_update_ipq</function></funcdef> - - <paramdef>struct mbuf - *<parameter>fragment</parameter></paramdef> - <paramdef>struct label - *<parameter>fragmentlabel</parameter></paramdef> - <paramdef>struct ipq - *<parameter>ipq</parameter></paramdef> - <paramdef>struct label - *<parameter>ipqlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>mbuf</parameter></entry> - <entry>IP fragment</entry> - </row> - - <row> - <entry><parameter>mbuflabel</parameter></entry> - <entry>Policy label for - <parameter>mbuf</parameter></entry> - </row> - - <row> - <entry><parameter>ipq</parameter></entry> - <entry>IP fragment reassembly queue</entry> - </row> - - <row> - <entry><parameter>ipqlabel</parameter></entry> - <entry>Policy label to be updated for - <parameter>ipq</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Update the label on an IP fragment reassembly queue - (<parameter>ipq</parameter>) based on the acceptance of - the passed IP fragment mbuf header - (<parameter>mbuf</parameter>).</para> - </sect4> - </sect3> - - <sect3 xml:id="mac-proc-labeling-event-ops"> - <title>Process Labeling Event Operations</title> - - <sect4 xml:id="mac-mpo-create-cred"> - <title><function>&mac.mpo;_create_cred</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_cred</function></funcdef> - - <paramdef>struct ucred - *<parameter>parent_cred</parameter></paramdef> - <paramdef>struct ucred - *<parameter>child_cred</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>parent_cred</parameter></entry> - <entry>Parent subject credential</entry> - </row> - - <row> - <entry><parameter>child_cred</parameter></entry> - <entry>Child subject credential</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Set 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 - <type>struct ucred</type>. This call should not be - confused with a process forking or creation event.</para> - </sect4> - - <sect4 xml:id="mac-mpo-execve-transition"> - <title><function>&mac.mpo;_execve_transition</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_execve_transition</function></funcdef> - - <paramdef>struct ucred - *<parameter>old</parameter></paramdef> - <paramdef>struct ucred - *<parameter>new</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>vnodelabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>old</parameter></entry> - <entry>Existing subject credential</entry> - <entry>Immutable</entry> - </row> - - <row> - <entry><parameter>new</parameter></entry> - <entry>New subject credential to be labeled</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>File to execute</entry> <entry>Locked</entry> - </row> - - <row> - <entry><parameter>vnodelabel</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Update the label of a newly created subject credential - (<parameter>new</parameter>) from the passed existing - subject credential (<parameter>old</parameter>) based on a - label transition caused by executing the passed vnode - (<parameter>vp</parameter>). This call occurs when a - process executes the passed vnode and one of the policies - returns a success from the - <function>mpo_execve_will_transition</function> entry - point. Policies may choose to implement this call simply - by invoking <function>mpo_create_cred</function> 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 - <function>mpo_create_cred</function>, even if they do not - implement - <function>mpo_execve_will_transition</function>.</para> - </sect4> - - <sect4 xml:id="mac-mpo-execve-will-transition"> - <title><function>&mac.mpo;_execve_will_transition</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_execve_will_transition</function></funcdef> - - <paramdef>struct ucred - *<parameter>old</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>vnodelabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>old</parameter></entry> - <entry>Subject credential prior to - &man.execve.2;</entry> - <entry>Immutable</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>File to execute</entry> - </row> - - <row> - <entry><parameter>vnodelabel</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine 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 - <returnvalue>1</returnvalue> if a transition is required, - <returnvalue>0</returnvalue> if not. Even if a policy - returns <returnvalue>0</returnvalue>, it should behave - correctly in the presence of an unexpected invocation of - <function>mpo_execve_transition</function>, as that call - may happen as a result of another policy requesting a - transition.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-proc0"> - <title><function>&mac.mpo;_create_proc0</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_proc0</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential to be filled in</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Create the subject credential of process 0, the parent - of all kernel processes.</para> - </sect4> - - <sect4 xml:id="mac-mpo-create-proc1"> - <title><function>&mac.mpo;_create_proc1</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_create_proc1</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential to be filled in</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Create the subject credential of process 1, the parent - of all user processes.</para> - </sect4> - - <sect4 xml:id="mac-mpo-relabel-cred"> - <title><function>&mac.mpo;_relabel_cred</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_relabel_cred</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct label - *<parameter>newlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>newlabel</parameter></entry> - <entry>Label update to apply to - <parameter>cred</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Update the label on a subject credential from the - passed update label.</para> - </sect4> - - </sect3> - </sect2> - - <sect2 xml:id="mac-access-control-checks"> - <title>Access Control Checks</title> - - <para>Access 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 - <function>error_select()</function> function in - <filename>kern_mac.c</filename>:</para> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="2"> - <tbody> - <row> - <entry>Most precedence</entry> - <entry><errorcode>EDEADLK</errorcode></entry> - </row> - - <row> - <entry/> - <entry><errorcode>EINVAL</errorcode></entry> - </row> - - <row> - <entry/> - <entry><errorcode>ESRCH</errorcode></entry> - </row> - - <row> - <entry/> - <entry>EACCES</entry> - </row> - - <row> - <entry>Least precedence</entry> - <entry>EPERM</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>If 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.</para> - - <sect3 xml:id="mac-mpo-bpfdesc-check-receive-from-ifnet"> - <title><function>&mac.mpo;_check_bpfdesc_receive</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_bpfdesc_receive</function></funcdef> - - <paramdef>struct bpf_d - *<parameter>bpf_d</parameter></paramdef> - <paramdef>struct label - *<parameter>bpflabel</parameter></paramdef> - <paramdef>struct ifnet - *<parameter>ifnet</parameter></paramdef> - <paramdef>struct label - *<parameter>ifnetlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>bpf_d</parameter></entry> - <entry>Subject; BPF descriptor</entry> - </row> - - <row> - <entry><parameter>bpflabel</parameter></entry> - <entry>Policy label for - <parameter>bpf_d</parameter></entry> - </row> - - <row> - <entry><parameter>ifnet</parameter></entry> - <entry>Object; network interface</entry> - </row> - - <row> - <entry><parameter>ifnetlabel</parameter></entry> - <entry>Policy label for - <parameter>ifnet</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the MAC framework should permit - datagrams from the passed interface to be delivered to the - buffers of the passed BPF descriptor. Return - (<returnvalue>0</returnvalue>) for success, or an - <varname>errno</varname> value for failure Suggested - failure: <errorcode>EACCES</errorcode> for label mismatches, - <errorcode>EPERM</errorcode> for lack of privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-kenv-dump"> - <title><function>&mac.mpo;_check_kenv_dump</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_kenv_dump</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to - retrieve the kernel environment (see &man.kenv.2;).</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-kenv-get"> - <title><function>&mac.mpo;_check_kenv_get</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_kenv_get</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>char *<parameter>name</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>name</parameter></entry> - <entry>Kernel environment variable name</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to - retrieve the value of the specified kernel environment - variable.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-kenv-set"> - <title><function>&mac.mpo;_check_kenv_set</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_kenv_set</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>char *<parameter>name</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>name</parameter></entry> - <entry>Kernel environment variable name</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to set - the specified kernel environment variable.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-kenv-unset"> - <title><function>&mac.mpo;_check_kenv_unset</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_kenv_unset</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>char *<parameter>name</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>name</parameter></entry> - <entry>Kernel environment variable name</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to unset - the specified kernel environment variable.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-kld-load"> - <title><function>&mac.mpo;_check_kld_load</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_kld_load</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>vlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Kernel module vnode</entry> - </row> - - <row> - <entry><parameter>vlabel</parameter></entry> - <entry>Label associated with - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to load - the specified module file.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-kld-stat"> - <title><function>&mac.mpo;_check_kld_stat</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_kld_stat</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to - retrieve a list of loaded kernel module files and associated - statistics.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-kld-unload"> - <title><function>&mac.mpo;_check_kld_unload</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_kld_unload</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to - unload a kernel module.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-pipe-ioctl"> - <title><function>&mac.mpo;_check_pipe_ioctl</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_pipe_ioctl</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct pipe - *<parameter>pipe</parameter></paramdef> - <paramdef>struct label - *<parameter>pipelabel</parameter></paramdef> - <paramdef>unsigned long - <parameter>cmd</parameter></paramdef> - <paramdef>void *<parameter>data</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>pipe</parameter></entry> - <entry>Pipe</entry> - </row> - - <row> - <entry><parameter>pipelabel</parameter></entry> - <entry>Policy label associated with - <parameter>pipe</parameter></entry> - </row> - - <row> - <entry><parameter>cmd</parameter></entry> - <entry>&man.ioctl.2; command</entry> - </row> - - <row> - <entry><parameter>data</parameter></entry> - <entry>&man.ioctl.2; data</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to make - the specified &man.ioctl.2; call.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-pipe-poll"> - <title><function>&mac.mpo;_check_pipe_poll</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_pipe_poll</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct pipe - *<parameter>pipe</parameter></paramdef> - <paramdef>struct label - *<parameter>pipelabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>pipe</parameter></entry> - <entry>Pipe</entry> - </row> - - <row> - <entry><parameter>pipelabel</parameter></entry> - <entry>Policy label associated with - <parameter>pipe</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to poll - <parameter>pipe</parameter>.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-pipe-read"> - <title><function>&mac.mpo;_check_pipe_read</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_pipe_read</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct pipe - *<parameter>pipe</parameter></paramdef> - <paramdef>struct label - *<parameter>pipelabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>pipe</parameter></entry> - <entry>Pipe</entry> - </row> - - <row> - <entry><parameter>pipelabel</parameter></entry> - <entry>Policy label associated with - <parameter>pipe</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed read - access to <parameter>pipe</parameter>.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-pipe-relabel"> - <title><function>&mac.mpo;_check_pipe_relabel</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_pipe_relabel</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct pipe - *<parameter>pipe</parameter></paramdef> - <paramdef>struct label - *<parameter>pipelabel</parameter></paramdef> - <paramdef>struct label - *<parameter>newlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>pipe</parameter></entry> - <entry>Pipe</entry> - </row> - - <row> - <entry><parameter>pipelabel</parameter></entry> - <entry>Current policy label associated with - <parameter>pipe</parameter></entry> - </row> - - <row> - <entry><parameter>newlabel</parameter></entry> - <entry>Label update to - <parameter>pipelabel</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to - relabel <parameter>pipe</parameter>.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-pipe-stat"> - <title><function>&mac.mpo;_check_pipe_stat</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_pipe_stat</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct pipe - *<parameter>pipe</parameter></paramdef> - <paramdef>struct label - *<parameter>pipelabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>pipe</parameter></entry> - <entry>Pipe</entry> - </row> - - <row> - <entry><parameter>pipelabel</parameter></entry> - <entry>Policy label associated with - <parameter>pipe</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to - retrieve statistics related to - <parameter>pipe</parameter>.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-pipe-write"> - <title><function>&mac.mpo;_check_pipe_write</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_pipe_write</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct pipe - *<parameter>pipe</parameter></paramdef> - <paramdef>struct label - *<parameter>pipelabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>pipe</parameter></entry> - <entry>Pipe</entry> - </row> - - <row> - <entry><parameter>pipelabel</parameter></entry> - <entry>Policy label associated with - <parameter>pipe</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to write - to <parameter>pipe</parameter>.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-socket-bind"> - <title><function>&mac.mpo;_check_socket_bind</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_socket_bind</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct socket - *<parameter>socket</parameter></paramdef> - <paramdef>struct label - *<parameter>socketlabel</parameter></paramdef> - <paramdef>struct sockaddr - *<parameter>sockaddr</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>socket</parameter></entry> - <entry>Socket to be bound</entry> - </row> - - <row> - <entry><parameter>socketlabel</parameter></entry> - <entry>Policy label for - <parameter>socket</parameter></entry> - </row> - - <row> - <entry><parameter>sockaddr</parameter></entry> - <entry>Address of - <parameter>socket</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-socket-connect"> - <title><function>&mac.mpo;_check_socket_connect</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_socket_connect</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct socket - *<parameter>socket</parameter></paramdef> - <paramdef>struct label - *<parameter>socketlabel</parameter></paramdef> - <paramdef>struct sockaddr - *<parameter>sockaddr</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>socket</parameter></entry> - <entry>Socket to be connected</entry> - </row> - - <row> - <entry><parameter>socketlabel</parameter></entry> - <entry>Policy label for - <parameter>socket</parameter></entry> - </row> - - <row> - <entry><parameter>sockaddr</parameter></entry> - <entry>Address of - <parameter>socket</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential - (<parameter>cred</parameter>) can connect the passed socket - (<parameter>socket</parameter>) to the passed socket address - (<parameter>sockaddr</parameter>). Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatches, - <errorcode>EPERM</errorcode> for lack of privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-socket-receive"> - <title><function>&mac.mpo;_check_socket_receive</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_socket_receive</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct socket - *<parameter>so</parameter></paramdef> - <paramdef>struct label - *<parameter>socketlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>so</parameter></entry> - <entry>Socket</entry> - </row> - - <row> - <entry><parameter>socketlabel</parameter></entry> - <entry>Policy label associated with - <parameter>so</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to - receive information from the socket - <parameter>so</parameter>.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-socket-send"> - <title><function>&mac.mpo;_check_socket_send</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_socket_send</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct socket - *<parameter>so</parameter></paramdef> - <paramdef>struct label - *<parameter>socketlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>so</parameter></entry> - <entry>Socket</entry> - </row> - - <row> - <entry><parameter>socketlabel</parameter></entry> - <entry>Policy label associated with - <parameter>so</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to send - information across the socket - <parameter>so</parameter>.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-cred-visible"> - <title><function>&mac.mpo;_check_cred_visible</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_cred_visible</function></funcdef> - - <paramdef>struct ucred - *<parameter>u1</parameter></paramdef> - <paramdef>struct ucred - *<parameter>u2</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>u1</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>u2</parameter></entry> - <entry>Object credential</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential - <parameter>u1</parameter> can <quote>see</quote> other - subjects with the passed subject credential - <parameter>u2</parameter>. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatches, - <errorcode>EPERM</errorcode> for lack of privilege, or - <errorcode>ESRCH</errorcode> to hide visibility. This call - may be made in a number of situations, including - inter-process status sysctl's used by <command>ps</command>, - and in procfs lookups.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-socket-visible"> - <title><function>&mac.mpo;_check_socket_visible</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_socket_visible</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct socket - *<parameter>socket</parameter></paramdef> - <paramdef>struct label - *<parameter>socketlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>socket</parameter></entry> - <entry>Object; socket</entry> - </row> - - <row> - <entry><parameter>socketlabel</parameter></entry> - <entry>Policy label for - <parameter>socket</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-ifnet-relabel"> - <title><function>&mac.mpo;_check_ifnet_relabel</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_ifnet_relabel</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct ifnet - *<parameter>ifnet</parameter></paramdef> - <paramdef>struct label - *<parameter>ifnetlabel</parameter></paramdef> - <paramdef>struct label - *<parameter>newlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>ifnet</parameter></entry> - <entry>Object; network interface</entry> - </row> - - <row> - <entry><parameter>ifnetlabel</parameter></entry> - <entry>Existing policy label for - <parameter>ifnet</parameter></entry> - </row> - - <row> - <entry><parameter>newlabel</parameter></entry> - <entry>Policy label update to later be applied to - <parameter>ifnet</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can relabel the - passed network interface to the passed label update.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-socket-relabel"> - <title><function>&mac.mpo;_check_socket_relabel</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_socket_relabel</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct socket - *<parameter>socket</parameter></paramdef> - <paramdef>struct label - *<parameter>socketlabel</parameter></paramdef> - <paramdef>struct label - *<parameter>newlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>socket</parameter></entry> - <entry>Object; socket</entry> - </row> - - <row> - <entry><parameter>socketlabel</parameter></entry> - <entry>Existing policy label for - <parameter>socket</parameter></entry> - </row> - - <row> - <entry><parameter>newlabel</parameter></entry> - <entry>Label update to later be applied to - <parameter>socketlabel</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can relabel the - passed socket to the passed label update.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-cred-relabel"> - <title><function>&mac.mpo;_check_cred_relabel</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_cred_relabel</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct label - *<parameter>newlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>newlabel</parameter></entry> - <entry>Label update to later be applied to - <parameter>cred</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can relabel - itself to the passed label update.</para> - </sect3> - - - <sect3 xml:id="mac-mpo-cred-check-vnode-relabel"> - <title><function>&mac.mpo;_check_vnode_relabel</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_relabel</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>vnodelabel</parameter></paramdef> - <paramdef>struct label - *<parameter>newlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - <entry>Immutable</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode</entry> - <entry>Locked</entry> - </row> - - <row> - <entry><parameter>vnodelabel</parameter></entry> - <entry>Existing policy label for - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>newlabel</parameter></entry> - <entry>Policy label update to later be applied to - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can relabel the - passed vnode to the passed label update.</para> - </sect3> - - <sect3 xml:id="mpo-cred-check-mount-stat"> - <title><function>&mac.mpo;_check_mount_stat</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_mount_stat</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct mount - *<parameter>mp</parameter></paramdef> - <paramdef>struct label - *<parameter>mountlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>mp</parameter></entry> - <entry>Object; file system mount</entry> - </row> - - <row> - <entry><parameter>mountlabel</parameter></entry> - <entry>Policy label for - <parameter>mp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <!-- XXX Update ? --> - <para>Determine whether the subject credential can see the - results of a statfs performed on the file system. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatches - or <errorcode>EPERM</errorcode> 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.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-proc-debug"> - <title><function>&mac.mpo;_check_proc_debug</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_proc_debug</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct proc - *<parameter>proc</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - <entry>Immutable</entry> - </row> - - <row> - <entry><parameter>proc</parameter></entry> - <entry>Object; process</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can debug the - passed process. Return <returnvalue>0</returnvalue> for - success, or an <varname>errno</varname> value for failure. - Suggested failure: <errorcode>EACCES</errorcode> for label - mismatch, <errorcode>EPERM</errorcode> for lack of - privilege, or <errorcode>ESRCH</errorcode> 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.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-access"> - <title><function>&mac.mpo;_check_vnode_access</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_access</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>int <parameter>flags</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>flags</parameter></entry> - <entry>&man.access.2; flags</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine 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 <function>&mac.mpo;_check_vnode_open</function>. - Return <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatches - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-chdir"> - <title><function>&mac.mpo;_check_vnode_chdir</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_chdir</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>dvp</parameter></paramdef> - <paramdef>struct label - *<parameter>dlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>dvp</parameter></entry> - <entry>Object; vnode to &man.chdir.2; into</entry> - </row> - - <row> - <entry><parameter>dlabel</parameter></entry> - <entry>Policy label for - <parameter>dvp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can change the - process working directory to the passed vnode. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-vnode-chroot"> - <title><function>&mac.mpo;_check_vnode_chroot</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_chroot</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>dvp</parameter></paramdef> - <paramdef>struct label - *<parameter>dlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>dvp</parameter></entry> - <entry>Directory vnode</entry> - </row> - - <row> - <entry><parameter>dlabel</parameter></entry> - <entry>Policy label associated with - <parameter>dvp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to - &man.chroot.2; into the specified directory - (<parameter>dvp</parameter>).</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-create"> - <title><function>&mac.mpo;_check_vnode_create</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_create</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>dvp</parameter></paramdef> - <paramdef>struct label - *<parameter>dlabel</parameter></paramdef> - <paramdef>struct componentname - *<parameter>cnp</parameter></paramdef> - <paramdef>struct vattr - *<parameter>vap</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>dvp</parameter></entry> - <entry>Object; vnode</entry> - </row> - - <row> - <entry><parameter>dlabel</parameter></entry> - <entry>Policy label for - <parameter>dvp</parameter></entry> - </row> - - <row> - <entry><parameter>cnp</parameter></entry> - <entry>Component name for - <parameter>dvp</parameter></entry> - </row> - - <row> - <entry><parameter>vap</parameter></entry> - <entry>vnode attributes for - <parameter>vap</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can create a - vnode with the passed parent directory, passed name - information, and passed attribute information. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> 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 - <symbol>O_CREAT</symbol>, &man.mkfifo.2;, and others.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-delete"> - <title><function>&mac.mpo;_check_vnode_delete</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_delete</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>dvp</parameter></paramdef> - <paramdef>struct label - *<parameter>dlabel</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>void *<parameter>label</parameter></paramdef> - <paramdef>struct componentname - *<parameter>cnp</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>dvp</parameter></entry> - <entry>Parent directory vnode</entry> - </row> - - <row> - <entry><parameter>dlabel</parameter></entry> - <entry>Policy label for - <parameter>dvp</parameter></entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode to delete</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>cnp</parameter></entry> - <entry>Component name for - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can delete a - vnode from the passed parent directory and passed name - information. Return <returnvalue>0</returnvalue> for - success, or an <varname>errno</varname> value for failure. - Suggested failure: <errorcode>EACCES</errorcode> for label - mismatch, or <errorcode>EPERM</errorcode> 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 - <function>mpo_check_rename_to</function> to authorize - deletion of objects as a result of being the target of a - rename.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-deleteacl"> - <title><function>&mac.mpo;_check_vnode_deleteacl</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_deleteacl</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>acl_type_t - <parameter>type</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - <entry>Immutable</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode</entry> - <entry>Locked</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>type</parameter></entry> - <entry>ACL type</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can delete the - ACL of passed type from the passed vnode. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-exec"> - <title><function>&mac.mpo;_check_vnode_exec</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_exec</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode to execute</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can execute the - passed vnode. Determination of execute privilege is made - separately from decisions about any transitioning event. - Return <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mpo-cred-check-vnode-getacl"> - <title><function>&mac.mpo;_check_vnode_getacl</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_getacl</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>acl_type_t - <parameter>type</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>type</parameter></entry> - <entry>ACL type</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can retrieve - the ACL of passed type from the passed vnode. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-getextattr"> - <title><function>&mac.mpo;_check_vnode_getextattr</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_getextattr</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>int - <parameter>attrnamespace</parameter></paramdef> - <paramdef>const char - *<parameter>name</parameter></paramdef> - <paramdef>struct uio - *<parameter>uio</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>attrnamespace</parameter></entry> - <entry>Extended attribute namespace</entry> - </row> - - <row> - <entry><parameter>name</parameter></entry> - <entry>Extended attribute name</entry> - </row> - - <row> - <entry><parameter>uio</parameter></entry> - <entry>I/O structure pointer; see &man.uio.9;</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>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 - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-vnode-link"> - <title><function>&mac.mpo;_check_vnode_link</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_link</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>dvp</parameter></paramdef> - <paramdef>struct label - *<parameter>dlabel</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>struct componentname - *<parameter>cnp</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>dvp</parameter></entry> - <entry>Directory vnode</entry> - </row> - - <row> - <entry><parameter>dlabel</parameter></entry> - <entry>Policy label associated with - <parameter>dvp</parameter></entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Link destination vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label associated with - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>cnp</parameter></entry> - <entry>Component name for the link being - created</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to - create a link to the vnode <parameter>vp</parameter> with - the name specified by <parameter>cnp</parameter>.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-vnode-mmap"> - <title><function>&mac.mpo;_check_vnode_mmap</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_mmap</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>int <parameter>prot</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Vnode to map</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label associated with - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>prot</parameter></entry> - <entry>Mmap protections (see &man.mmap.2;)</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to map - the vnode <parameter>vp</parameter> with the protections - specified in <parameter>prot</parameter>.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-vnode-mmap-downgrade"> - <title><function>&mac.mpo;_check_vnode_mmap_downgrade</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>void - <function>&mac.mpo;_check_vnode_mmap_downgrade</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>int *<parameter>prot</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry morerows="2">See <xref - linkend="mac-mpo-check-vnode-mmap"/>.</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - </row> - - <row> - <entry><parameter>prot</parameter></entry> - <entry>Mmap protections to be downgraded</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Downgrade the mmap protections based on the subject and - object labels.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-vnode-mprotect"> - <title><function>&mac.mpo;_check_vnode_mprotect</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_mprotect</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>int <parameter>prot</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Mapped vnode</entry> - </row> - - <row> - <entry><parameter>prot</parameter></entry> - <entry>Memory protections</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to set - the specified memory protections on memory mapped from the - vnode <parameter>vp</parameter>.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-vnode-poll"> - <title><function>&mac.mpo;_check_vnode_poll</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_poll</function></funcdef> - - <paramdef>struct ucred - *<parameter>active_cred</parameter></paramdef> - <paramdef>struct ucred - *<parameter>file_cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>active_cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>file_cred</parameter></entry> - <entry>Credential associated with the <type>struct - file</type></entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Polled vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label associated with - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to poll - the vnode <parameter>vp</parameter>.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-vnode-rename-from"> - <title><function>&mac.mpo;_check_vnode_rename_from</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_vnode_rename_from</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>dvp</parameter></paramdef> - <paramdef>struct label - *<parameter>dlabel</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>struct componentname - *<parameter>cnp</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>dvp</parameter></entry> - <entry>Directory vnode</entry> - </row> - - <row> - <entry><parameter>dlabel</parameter></entry> - <entry>Policy label associated with - <parameter>dvp</parameter></entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Vnode to be renamed</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label associated with - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>cnp</parameter></entry> - <entry>Component name for - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to - rename the vnode <parameter>vp</parameter> to something - else.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-vnode-rename-to"> - <title><function>&mac.mpo;_check_vnode_rename_to</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_rename_to</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>dvp</parameter></paramdef> - <paramdef>struct label - *<parameter>dlabel</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>int <parameter>samedir</parameter></paramdef> - <paramdef>struct componentname - *<parameter>cnp</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>dvp</parameter></entry> - <entry>Directory vnode</entry> - </row> - - <row> - <entry><parameter>dlabel</parameter></entry> - <entry>Policy label associated with - <parameter>dvp</parameter></entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Overwritten vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label associated with - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>samedir</parameter></entry> - <entry>Boolean; <literal>1</literal> if the source and - destination directories are the same</entry> - </row> - - <row> - <entry><parameter>cnp</parameter></entry> - <entry>Destination component name</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject should be allowed to - rename to the vnode <parameter>vp</parameter>, into the - directory <parameter>dvp</parameter>, or to the name - represented by <parameter>cnp</parameter>. If there is no - existing file to overwrite, <parameter>vp</parameter> and - <parameter>label</parameter> will be NULL.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-socket-listen"> - <title><function>&mac.mpo;_check_socket_listen</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_socket_listen</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct socket - *<parameter>socket</parameter></paramdef> - <paramdef>struct label - *<parameter>socketlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>socket</parameter></entry> - <entry>Object; socket</entry> - </row> - - <row> - <entry><parameter>socketlabel</parameter></entry> - <entry>Policy label for - <parameter>socket</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can listen on - the passed socket. Return <returnvalue>0</returnvalue> for - success, or an <varname>errno</varname> value for failure. - Suggested failure: <errorcode>EACCES</errorcode> for label - mismatch, or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-lookup"> - <title><function>&mac.mpo;_check_vnode_lookup</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_lookup</function></funcdef> - - <paramdef>struct ucred *<parameter/>cred</paramdef> - <paramdef>struct vnode *<parameter/>dvp</paramdef> - <paramdef>struct label *<parameter/>dlabel</paramdef> - <paramdef>struct componentname - *<parameter>cnp</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>dvp</parameter></entry> - <entry>Object; vnode</entry> - </row> - - <row> - <entry><parameter>dlabel</parameter></entry> - <entry>Policy label for - <parameter>dvp</parameter></entry> - </row> - - <row> - <entry><parameter>cnp</parameter></entry> - <entry>Component name being looked up</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can perform a - lookup in the passed directory vnode for the passed name. - Return <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-open"> - <title><function>&mac.mpo;_check_vnode_open</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_open</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>int <parameter>acc_mode</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>acc_mode</parameter></entry> - <entry>&man.open.2; access mode</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can perform an - open operation on the passed vnode with the passed access - mode. Return <returnvalue>0</returnvalue> for success, or - an errno value for failure. Suggested failure: - <errorcode>EACCES</errorcode> for label mismatch, or - <errorcode>EPERM</errorcode> for lack of privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-readdir"> - <title><function>&mac.mpo;_check_vnode_readdir</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_readdir</function></funcdef> - - <paramdef>struct ucred *<parameter/>cred</paramdef> - <paramdef>struct vnode *<parameter/>dvp</paramdef> - <paramdef>struct label *<parameter/>dlabel</paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>dvp</parameter></entry> - <entry>Object; directory vnode</entry> - </row> - - <row> - <entry><parameter>dlabel</parameter></entry> - <entry>Policy label for - <parameter>dvp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can perform a - <function>readdir</function> operation on the passed - directory vnode. Return <returnvalue>0</returnvalue> for - success, or an <varname>errno</varname> value for failure. - Suggested failure: <errorcode>EACCES</errorcode> for label - mismatch, or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-readlink"> - <title><function>&mac.mpo;_check_vnode_readlink</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_readlink</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can perform a - <function>readlink</function> operation on the passed - symlink vnode. Return <returnvalue>0</returnvalue> for - success, or an <varname>errno</varname> value for failure. - Suggested failure: <errorcode>EACCES</errorcode> for label - mismatch, or <errorcode>EPERM</errorcode> for lack of - privilege. This call may be made in a number of situations, - including an explicit <function>readlink</function> call by - the user process, or as a result of an implicit - <function>readlink</function> during a name lookup by the - process.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-revoke"> - <title><function>&mac.mpo;_check_vnode_revoke</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_revoke</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can revoke - access to the passed vnode. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-setacl"> - <title><function>&mac.mpo;_check_vnode_setacl</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_setacl</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>acl_type_t - <parameter>type</parameter></paramdef> - <paramdef>struct acl - *<parameter>acl</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>type</parameter></entry> - <entry>ACL type</entry> - </row> - - <row> - <entry><parameter>acl</parameter></entry> - <entry>ACL</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can set the - passed ACL of passed type on the passed vnode. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-setextattr"> - <title><function>&mac.mpo;_check_vnode_setextattr</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_setextattr</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>int - <parameter>attrnamespace</parameter></paramdef> - <paramdef>const char - *<parameter>name</parameter></paramdef> - <paramdef>struct uio - *<parameter>uio</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>attrnamespace</parameter></entry> - <entry>Extended attribute namespace</entry> - </row> - - <row> - <entry><parameter>name</parameter></entry> - <entry>Extended attribute name</entry> - </row> - - <row> - <entry><parameter>uio</parameter></entry> - <entry>I/O structure pointer; see &man.uio.9;</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>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 <parameter>uio</parameter>, as there is a - potential race condition between this check and the actual - operation. The <parameter>uio</parameter> may also be - <literal>NULL</literal> if a delete operation is being - performed. Return <returnvalue>0</returnvalue> for success, - or an <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-setflags"> - <title><function>&mac.mpo;_check_vnode_setflags</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_setflags</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>u_long <parameter>flags</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>flags</parameter></entry> - <entry>File flags; see &man.chflags.2;</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can set the - passed flags on the passed vnode. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-setmode"> - <title><function>&mac.mpo;_check_vnode_setmode</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_setmode</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>mode_t <parameter>mode</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>mode</parameter></entry> - <entry>File mode; see &man.chmod.2;</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can set the - passed mode on the passed vnode. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-setowner"> - <title><function>&mac.mpo;_check_vnode_setowner</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_setowner</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - <paramdef>uid_t <parameter>uid</parameter></paramdef> - <paramdef>gid_t <parameter>gid</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>uid</parameter></entry> - <entry>User ID</entry> - </row> - - <row> - <entry><parameter>gid</parameter></entry> - <entry>Group ID</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine 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 (<literal>-1</literal>) - to request no update. Return <returnvalue>0</returnvalue> - for success, or an <varname>errno</varname> value for - failure. Suggested failure: <errorcode>EACCES</errorcode> - for label mismatch, or <errorcode>EPERM</errorcode> for lack - of privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-setutimes"> - <title><function>&mac.mpo;_check_vnode_setutimes</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_setutimes</function></funcdef> - - <paramdef>struct ucred *<parameter/>cred</paramdef> - <paramdef>struct vnode *<parameter/>vp</paramdef> - <paramdef>struct label *<parameter/>label</paramdef> - <paramdef>struct timespec <parameter/>atime</paramdef> - <paramdef>struct timespec <parameter/>mtime</paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vp</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - - <row> - <entry><parameter>atime</parameter></entry> - <entry>Access time; see &man.utimes.2;</entry> - </row> - - <row> - <entry><parameter>mtime</parameter></entry> - <entry>Modification time; see &man.utimes.2;</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can set the - passed access timestamps on the passed vnode. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-proc-sched"> - <title><function>&mac.mpo;_check_proc_sched</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_proc_sched</function></funcdef> - - <paramdef>struct ucred - *<parameter>ucred</parameter></paramdef> - <paramdef>struct proc - *<parameter>proc</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>proc</parameter></entry> - <entry>Object; process</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can change the - scheduling parameters of the passed process. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - <errorcode>EPERM</errorcode> for lack of privilege, or - <errorcode>ESRCH</errorcode> to limit visibility.</para> - - <para>See &man.setpriority.2; for more information.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-proc-signal"> - <title><function>&mac.mpo;_check_proc_signal</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_proc_signal</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct proc - *<parameter>proc</parameter></paramdef> - <paramdef>int <parameter>signal</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>proc</parameter></entry> - <entry>Object; process</entry> - </row> - - <row> - <entry><parameter>signal</parameter></entry> - <entry>Signal; see &man.kill.2;</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can deliver the - passed signal to the passed process. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - <errorcode>EPERM</errorcode> for lack of privilege, or - <errorcode>ESRCH</errorcode> to limit visibility.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-vnode-stat"> - <title><function>&mac.mpo;_check_vnode_stat</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_vnode_stat</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>label</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>vp</parameter></entry> - <entry>Object; vnode</entry> - </row> - - <row> - <entry><parameter>label</parameter></entry> - <entry>Policy label for - <parameter>vp</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential can - <function>stat</function> the passed vnode. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - - <para>See &man.stat.2; for more information.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-ifnet-transmit"> - <title><function>&mac.mpo;_check_ifnet_transmit</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_ifnet_transmit</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct ifnet - *<parameter>ifnet</parameter></paramdef> - <paramdef>struct label - *<parameter>ifnetlabel</parameter></paramdef> - <paramdef>struct mbuf - *<parameter>mbuf</parameter></paramdef> - <paramdef>struct label - *<parameter>mbuflabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>ifnet</parameter></entry> - <entry>Network interface</entry> - </row> - - <row> - <entry><parameter>ifnetlabel</parameter></entry> - <entry>Policy label for - <parameter>ifnet</parameter></entry> - </row> - - <row> - <entry><parameter>mbuf</parameter></entry> - <entry>Object; mbuf to be sent</entry> - </row> - - <row> - <entry><parameter>mbuflabel</parameter></entry> - <entry>Policy label for - <parameter>mbuf</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the network interface can transmit the - passed mbuf. Return <returnvalue>0</returnvalue> for - success, or an <varname>errno</varname> value for failure. - Suggested failure: <errorcode>EACCES</errorcode> for label - mismatch, or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-cred-check-socket-deliver"> - <title><function>&mac.mpo;_check_socket_deliver</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_socket_deliver</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct ifnet - *<parameter>ifnet</parameter></paramdef> - <paramdef>struct label - *<parameter>ifnetlabel</parameter></paramdef> - <paramdef>struct mbuf - *<parameter>mbuf</parameter></paramdef> - <paramdef>struct label - *<parameter>mbuflabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - </row> - - <row> - <entry><parameter>ifnet</parameter></entry> - <entry>Network interface</entry> - </row> - - <row> - <entry><parameter>ifnetlabel</parameter></entry> - <entry>Policy label for - <parameter>ifnet</parameter></entry> - </row> - - <row> - <entry><parameter>mbuf</parameter></entry> - <entry>Object; mbuf to be delivered</entry> - </row> - - <row> - <entry><parameter>mbuflabel</parameter></entry> - <entry>Policy label for - <parameter>mbuf</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the socket may receive the datagram - stored in the passed mbuf header. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failures: <errorcode>EACCES</errorcode> for label mismatch, - or <errorcode>EPERM</errorcode> for lack of - privilege.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-socket-visible"> - <title><function>&mac.mpo;_check_socket_visible</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_socket_visible</function></funcdef> - - <paramdef>struct ucred - *<parameter>cred</parameter></paramdef> - <paramdef>struct socket - *<parameter>so</parameter></paramdef> - <paramdef>struct label - *<parameter>socketlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> - <row> - <entry><parameter>cred</parameter></entry> - <entry>Subject credential</entry> - <entry>Immutable</entry> - </row> - - <row> - <entry><parameter>so</parameter></entry> - <entry>Object; socket</entry> - </row> - - <row> - <entry><parameter>socketlabel</parameter></entry> - <entry>Policy label for - <parameter>so</parameter></entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>Determine whether the subject credential cred can "see" - the passed socket (<parameter>socket</parameter>) using - system monitoring functions, such as those employed by - &man.netstat.8; and &man.sockstat.1;. Return - <returnvalue>0</returnvalue> for success, or an - <varname>errno</varname> value for failure. Suggested - failure: <errorcode>EACCES</errorcode> for label mismatches, - <errorcode>EPERM</errorcode> for lack of privilege, or - <errorcode>ESRCH</errorcode> to hide visibility.</para> - </sect3> - - <sect3 xml:id="mac-mpo-check-system-acct"> - <title><function>&mac.mpo;_check_system_acct</function></title> - - <funcsynopsis> - <funcprototype> - <funcdef>int - <function>&mac.mpo;_check_system_acct</function></funcdef> - - <paramdef>struct ucred - *<parameter>ucred</parameter></paramdef> - <paramdef>struct vnode - *<parameter>vp</parameter></paramdef> - <paramdef>struct label - *<parameter>vlabel</parameter></paramdef> - </funcprototype> - </funcsynopsis> - - <informaltable frame="none" pgwide="1"> - <tgroup cols="3"> - &mac.thead; - - <tbody> |